thds.core 1.45.20250805195434__py3-none-any.whl → 1.45.20250805205302__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.
Potentially problematic release.
This version of thds.core might be problematic. Click here for more details.
- thds/core/iterators.py +19 -0
- thds/core/progress.py +36 -2
- {thds_core-1.45.20250805195434.dist-info → thds_core-1.45.20250805205302.dist-info}/METADATA +1 -1
- {thds_core-1.45.20250805195434.dist-info → thds_core-1.45.20250805205302.dist-info}/RECORD +7 -7
- {thds_core-1.45.20250805195434.dist-info → thds_core-1.45.20250805205302.dist-info}/WHEEL +0 -0
- {thds_core-1.45.20250805195434.dist-info → thds_core-1.45.20250805205302.dist-info}/entry_points.txt +0 -0
- {thds_core-1.45.20250805195434.dist-info → thds_core-1.45.20250805205302.dist-info}/top_level.txt +0 -0
thds/core/iterators.py
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import time
|
|
1
2
|
import typing as ty
|
|
3
|
+
from datetime import timedelta
|
|
2
4
|
|
|
3
5
|
T = ty.TypeVar("T")
|
|
4
6
|
|
|
@@ -7,3 +9,20 @@ def null_safe_iter(it: ty.Optional[ty.Iterable[T]]) -> ty.Iterator[T]:
|
|
|
7
9
|
"""Iterate the iterable if it is not None"""
|
|
8
10
|
if it is not None:
|
|
9
11
|
yield from it
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
_Frequency = ty.Union[timedelta, float]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _to_float(t: _Frequency) -> float:
|
|
18
|
+
return t.total_seconds() if isinstance(t, timedelta) else t
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def titrate(it: ty.Iterable[T], *, at_rate: _Frequency, until_nth: int) -> ty.Iterator[T]:
|
|
22
|
+
it_, freq = iter(it), _to_float(at_rate)
|
|
23
|
+
|
|
24
|
+
for i, x in enumerate(it_):
|
|
25
|
+
yield x
|
|
26
|
+
|
|
27
|
+
if i + 1 < until_nth:
|
|
28
|
+
time.sleep(freq)
|
thds/core/progress.py
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import concurrent.futures
|
|
1
2
|
import math
|
|
2
3
|
import typing as ty
|
|
4
|
+
from contextlib import contextmanager
|
|
3
5
|
from datetime import timedelta
|
|
4
6
|
from functools import partial, wraps
|
|
5
7
|
from timeit import default_timer
|
|
@@ -54,12 +56,19 @@ def _name(obj: ty.Any) -> str:
|
|
|
54
56
|
return "item"
|
|
55
57
|
|
|
56
58
|
|
|
59
|
+
_Frequency = ty.Union[timedelta, float]
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _to_float(t: _Frequency) -> float:
|
|
63
|
+
return t if isinstance(t, float) else t.total_seconds()
|
|
64
|
+
|
|
65
|
+
|
|
57
66
|
@_progress_scope.bound
|
|
58
67
|
def report(
|
|
59
68
|
it: ty.Iterable[T],
|
|
60
69
|
*,
|
|
61
70
|
name: str = "",
|
|
62
|
-
roughly_every_s:
|
|
71
|
+
roughly_every_s: _Frequency = timedelta(seconds=20),
|
|
63
72
|
) -> ty.Iterator[T]:
|
|
64
73
|
"""Report round-number progress roughly every so often..."""
|
|
65
74
|
iterator = iter(it)
|
|
@@ -67,7 +76,7 @@ def report(
|
|
|
67
76
|
start = default_timer()
|
|
68
77
|
report_every = 0
|
|
69
78
|
last_report = 0
|
|
70
|
-
frequency = roughly_every_s
|
|
79
|
+
frequency = _to_float(roughly_every_s)
|
|
71
80
|
|
|
72
81
|
try:
|
|
73
82
|
first_item = next(iterator)
|
|
@@ -110,3 +119,28 @@ def _report_gen(f: ty.Callable[P, ty.Iterator[T]], *args: P.args, **kwargs: P.kw
|
|
|
110
119
|
|
|
111
120
|
def report_gen(f: ty.Callable[P, ty.Iterator[T]]) -> ty.Callable[P, ty.Iterator[T]]:
|
|
112
121
|
return wraps(f)(partial(_report_gen, f))
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@contextmanager
|
|
125
|
+
def report_still_alive(
|
|
126
|
+
roughly_every_s: _Frequency = timedelta(seconds=60), *, name: str = ""
|
|
127
|
+
) -> ty.Iterator[None]:
|
|
128
|
+
start, frequency = default_timer(), _to_float(roughly_every_s)
|
|
129
|
+
|
|
130
|
+
sentinel: concurrent.futures.Future[bool] = concurrent.futures.Future()
|
|
131
|
+
|
|
132
|
+
def _report_still_alive():
|
|
133
|
+
while not sentinel.done():
|
|
134
|
+
try:
|
|
135
|
+
return sentinel.result(timeout=frequency)
|
|
136
|
+
except concurrent.futures.TimeoutError:
|
|
137
|
+
logger.info(
|
|
138
|
+
f"Still working{f' on {name} ' if name else ' '}after {default_timer() - start:.3f} seconds..."
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
with concurrent.futures.ThreadPoolExecutor() as executor:
|
|
142
|
+
executor.submit(_report_still_alive)
|
|
143
|
+
|
|
144
|
+
yield
|
|
145
|
+
|
|
146
|
+
sentinel.set_result(True)
|
|
@@ -23,7 +23,7 @@ thds/core/home.py,sha256=tTClL_AarIKeri1aNCpuIC6evD7qr83ESGD173B81hU,470
|
|
|
23
23
|
thds/core/hostname.py,sha256=canFGr-JaaG7nUfsQlyL0JT-2tnZoT1BvXzyaOMK1vA,208
|
|
24
24
|
thds/core/imports.py,sha256=0LVegY8I8_XKZPcqiIp2OVVzEDtyqYA3JETf9OAKNKs,568
|
|
25
25
|
thds/core/inspect.py,sha256=3IY9CSa7zAcAVyBDOYfMtJ2QU5cRc98JaN91XAbaSok,2368
|
|
26
|
-
thds/core/iterators.py,sha256=
|
|
26
|
+
thds/core/iterators.py,sha256=h0JBu2-rYhKMfJTDlZWfyHQWzgtIO8vp_Sp0gENFo7g,645
|
|
27
27
|
thds/core/lazy.py,sha256=e1WvG4LsbEydV0igEr_Vl1cq05zlQNIE8MFYT90yglE,3289
|
|
28
28
|
thds/core/link.py,sha256=4-9d22l_oSkKoSzlYEO-rwxO1hvvj6VETY7LwvGcX6M,5534
|
|
29
29
|
thds/core/logical_root.py,sha256=gWkIYRv9kNQfzbpxJaYiwNXVz1neZ2NvnvProtOn9d8,1399
|
|
@@ -32,7 +32,7 @@ thds/core/meta.py,sha256=3oX7wTO_SmrVKABFPLHHIVyNBXEil1MdGfc5s88_Isk,12134
|
|
|
32
32
|
thds/core/parallel.py,sha256=0A3JQx7aPNaFLh61gZog2E3k4C5qdr5st-xOPS-3j1Y,7612
|
|
33
33
|
thds/core/pickle_visit.py,sha256=QNMWIi5buvk2zsvx1-D-FKL7tkrFUFDs387vxgGebgU,833
|
|
34
34
|
thds/core/prof.py,sha256=5ViolfPsAPwUTHuhAe-bon7IArPGXydpGoB5uZmObDk,8264
|
|
35
|
-
thds/core/progress.py,sha256=
|
|
35
|
+
thds/core/progress.py,sha256=tY8tc_6CMnu_O8DVisnsRoDpFJOw5vqyYzLhQDxsLn8,4361
|
|
36
36
|
thds/core/project_root.py,sha256=K18U3MLthZnzmdrWmKKtHLd6iu7am9b2vNAThqknpfo,891
|
|
37
37
|
thds/core/protocols.py,sha256=4na2EeWUDWfLn5-SxfMmKegDSndJ5z-vwMhDavhCpEM,409
|
|
38
38
|
thds/core/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -73,8 +73,8 @@ thds/core/sqlite/structured.py,sha256=SvZ67KcVcVdmpR52JSd52vMTW2ALUXmlHEeD-VrzWV
|
|
|
73
73
|
thds/core/sqlite/types.py,sha256=oUkfoKRYNGDPZRk29s09rc9ha3SCk2SKr_K6WKebBFs,1308
|
|
74
74
|
thds/core/sqlite/upsert.py,sha256=BmKK6fsGVedt43iY-Lp7dnAu8aJ1e9CYlPVEQR2pMj4,5827
|
|
75
75
|
thds/core/sqlite/write.py,sha256=z0219vDkQDCnsV0WLvsj94keItr7H4j7Y_evbcoBrWU,3458
|
|
76
|
-
thds_core-1.45.
|
|
77
|
-
thds_core-1.45.
|
|
78
|
-
thds_core-1.45.
|
|
79
|
-
thds_core-1.45.
|
|
80
|
-
thds_core-1.45.
|
|
76
|
+
thds_core-1.45.20250805205302.dist-info/METADATA,sha256=Sqmu1rzU2Q7vL6cGeaU9C9DzbH302MIkPGoFU-B3Ttg,2216
|
|
77
|
+
thds_core-1.45.20250805205302.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
78
|
+
thds_core-1.45.20250805205302.dist-info/entry_points.txt,sha256=bOCOVhKZv7azF3FvaWX6uxE6yrjK6FcjqhtxXvLiFY8,161
|
|
79
|
+
thds_core-1.45.20250805205302.dist-info/top_level.txt,sha256=LTZaE5SkWJwv9bwOlMbIhiS-JWQEEIcjVYnJrt-CriY,5
|
|
80
|
+
thds_core-1.45.20250805205302.dist-info/RECORD,,
|
|
File without changes
|
{thds_core-1.45.20250805195434.dist-info → thds_core-1.45.20250805205302.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{thds_core-1.45.20250805195434.dist-info → thds_core-1.45.20250805205302.dist-info}/top_level.txt
RENAMED
|
File without changes
|