valediction 1.0.0__py3-none-any.whl → 1.0.3__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/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)