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 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: timedelta = timedelta(seconds=20),
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.total_seconds()
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)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: thds.core
3
- Version: 1.45.20250805195434
3
+ Version: 1.45.20250805205302
4
4
  Summary: Core utilities.
5
5
  Author-email: Trilliant Health <info@trillianthealth.com>
6
6
  License: MIT
@@ -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=d3iTQDR0gCW1nMRmknQeodR_4THzR9Ajmp8F8KCCFgg,208
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=4YGbxliDl1i-k-88w4s86uy1E69eQ6xJySGPSkpH1QM,3358
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.20250805195434.dist-info/METADATA,sha256=91Sly1y3tAKBag9aPdocjvr4bpvy317V9-O0RAB-eN0,2216
77
- thds_core-1.45.20250805195434.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
78
- thds_core-1.45.20250805195434.dist-info/entry_points.txt,sha256=bOCOVhKZv7azF3FvaWX6uxE6yrjK6FcjqhtxXvLiFY8,161
79
- thds_core-1.45.20250805195434.dist-info/top_level.txt,sha256=LTZaE5SkWJwv9bwOlMbIhiS-JWQEEIcjVYnJrt-CriY,5
80
- thds_core-1.45.20250805195434.dist-info/RECORD,,
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,,