-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtimehelp.py
126 lines (106 loc) · 4.16 KB
/
timehelp.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import timeit
from datetime import timedelta, datetime
from functools import wraps
import ipywidgets as widgets
from IPython.display import display
import time
def tobase(number, base, pad=None):
if number == 0:
digit_list = [0]
else:
digit_list = []
while number > 0:
remainder = number % base
digit_list.insert(0, remainder)
number //= base
if pad is not None:
while len(digit_list) < pad:
digit_list.insert(0, 0)
return digit_list
def fmt_delta(elapsed_time):
ipart = int(elapsed_time)
fpart = elapsed_time - ipart
hr, mn, sec = tobase(ipart, 60, pad=3)
ms = int(fpart * 1000)
elapsed_parts = []
if hr > 0:
elapsed_parts.append(f"{hr}hr")
if mn > 0:
elapsed_parts.append(f"{mn}min")
if sec > 0:
elapsed_parts.append(f"{sec}s")
if len(elapsed_parts) < 2 and ms > 0:
elapsed_parts.append(f"{ms}ms")
if len(elapsed_parts) == 0:
return "~0s"
return " ".join(elapsed_parts)
# only one at a time
timer_started = None
timer_label = None
def time_start(label=".timehelp"):
global timer_started, timer_label
timer_label = label
display_now = datetime.today().strftime("%Y-%m-%d@%H:%M:%S")
print(f"[{display_now}|{timer_label}] Starting timer.")
timer_started = timeit.default_timer()
def time_end():
now = timeit.default_timer()
elapsed = now - timer_started
display_now = datetime.today().strftime("%Y-%m-%d@%H:%M:%S")
print(f"[{display_now}|{timer_label}] Time elapsed:", fmt_delta(elapsed))
def with_progress(steps=None, label="Progress"):
assert steps is not None, "@with_progress: Missing required parameter steps"
total_steps = steps
def decorator(func):
@wraps(func)
def wrapper(*args, skip=None, **kwargs):
# Create widgets
progress = widgets.IntProgress(
value=0, min=0, max=total_steps,
**(
dict(description=f"{label}:") if label
else {}
)
)
estimated_time = widgets.Label(value="Estimated time remaining: calculating...")
hbox = widgets.VBox([progress, estimated_time])
display(hbox)
start_time = time.time()
start = 0
if skip is not None:
assert skip >= 0, f"Cannot skip {skip} lines"
start = skip
my_total_steps = total_steps - start
result = None
progress.value = start
for step in range(start, start + my_total_steps):
# Call the wrapped function
result = func(*args, **kwargs, step=step)
# Update progress bar
progress.value = step + 1
# Calculate and update estimated time remaining
elapsed_time = time.time() - start_time
remaining_steps = total_steps - (step + 1)
steps_so_far = step + 1 - start
if steps_so_far > 1:
time_per_step = elapsed_time / steps_so_far
estimated_remaining_time = time_per_step * remaining_steps
estimated_time.value = f"[{step + 1}/{total_steps}] ETA: {fmt_delta(estimated_remaining_time)}, {fmt_delta(elapsed_time)} elapsed..."
else:
estimated_time.value = f"[{step + 1}/{total_steps}] ETA: calculating, {fmt_delta(elapsed_time)} elapsed..."
progress.value = total_steps
estimated_time.value = f"Done, {fmt_delta(time.time() - start_time)} elapsed."
print(estimated_time.value)
return result
return wrapper
return decorator
def display_header(text, depth=1):
style = "font-weight: bold;"
if depth == 1:
style += " border-bottom: 1px solid;"
elif depth == 2:
style += " border-bottom: 1px dotted;"
header = widgets.HTML(value=f"<h{depth} style='{style}'>{text}</h{depth}>")
display(header)
markdown_header_prefix = "#" * depth
print(f"{markdown_header_prefix} {text}")