valediction 1.0.0__py3-none-any.whl → 1.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- valediction/__init__.py +8 -8
- valediction/convenience.py +45 -50
- valediction/data_types/data_type_helpers.py +75 -75
- valediction/data_types/data_types.py +58 -58
- valediction/data_types/type_inference.py +541 -541
- valediction/datasets/datasets.py +870 -870
- valediction/datasets/datasets_helpers.py +46 -46
- valediction/demo/DEMOGRAPHICS.csv +101 -101
- valediction/demo/DIAGNOSES.csv +650 -650
- valediction/demo/LAB_TESTS.csv +1001 -1001
- valediction/demo/VITALS.csv +1001 -1001
- valediction/demo/__init__.py +6 -6
- valediction/demo/demo_dictionary.py +129 -129
- valediction/dictionary/exporting.py +501 -501
- valediction/dictionary/exporting_helpers.py +371 -371
- valediction/dictionary/generation.py +357 -357
- valediction/dictionary/helpers.py +174 -174
- valediction/dictionary/importing.py +494 -494
- valediction/dictionary/integrity.py +37 -37
- valediction/dictionary/model.py +582 -582
- valediction/exceptions.py +22 -22
- valediction/integrity.py +97 -97
- valediction/io/csv_readers.py +307 -307
- valediction/progress.py +206 -206
- valediction/support.py +72 -72
- valediction/validation/helpers.py +315 -315
- valediction/validation/issues.py +280 -280
- valediction/validation/validation.py +598 -598
- {valediction-1.0.0.dist-info → valediction-1.1.0.dist-info}/METADATA +1 -1
- valediction-1.1.0.dist-info/RECORD +38 -0
- {valediction-1.0.0.dist-info → valediction-1.1.0.dist-info}/WHEEL +1 -1
- valediction-1.0.0.dist-info/RECORD +0 -38
valediction/progress.py
CHANGED
|
@@ -1,206 +1,206 @@
|
|
|
1
|
-
# progress.py
|
|
2
|
-
from __future__ import annotations
|
|
3
|
-
|
|
4
|
-
from datetime import datetime, timedelta
|
|
5
|
-
|
|
6
|
-
from tqdm import tqdm
|
|
7
|
-
|
|
8
|
-
from valediction.support import BOLD_GREEN, BOLD_RED, RESET, calculate_runtime
|
|
9
|
-
|
|
10
|
-
FORMAT_KNOWN_TOTAL = (
|
|
11
|
-
"{desc} {percentage:3.0f}%|{bar}| {n_fmt}/{total_fmt} "
|
|
12
|
-
"[{elapsed}<{remaining}, {rate_fmt}{postfix}]"
|
|
13
|
-
)
|
|
14
|
-
|
|
15
|
-
FORMAT_UNKNOWN_TOTAL = (
|
|
16
|
-
"{desc} {percentage:3.0f}%|{bar}| ?/? [{elapsed}<{remaining}, {rate_fmt}{postfix}]"
|
|
17
|
-
)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class Progress:
|
|
21
|
-
def __init__(
|
|
22
|
-
self,
|
|
23
|
-
desc: str = "",
|
|
24
|
-
est_total: int | None = 1,
|
|
25
|
-
smoothing_steps: int = 0,
|
|
26
|
-
unit: str = "step",
|
|
27
|
-
starting_step: str | None = None,
|
|
28
|
-
enabled: bool = True,
|
|
29
|
-
) -> None:
|
|
30
|
-
"""Progress bar (tqdm) with manual control.
|
|
31
|
-
|
|
32
|
-
Args:
|
|
33
|
-
desc (str): label shown to the left of the bar
|
|
34
|
-
starting_step (str, optional): initial step and starting postfix, e.g. "Importing Data".
|
|
35
|
-
Defaults to "".
|
|
36
|
-
est_total (int, optional): initial total number of steps (can grow/shrink later).
|
|
37
|
-
Defaults to 1.
|
|
38
|
-
smoothing_steps (int, optional): window length of previous steps to approximate ETA.
|
|
39
|
-
Use 0 for global average. Defaults to 0.
|
|
40
|
-
unit (str, optional): display unit (default: "step"). Defaults to "step".
|
|
41
|
-
bar_format (str, optional): custom bar format. Defaults to None (using Progress
|
|
42
|
-
default).
|
|
43
|
-
enabled (bool, optional): Enables switching off, avoiding duplication of upstream
|
|
44
|
-
checks. Defaults to True.
|
|
45
|
-
"""
|
|
46
|
-
self.enabled: bool = enabled
|
|
47
|
-
self.desc: str = desc
|
|
48
|
-
self.est_total: int = est_total
|
|
49
|
-
self.smoothing_steps: int = max(0, int(smoothing_steps or 0))
|
|
50
|
-
self.unit: str = unit
|
|
51
|
-
self.postfix: str = ""
|
|
52
|
-
|
|
53
|
-
# Bar
|
|
54
|
-
self.bar: tqdm = None
|
|
55
|
-
self.total_steps: int = self.est_total
|
|
56
|
-
self.completed_steps: int = 0
|
|
57
|
-
|
|
58
|
-
# Runtimes
|
|
59
|
-
self.full_start: datetime = None
|
|
60
|
-
self.step_start: datetime = None
|
|
61
|
-
self.current_step = starting_step or ""
|
|
62
|
-
self.runtimes: dict[str, timedelta] = {}
|
|
63
|
-
|
|
64
|
-
self.__init_progress_bar()
|
|
65
|
-
|
|
66
|
-
# Context
|
|
67
|
-
def __enter__(self) -> Progress:
|
|
68
|
-
return self
|
|
69
|
-
|
|
70
|
-
def __exit__(self, exc_type, exc, tb) -> None:
|
|
71
|
-
self.close()
|
|
72
|
-
|
|
73
|
-
# Initialisation
|
|
74
|
-
def __init_progress_bar(self) -> None:
|
|
75
|
-
now = datetime.now()
|
|
76
|
-
self.full_start = now
|
|
77
|
-
self.step_start = now
|
|
78
|
-
|
|
79
|
-
if not self.enabled:
|
|
80
|
-
return
|
|
81
|
-
|
|
82
|
-
smoothing = (
|
|
83
|
-
0.0 if self.smoothing_steps == 0 else 2.0 / (self.smoothing_steps + 1)
|
|
84
|
-
)
|
|
85
|
-
|
|
86
|
-
self.bar = tqdm(
|
|
87
|
-
total=self.total_steps,
|
|
88
|
-
unit=self.unit,
|
|
89
|
-
desc=self.desc,
|
|
90
|
-
smoothing=smoothing,
|
|
91
|
-
)
|
|
92
|
-
self.__set_bar_format()
|
|
93
|
-
if self.current_step:
|
|
94
|
-
self.bar.set_postfix_str(self.current_step)
|
|
95
|
-
|
|
96
|
-
def __set_bar_format(self) -> None:
|
|
97
|
-
if self.est_total:
|
|
98
|
-
self.bar.bar_format = FORMAT_KNOWN_TOTAL
|
|
99
|
-
else:
|
|
100
|
-
self.bar.bar_format = FORMAT_UNKNOWN_TOTAL
|
|
101
|
-
|
|
102
|
-
# Management
|
|
103
|
-
def retarget_total(self, new_total: int) -> None:
|
|
104
|
-
if not self.enabled:
|
|
105
|
-
return
|
|
106
|
-
|
|
107
|
-
new_total = max(1, int(new_total))
|
|
108
|
-
self.total_steps = new_total
|
|
109
|
-
self.est_total = new_total
|
|
110
|
-
self.__set_bar_format()
|
|
111
|
-
|
|
112
|
-
if self.bar is None:
|
|
113
|
-
return
|
|
114
|
-
|
|
115
|
-
if int(self.bar.total or 0) == new_total:
|
|
116
|
-
return
|
|
117
|
-
|
|
118
|
-
self.bar.total = new_total
|
|
119
|
-
self._refresh()
|
|
120
|
-
|
|
121
|
-
def begin_step(self, step: str, alt_postfix: str = None) -> None:
|
|
122
|
-
self.step_start = datetime.now()
|
|
123
|
-
self.current_step = step
|
|
124
|
-
postfix = alt_postfix or self.current_step
|
|
125
|
-
|
|
126
|
-
if self.enabled:
|
|
127
|
-
self._set_postfix(postfix)
|
|
128
|
-
self._refresh()
|
|
129
|
-
|
|
130
|
-
def complete_step(
|
|
131
|
-
self, n: int = 1, from_time: datetime = None, save_as: str = None
|
|
132
|
-
) -> None:
|
|
133
|
-
step = save_as or self.current_step
|
|
134
|
-
runtime = calculate_runtime(start=from_time or self.step_start)
|
|
135
|
-
if self.runtimes.get(step) is None:
|
|
136
|
-
self.runtimes[step] = runtime.timedelta
|
|
137
|
-
else:
|
|
138
|
-
self.runtimes[step] += runtime.timedelta
|
|
139
|
-
|
|
140
|
-
if self.enabled:
|
|
141
|
-
self._tick(n=n)
|
|
142
|
-
|
|
143
|
-
def finish(
|
|
144
|
-
self,
|
|
145
|
-
postfix: str | None = "Completed",
|
|
146
|
-
save_as: str = "Total",
|
|
147
|
-
good: bool = None,
|
|
148
|
-
) -> None:
|
|
149
|
-
self.complete_step(n=0, from_time=self.full_start, save_as=save_as)
|
|
150
|
-
|
|
151
|
-
if not self.enabled:
|
|
152
|
-
return
|
|
153
|
-
|
|
154
|
-
postfix = (
|
|
155
|
-
f"{BOLD_GREEN if good else BOLD_RED if good is False else ''}"
|
|
156
|
-
+ postfix
|
|
157
|
-
+ f"{'' if good is None else RESET}"
|
|
158
|
-
)
|
|
159
|
-
self._set_postfix(postfix)
|
|
160
|
-
completed_steps = int(getattr(self.bar, "n", 0))
|
|
161
|
-
if completed_steps <= 0:
|
|
162
|
-
self.bar.total = 1
|
|
163
|
-
self.bar.update(1)
|
|
164
|
-
self.completed_steps = 1
|
|
165
|
-
|
|
166
|
-
else:
|
|
167
|
-
self.bar.total = completed_steps
|
|
168
|
-
if self.bar.n < completed_steps:
|
|
169
|
-
self.bar.update(completed_steps - self.bar.n)
|
|
170
|
-
self.completed_steps = completed_steps
|
|
171
|
-
self._refresh()
|
|
172
|
-
|
|
173
|
-
def close(self) -> None:
|
|
174
|
-
if not self.enabled:
|
|
175
|
-
return
|
|
176
|
-
|
|
177
|
-
if self.bar:
|
|
178
|
-
try:
|
|
179
|
-
self.bar.close()
|
|
180
|
-
finally:
|
|
181
|
-
self.bar = None
|
|
182
|
-
|
|
183
|
-
# Helpers
|
|
184
|
-
def _refresh(self) -> None:
|
|
185
|
-
if not self.enabled:
|
|
186
|
-
return
|
|
187
|
-
|
|
188
|
-
self.bar.refresh()
|
|
189
|
-
|
|
190
|
-
def _tick(self, n: int = 1):
|
|
191
|
-
self.completed_steps += n
|
|
192
|
-
if not self.enabled:
|
|
193
|
-
return
|
|
194
|
-
|
|
195
|
-
if n:
|
|
196
|
-
self.bar.update(n)
|
|
197
|
-
self._refresh()
|
|
198
|
-
|
|
199
|
-
def _set_postfix(self, postfix: str) -> None:
|
|
200
|
-
if not self.enabled:
|
|
201
|
-
return
|
|
202
|
-
|
|
203
|
-
postfix = postfix or ""
|
|
204
|
-
self.postfix = postfix
|
|
205
|
-
self.bar.set_postfix_str(postfix)
|
|
206
|
-
self._refresh()
|
|
1
|
+
# progress.py
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from datetime import datetime, timedelta
|
|
5
|
+
|
|
6
|
+
from tqdm import tqdm
|
|
7
|
+
|
|
8
|
+
from valediction.support import BOLD_GREEN, BOLD_RED, RESET, calculate_runtime
|
|
9
|
+
|
|
10
|
+
FORMAT_KNOWN_TOTAL = (
|
|
11
|
+
"{desc} {percentage:3.0f}%|{bar}| {n_fmt}/{total_fmt} "
|
|
12
|
+
"[{elapsed}<{remaining}, {rate_fmt}{postfix}]"
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
FORMAT_UNKNOWN_TOTAL = (
|
|
16
|
+
"{desc} {percentage:3.0f}%|{bar}| ?/? [{elapsed}<{remaining}, {rate_fmt}{postfix}]"
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class Progress:
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
desc: str = "",
|
|
24
|
+
est_total: int | None = 1,
|
|
25
|
+
smoothing_steps: int = 0,
|
|
26
|
+
unit: str = "step",
|
|
27
|
+
starting_step: str | None = None,
|
|
28
|
+
enabled: bool = True,
|
|
29
|
+
) -> None:
|
|
30
|
+
"""Progress bar (tqdm) with manual control.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
desc (str): label shown to the left of the bar
|
|
34
|
+
starting_step (str, optional): initial step and starting postfix, e.g. "Importing Data".
|
|
35
|
+
Defaults to "".
|
|
36
|
+
est_total (int, optional): initial total number of steps (can grow/shrink later).
|
|
37
|
+
Defaults to 1.
|
|
38
|
+
smoothing_steps (int, optional): window length of previous steps to approximate ETA.
|
|
39
|
+
Use 0 for global average. Defaults to 0.
|
|
40
|
+
unit (str, optional): display unit (default: "step"). Defaults to "step".
|
|
41
|
+
bar_format (str, optional): custom bar format. Defaults to None (using Progress
|
|
42
|
+
default).
|
|
43
|
+
enabled (bool, optional): Enables switching off, avoiding duplication of upstream
|
|
44
|
+
checks. Defaults to True.
|
|
45
|
+
"""
|
|
46
|
+
self.enabled: bool = enabled
|
|
47
|
+
self.desc: str = desc
|
|
48
|
+
self.est_total: int = est_total
|
|
49
|
+
self.smoothing_steps: int = max(0, int(smoothing_steps or 0))
|
|
50
|
+
self.unit: str = unit
|
|
51
|
+
self.postfix: str = ""
|
|
52
|
+
|
|
53
|
+
# Bar
|
|
54
|
+
self.bar: tqdm = None
|
|
55
|
+
self.total_steps: int = self.est_total
|
|
56
|
+
self.completed_steps: int = 0
|
|
57
|
+
|
|
58
|
+
# Runtimes
|
|
59
|
+
self.full_start: datetime = None
|
|
60
|
+
self.step_start: datetime = None
|
|
61
|
+
self.current_step = starting_step or ""
|
|
62
|
+
self.runtimes: dict[str, timedelta] = {}
|
|
63
|
+
|
|
64
|
+
self.__init_progress_bar()
|
|
65
|
+
|
|
66
|
+
# Context
|
|
67
|
+
def __enter__(self) -> Progress:
|
|
68
|
+
return self
|
|
69
|
+
|
|
70
|
+
def __exit__(self, exc_type, exc, tb) -> None:
|
|
71
|
+
self.close()
|
|
72
|
+
|
|
73
|
+
# Initialisation
|
|
74
|
+
def __init_progress_bar(self) -> None:
|
|
75
|
+
now = datetime.now()
|
|
76
|
+
self.full_start = now
|
|
77
|
+
self.step_start = now
|
|
78
|
+
|
|
79
|
+
if not self.enabled:
|
|
80
|
+
return
|
|
81
|
+
|
|
82
|
+
smoothing = (
|
|
83
|
+
0.0 if self.smoothing_steps == 0 else 2.0 / (self.smoothing_steps + 1)
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
self.bar = tqdm(
|
|
87
|
+
total=self.total_steps,
|
|
88
|
+
unit=self.unit,
|
|
89
|
+
desc=self.desc,
|
|
90
|
+
smoothing=smoothing,
|
|
91
|
+
)
|
|
92
|
+
self.__set_bar_format()
|
|
93
|
+
if self.current_step:
|
|
94
|
+
self.bar.set_postfix_str(self.current_step)
|
|
95
|
+
|
|
96
|
+
def __set_bar_format(self) -> None:
|
|
97
|
+
if self.est_total:
|
|
98
|
+
self.bar.bar_format = FORMAT_KNOWN_TOTAL
|
|
99
|
+
else:
|
|
100
|
+
self.bar.bar_format = FORMAT_UNKNOWN_TOTAL
|
|
101
|
+
|
|
102
|
+
# Management
|
|
103
|
+
def retarget_total(self, new_total: int) -> None:
|
|
104
|
+
if not self.enabled:
|
|
105
|
+
return
|
|
106
|
+
|
|
107
|
+
new_total = max(1, int(new_total))
|
|
108
|
+
self.total_steps = new_total
|
|
109
|
+
self.est_total = new_total
|
|
110
|
+
self.__set_bar_format()
|
|
111
|
+
|
|
112
|
+
if self.bar is None:
|
|
113
|
+
return
|
|
114
|
+
|
|
115
|
+
if int(self.bar.total or 0) == new_total:
|
|
116
|
+
return
|
|
117
|
+
|
|
118
|
+
self.bar.total = new_total
|
|
119
|
+
self._refresh()
|
|
120
|
+
|
|
121
|
+
def begin_step(self, step: str, alt_postfix: str = None) -> None:
|
|
122
|
+
self.step_start = datetime.now()
|
|
123
|
+
self.current_step = step
|
|
124
|
+
postfix = alt_postfix or self.current_step
|
|
125
|
+
|
|
126
|
+
if self.enabled:
|
|
127
|
+
self._set_postfix(postfix)
|
|
128
|
+
self._refresh()
|
|
129
|
+
|
|
130
|
+
def complete_step(
|
|
131
|
+
self, n: int = 1, from_time: datetime = None, save_as: str = None
|
|
132
|
+
) -> None:
|
|
133
|
+
step = save_as or self.current_step
|
|
134
|
+
runtime = calculate_runtime(start=from_time or self.step_start)
|
|
135
|
+
if self.runtimes.get(step) is None:
|
|
136
|
+
self.runtimes[step] = runtime.timedelta
|
|
137
|
+
else:
|
|
138
|
+
self.runtimes[step] += runtime.timedelta
|
|
139
|
+
|
|
140
|
+
if self.enabled:
|
|
141
|
+
self._tick(n=n)
|
|
142
|
+
|
|
143
|
+
def finish(
|
|
144
|
+
self,
|
|
145
|
+
postfix: str | None = "Completed",
|
|
146
|
+
save_as: str = "Total",
|
|
147
|
+
good: bool = None,
|
|
148
|
+
) -> None:
|
|
149
|
+
self.complete_step(n=0, from_time=self.full_start, save_as=save_as)
|
|
150
|
+
|
|
151
|
+
if not self.enabled:
|
|
152
|
+
return
|
|
153
|
+
|
|
154
|
+
postfix = (
|
|
155
|
+
f"{BOLD_GREEN if good else BOLD_RED if good is False else ''}"
|
|
156
|
+
+ postfix
|
|
157
|
+
+ f"{'' if good is None else RESET}"
|
|
158
|
+
)
|
|
159
|
+
self._set_postfix(postfix)
|
|
160
|
+
completed_steps = int(getattr(self.bar, "n", 0))
|
|
161
|
+
if completed_steps <= 0:
|
|
162
|
+
self.bar.total = 1
|
|
163
|
+
self.bar.update(1)
|
|
164
|
+
self.completed_steps = 1
|
|
165
|
+
|
|
166
|
+
else:
|
|
167
|
+
self.bar.total = completed_steps
|
|
168
|
+
if self.bar.n < completed_steps:
|
|
169
|
+
self.bar.update(completed_steps - self.bar.n)
|
|
170
|
+
self.completed_steps = completed_steps
|
|
171
|
+
self._refresh()
|
|
172
|
+
|
|
173
|
+
def close(self) -> None:
|
|
174
|
+
if not self.enabled:
|
|
175
|
+
return
|
|
176
|
+
|
|
177
|
+
if self.bar:
|
|
178
|
+
try:
|
|
179
|
+
self.bar.close()
|
|
180
|
+
finally:
|
|
181
|
+
self.bar = None
|
|
182
|
+
|
|
183
|
+
# Helpers
|
|
184
|
+
def _refresh(self) -> None:
|
|
185
|
+
if not self.enabled:
|
|
186
|
+
return
|
|
187
|
+
|
|
188
|
+
self.bar.refresh()
|
|
189
|
+
|
|
190
|
+
def _tick(self, n: int = 1):
|
|
191
|
+
self.completed_steps += n
|
|
192
|
+
if not self.enabled:
|
|
193
|
+
return
|
|
194
|
+
|
|
195
|
+
if n:
|
|
196
|
+
self.bar.update(n)
|
|
197
|
+
self._refresh()
|
|
198
|
+
|
|
199
|
+
def _set_postfix(self, postfix: str) -> None:
|
|
200
|
+
if not self.enabled:
|
|
201
|
+
return
|
|
202
|
+
|
|
203
|
+
postfix = postfix or ""
|
|
204
|
+
self.postfix = postfix
|
|
205
|
+
self.bar.set_postfix_str(postfix)
|
|
206
|
+
self._refresh()
|
valediction/support.py
CHANGED
|
@@ -1,72 +1,72 @@
|
|
|
1
|
-
from dataclasses import dataclass
|
|
2
|
-
from datetime import datetime, timedelta
|
|
3
|
-
from math import trunc
|
|
4
|
-
|
|
5
|
-
BOLD_RED = "\033[1;31m"
|
|
6
|
-
BOLD_GREEN = "\033[1;92m"
|
|
7
|
-
RED = "\033[31m"
|
|
8
|
-
GREEN = "\033[92m"
|
|
9
|
-
RESET = "\033[0m"
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
@dataclass
|
|
13
|
-
class Runtime:
|
|
14
|
-
message: str
|
|
15
|
-
timedelta: timedelta
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def print_bold_red(message: str, end: str | None = "\n") -> None:
|
|
19
|
-
print(f"{BOLD_RED}{message}{RESET}", end=end)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def print_bold_green(message: str, end: str | None = "\n") -> None:
|
|
23
|
-
print(f"{BOLD_GREEN}{message}{RESET}", end=end)
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
def print_green(message: str, end: str | None = "\n") -> None:
|
|
27
|
-
print(f"{GREEN}{message}{RESET}", end=end)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
def print_red(message: str, end: str | None = "\n") -> None:
|
|
31
|
-
print(f"{RED}{message}{RESET}", end=end)
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def list_as_bullets(elements: list, bullet: str = "\n - ") -> str:
|
|
35
|
-
return bullet + bullet.join(elements)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def _normalise_name(name: str) -> str:
|
|
39
|
-
return name.strip().upper()
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
def _get_runtime_string(runtime: timedelta) -> str:
|
|
43
|
-
total_seconds = runtime.total_seconds()
|
|
44
|
-
hours = trunc(total_seconds / 3600)
|
|
45
|
-
minutes = trunc((total_seconds - (hours * 3600)) / 60)
|
|
46
|
-
seconds = trunc((total_seconds - (hours * 3600) - (minutes * 60)) * 10) / 10
|
|
47
|
-
runtime_string = (
|
|
48
|
-
(f"{hours}h " if hours else "")
|
|
49
|
-
+ (f"{minutes}m " if minutes else "")
|
|
50
|
-
+ (f"{seconds}s" if not hours and not minutes else f"{trunc(seconds)}s")
|
|
51
|
-
)
|
|
52
|
-
return runtime_string
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
def calculate_runtime(start: datetime, stop: datetime | None = None) -> Runtime:
|
|
56
|
-
"""
|
|
57
|
-
Summary:
|
|
58
|
-
- Takes two datetimes, and calculates the difference.
|
|
59
|
-
- Returns a message and raw timedelta as a named tuple, callable with .message or .delta
|
|
60
|
-
|
|
61
|
-
Args:
|
|
62
|
-
- start (datetime): Start time for calculation.
|
|
63
|
-
- stop (datetime): Stop time for calculation. Defaults to now if not entered.
|
|
64
|
-
|
|
65
|
-
Returns:
|
|
66
|
-
tuple[str, timedelta]: Returns tuple, callable with .message (string) or .delta (raw timedelta)
|
|
67
|
-
"""
|
|
68
|
-
stop = stop if stop else datetime.now()
|
|
69
|
-
runtime = stop - start
|
|
70
|
-
runtime_string = _get_runtime_string(runtime)
|
|
71
|
-
|
|
72
|
-
return Runtime(message=runtime_string, timedelta=runtime)
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from datetime import datetime, timedelta
|
|
3
|
+
from math import trunc
|
|
4
|
+
|
|
5
|
+
BOLD_RED = "\033[1;31m"
|
|
6
|
+
BOLD_GREEN = "\033[1;92m"
|
|
7
|
+
RED = "\033[31m"
|
|
8
|
+
GREEN = "\033[92m"
|
|
9
|
+
RESET = "\033[0m"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class Runtime:
|
|
14
|
+
message: str
|
|
15
|
+
timedelta: timedelta
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def print_bold_red(message: str, end: str | None = "\n") -> None:
|
|
19
|
+
print(f"{BOLD_RED}{message}{RESET}", end=end)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def print_bold_green(message: str, end: str | None = "\n") -> None:
|
|
23
|
+
print(f"{BOLD_GREEN}{message}{RESET}", end=end)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def print_green(message: str, end: str | None = "\n") -> None:
|
|
27
|
+
print(f"{GREEN}{message}{RESET}", end=end)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def print_red(message: str, end: str | None = "\n") -> None:
|
|
31
|
+
print(f"{RED}{message}{RESET}", end=end)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def list_as_bullets(elements: list, bullet: str = "\n - ") -> str:
|
|
35
|
+
return bullet + bullet.join(elements)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _normalise_name(name: str) -> str:
|
|
39
|
+
return name.strip().upper()
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _get_runtime_string(runtime: timedelta) -> str:
|
|
43
|
+
total_seconds = runtime.total_seconds()
|
|
44
|
+
hours = trunc(total_seconds / 3600)
|
|
45
|
+
minutes = trunc((total_seconds - (hours * 3600)) / 60)
|
|
46
|
+
seconds = trunc((total_seconds - (hours * 3600) - (minutes * 60)) * 10) / 10
|
|
47
|
+
runtime_string = (
|
|
48
|
+
(f"{hours}h " if hours else "")
|
|
49
|
+
+ (f"{minutes}m " if minutes else "")
|
|
50
|
+
+ (f"{seconds}s" if not hours and not minutes else f"{trunc(seconds)}s")
|
|
51
|
+
)
|
|
52
|
+
return runtime_string
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def calculate_runtime(start: datetime, stop: datetime | None = None) -> Runtime:
|
|
56
|
+
"""
|
|
57
|
+
Summary:
|
|
58
|
+
- Takes two datetimes, and calculates the difference.
|
|
59
|
+
- Returns a message and raw timedelta as a named tuple, callable with .message or .delta
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
- start (datetime): Start time for calculation.
|
|
63
|
+
- stop (datetime): Stop time for calculation. Defaults to now if not entered.
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
tuple[str, timedelta]: Returns tuple, callable with .message (string) or .delta (raw timedelta)
|
|
67
|
+
"""
|
|
68
|
+
stop = stop if stop else datetime.now()
|
|
69
|
+
runtime = stop - start
|
|
70
|
+
runtime_string = _get_runtime_string(runtime)
|
|
71
|
+
|
|
72
|
+
return Runtime(message=runtime_string, timedelta=runtime)
|