ominfra 0.0.0.dev102__py3-none-any.whl → 0.0.0.dev104__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.
@@ -1410,7 +1410,7 @@ class DataclassObjMarshaler(ObjMarshaler):
1410
1410
  return {k: m.marshal(getattr(o, k)) for k, m in self.fs.items()}
1411
1411
 
1412
1412
  def unmarshal(self, o: ta.Any) -> ta.Any:
1413
- return self.ty(**{k: self.fs[k].unmarshal(v) for k, v in o.items() if self.nonstrict or k in self.fs})
1413
+ return self.ty(**{k: self.fs[k].unmarshal(v) for k, v in o.items() if not self.nonstrict or k in self.fs})
1414
1414
 
1415
1415
 
1416
1416
  @dc.dataclass(frozen=True)
@@ -1470,7 +1470,10 @@ class UuidObjMarshaler(ObjMarshaler):
1470
1470
  return uuid.UUID(o)
1471
1471
 
1472
1472
 
1473
- _OBJ_MARSHALERS: ta.Dict[ta.Any, ObjMarshaler] = {
1473
+ ##
1474
+
1475
+
1476
+ _DEFAULT_OBJ_MARSHALERS: ta.Dict[ta.Any, ObjMarshaler] = {
1474
1477
  **{t: NopObjMarshaler() for t in (type(None),)},
1475
1478
  **{t: CastObjMarshaler(t) for t in (int, float, str, bool)},
1476
1479
  **{t: Base64ObjMarshaler(t) for t in (bytes, bytearray)},
@@ -1499,20 +1502,19 @@ _OBJ_MARSHALER_GENERIC_ITERABLE_TYPES: ta.Dict[ta.Any, type] = {
1499
1502
  }
1500
1503
 
1501
1504
 
1502
- def register_opj_marshaler(ty: ta.Any, m: ObjMarshaler) -> None:
1503
- if ty in _OBJ_MARSHALERS:
1504
- raise KeyError(ty)
1505
- _OBJ_MARSHALERS[ty] = m
1506
-
1507
-
1508
- def _make_obj_marshaler(ty: ta.Any) -> ObjMarshaler:
1505
+ def _make_obj_marshaler(
1506
+ ty: ta.Any,
1507
+ rec: ta.Callable[[ta.Any], ObjMarshaler],
1508
+ *,
1509
+ nonstrict_dataclasses: bool = False,
1510
+ ) -> ObjMarshaler:
1509
1511
  if isinstance(ty, type):
1510
1512
  if abc.ABC in ty.__bases__:
1511
1513
  impls = [ # type: ignore
1512
1514
  PolymorphicObjMarshaler.Impl(
1513
1515
  ity,
1514
1516
  ity.__qualname__,
1515
- get_obj_marshaler(ity),
1517
+ rec(ity),
1516
1518
  )
1517
1519
  for ity in deep_subclasses(ty)
1518
1520
  if abc.ABC not in ity.__bases__
@@ -1528,7 +1530,8 @@ def _make_obj_marshaler(ty: ta.Any) -> ObjMarshaler:
1528
1530
  if dc.is_dataclass(ty):
1529
1531
  return DataclassObjMarshaler(
1530
1532
  ty,
1531
- {f.name: get_obj_marshaler(f.type) for f in dc.fields(ty)},
1533
+ {f.name: rec(f.type) for f in dc.fields(ty)},
1534
+ nonstrict=nonstrict_dataclasses,
1532
1535
  )
1533
1536
 
1534
1537
  if is_generic_alias(ty):
@@ -1538,7 +1541,7 @@ def _make_obj_marshaler(ty: ta.Any) -> ObjMarshaler:
1538
1541
  pass
1539
1542
  else:
1540
1543
  k, v = ta.get_args(ty)
1541
- return MappingObjMarshaler(mt, get_obj_marshaler(k), get_obj_marshaler(v))
1544
+ return MappingObjMarshaler(mt, rec(k), rec(v))
1542
1545
 
1543
1546
  try:
1544
1547
  st = _OBJ_MARSHALER_GENERIC_ITERABLE_TYPES[ta.get_origin(ty)]
@@ -1546,33 +1549,71 @@ def _make_obj_marshaler(ty: ta.Any) -> ObjMarshaler:
1546
1549
  pass
1547
1550
  else:
1548
1551
  [e] = ta.get_args(ty)
1549
- return IterableObjMarshaler(st, get_obj_marshaler(e))
1552
+ return IterableObjMarshaler(st, rec(e))
1550
1553
 
1551
1554
  if is_union_alias(ty):
1552
- return OptionalObjMarshaler(get_obj_marshaler(get_optional_alias_arg(ty)))
1555
+ return OptionalObjMarshaler(rec(get_optional_alias_arg(ty)))
1553
1556
 
1554
1557
  raise TypeError(ty)
1555
1558
 
1556
1559
 
1557
- def get_obj_marshaler(ty: ta.Any) -> ObjMarshaler:
1558
- try:
1559
- return _OBJ_MARSHALERS[ty]
1560
- except KeyError:
1561
- pass
1560
+ ##
1562
1561
 
1563
- p = ProxyObjMarshaler()
1564
- _OBJ_MARSHALERS[ty] = p
1565
- try:
1566
- m = _make_obj_marshaler(ty)
1567
- except Exception:
1568
- del _OBJ_MARSHALERS[ty]
1569
- raise
1570
- else:
1571
- p.m = m
1562
+
1563
+ _OBJ_MARSHALERS_LOCK = threading.RLock()
1564
+
1565
+ _OBJ_MARSHALERS: ta.Dict[ta.Any, ObjMarshaler] = dict(_DEFAULT_OBJ_MARSHALERS)
1566
+
1567
+ _OBJ_MARSHALER_PROXIES: ta.Dict[ta.Any, ProxyObjMarshaler] = {}
1568
+
1569
+
1570
+ def register_opj_marshaler(ty: ta.Any, m: ObjMarshaler) -> None:
1571
+ with _OBJ_MARSHALERS_LOCK:
1572
+ if ty in _OBJ_MARSHALERS:
1573
+ raise KeyError(ty)
1572
1574
  _OBJ_MARSHALERS[ty] = m
1575
+
1576
+
1577
+ def get_obj_marshaler(
1578
+ ty: ta.Any,
1579
+ *,
1580
+ no_cache: bool = False,
1581
+ **kwargs: ta.Any,
1582
+ ) -> ObjMarshaler:
1583
+ with _OBJ_MARSHALERS_LOCK:
1584
+ if not no_cache:
1585
+ try:
1586
+ return _OBJ_MARSHALERS[ty]
1587
+ except KeyError:
1588
+ pass
1589
+
1590
+ try:
1591
+ return _OBJ_MARSHALER_PROXIES[ty]
1592
+ except KeyError:
1593
+ pass
1594
+
1595
+ rec = functools.partial(
1596
+ get_obj_marshaler,
1597
+ no_cache=no_cache,
1598
+ **kwargs,
1599
+ )
1600
+
1601
+ p = ProxyObjMarshaler()
1602
+ _OBJ_MARSHALER_PROXIES[ty] = p
1603
+ try:
1604
+ m = _make_obj_marshaler(ty, rec, **kwargs)
1605
+ finally:
1606
+ del _OBJ_MARSHALER_PROXIES[ty]
1607
+ p.m = m
1608
+
1609
+ if not no_cache:
1610
+ _OBJ_MARSHALERS[ty] = m
1573
1611
  return m
1574
1612
 
1575
1613
 
1614
+ ##
1615
+
1616
+
1576
1617
  def marshal_obj(o: ta.Any, ty: ta.Any = None) -> ta.Any:
1577
1618
  return get_obj_marshaler(ty if ty is not None else type(o)).marshal(o)
1578
1619
 
@@ -0,0 +1,139 @@
1
+ # ruff: noqa: UP006 UP007
2
+ # @omlish-lite
3
+ """
4
+ TODO:
5
+ - implement stop lol
6
+ - collective heartbeat monitoring - ThreadWorkerGroups
7
+ - group -> 'context'? :|
8
+ - shared stop_event?
9
+ """
10
+ import abc
11
+ import dataclasses as dc
12
+ import threading
13
+ import time
14
+ import typing as ta
15
+
16
+ from omlish.lite.contextmanagers import ExitStacked
17
+ from omlish.lite.logs import log
18
+
19
+
20
+ T = ta.TypeVar('T')
21
+ ThreadWorkerT = ta.TypeVar('ThreadWorkerT', bound='ThreadWorker')
22
+
23
+
24
+ ##
25
+
26
+
27
+ class ThreadWorker(ExitStacked, abc.ABC):
28
+ def __init__(
29
+ self,
30
+ *,
31
+ stop_event: ta.Optional[threading.Event] = None,
32
+ ) -> None:
33
+ super().__init__()
34
+
35
+ if stop_event is None:
36
+ stop_event = threading.Event()
37
+ self._stop_event = stop_event
38
+
39
+ self._lock = threading.RLock()
40
+ self._thread: ta.Optional[threading.Thread] = None
41
+ self._last_heartbeat: ta.Optional[float] = None
42
+
43
+ #
44
+
45
+ def __enter__(self: ThreadWorkerT) -> ThreadWorkerT:
46
+ with self._lock:
47
+ return super().__enter__() # noqa
48
+
49
+ #
50
+
51
+ def should_stop(self) -> bool:
52
+ return self._stop_event.is_set()
53
+
54
+ class Stopping(Exception): # noqa
55
+ pass
56
+
57
+ #
58
+
59
+ @property
60
+ def last_heartbeat(self) -> ta.Optional[float]:
61
+ return self._last_heartbeat
62
+
63
+ def _heartbeat(
64
+ self,
65
+ *,
66
+ no_stop_check: bool = False,
67
+ ) -> None:
68
+ self._last_heartbeat = time.time()
69
+
70
+ if not no_stop_check and self.should_stop():
71
+ log.info('Stopping: %s', self)
72
+ raise ThreadWorker.Stopping
73
+
74
+ #
75
+
76
+ def has_started(self) -> bool:
77
+ return self._thread is not None
78
+
79
+ def is_alive(self) -> bool:
80
+ return (thr := self._thread) is not None and thr.is_alive()
81
+
82
+ def start(self) -> None:
83
+ with self._lock:
84
+ if self._thread is not None:
85
+ raise RuntimeError('Thread already started: %r', self)
86
+
87
+ thr = threading.Thread(target=self.__run)
88
+ self._thread = thr
89
+ thr.start()
90
+
91
+ #
92
+
93
+ def __run(self) -> None:
94
+ try:
95
+ self._run()
96
+ except ThreadWorker.Stopping:
97
+ log.exception('Thread worker stopped: %r', self)
98
+ except Exception: # noqa
99
+ log.exception('Error in worker thread: %r', self)
100
+ raise
101
+
102
+ @abc.abstractmethod
103
+ def _run(self) -> None:
104
+ raise NotImplementedError
105
+
106
+ #
107
+
108
+ def stop(self) -> None:
109
+ self._stop_event.set()
110
+
111
+ def join(self, timeout: ta.Optional[float] = None) -> None:
112
+ with self._lock:
113
+ if self._thread is None:
114
+ raise RuntimeError('Thread not started: %r', self)
115
+ self._thread.join(timeout)
116
+
117
+
118
+ ##
119
+
120
+
121
+ class ThreadWorkerGroup:
122
+ @dc.dataclass()
123
+ class State:
124
+ worker: ThreadWorker
125
+
126
+ def __init__(self) -> None:
127
+ super().__init__()
128
+
129
+ self._lock = threading.RLock()
130
+ self._states: ta.Dict[ThreadWorker, ThreadWorkerGroup.State] = {}
131
+
132
+ def add(self, *workers: ThreadWorker) -> 'ThreadWorkerGroup':
133
+ with self._lock:
134
+ for w in workers:
135
+ if w in self._states:
136
+ raise KeyError(w)
137
+ self._states[w] = ThreadWorkerGroup.State(w)
138
+
139
+ return self
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ominfra
3
- Version: 0.0.0.dev102
3
+ Version: 0.0.0.dev104
4
4
  Summary: ominfra
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -12,8 +12,8 @@ Classifier: Operating System :: OS Independent
12
12
  Classifier: Operating System :: POSIX
13
13
  Requires-Python: >=3.12
14
14
  License-File: LICENSE
15
- Requires-Dist: omdev ==0.0.0.dev102
16
- Requires-Dist: omlish ==0.0.0.dev102
15
+ Requires-Dist: omdev ==0.0.0.dev104
16
+ Requires-Dist: omlish ==0.0.0.dev104
17
17
  Provides-Extra: all
18
18
  Requires-Dist: paramiko ~=3.5 ; extra == 'all'
19
19
  Requires-Dist: asyncssh ~=2.18 ; extra == 'all'
@@ -3,19 +3,24 @@ ominfra/__about__.py,sha256=6i1AoruFYQCd-PyhhbDQDWY2d1tiQu9nkwWr-fXAqfY,705
3
3
  ominfra/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  ominfra/cmds.py,sha256=E0AfnvEmnKntXWvmLW5L05_NeDpBET1VBXn7vV6EwBQ,2083
5
5
  ominfra/ssh.py,sha256=jQpc4WvkMckIfk4vILda8zFaeharRqc_6wxW50b0OjQ,5431
6
- ominfra/threadworker.py,sha256=8rnWvgKjPIAdctS6wxiUiEIzm-mORRkWVD94YghVj0g,1413
6
+ ominfra/threadworkers.py,sha256=QuRpz9Yjyb4F8_IjzqmL7eNCAmXZfy3XLl7QoVF7Ohw,3273
7
7
  ominfra/clouds/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  ominfra/clouds/aws/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  ominfra/clouds/aws/__main__.py,sha256=HXMoxEl9KHhv6zOOPQxiJAftfR2SjBqeVTYw-og9aFw,163
10
10
  ominfra/clouds/aws/auth.py,sha256=p50hnm8SU4CWAkLX0C4XCTAm7yAAg-HqcP1YvL5cW94,6205
11
11
  ominfra/clouds/aws/cli.py,sha256=OJVVLIwSy1378drkgP1ke_JltbyzBmnrB_Lom6A83os,510
12
12
  ominfra/clouds/aws/dataclasses.py,sha256=rKhtJKJ0JhMssU9n9CABX_JaUiokIboEATJ9TZgZQ6A,3868
13
- ominfra/clouds/aws/logs.py,sha256=7Cl9vjco6G-5wW06TmuzU9GZ-diFP8V26X2UZnfJD3U,5232
13
+ ominfra/clouds/aws/logs.py,sha256=z9ouU2IYXNHsl7_Whbjs1FGtlUwsEq0RV8LNrM_QNTE,5471
14
14
  ominfra/clouds/aws/metadata.py,sha256=XR1BuMdQheyeFjjA3MN8GCNWVAp5ahoPdbWXEmViutQ,2767
15
15
  ominfra/clouds/aws/journald2aws/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
16
- ominfra/clouds/aws/journald2aws/main.py,sha256=d7jSbcaxjGgpVpDCPl1kJCOZg3S7g2n0Lf7gI0ZL3j0,9126
16
+ ominfra/clouds/aws/journald2aws/cursor.py,sha256=tQ7O6BHlEdaalbiI_Rqagj0aHfdtTQ_ZJwdOSRUjNvQ,1173
17
+ ominfra/clouds/aws/journald2aws/driver.py,sha256=8jiuEpOgKFSucpEJBBTBiSVg6L_tA4alUNK-I788HWU,5452
18
+ ominfra/clouds/aws/journald2aws/main.py,sha256=xFkEhkYKtFfW0XRfY0UaX_gd_FU66WTZOMCyiIaPY3E,2237
19
+ ominfra/clouds/aws/journald2aws/poster.py,sha256=hz1XuctW8GtLmfjhRvCFY6py52D4BzXHYny5XKFpHSA,2833
20
+ ominfra/clouds/gcp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
+ ominfra/clouds/gcp/auth.py,sha256=3PyfRJNgajjMqJFem3SKui0CqGeHEsZlvbRhuxFcZG8,1348
17
22
  ominfra/deploy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
- ominfra/deploy/_executor.py,sha256=zHn4zAz6Ch1i5R_EdKTfJv_4SE0QPNuQEk7O1ptB_7A,32834
23
+ ominfra/deploy/_executor.py,sha256=3_ndcukzPt6Pc-5Cfnxz4OFjOYJefuTYM6ouijRjhTs,34042
19
24
  ominfra/deploy/configs.py,sha256=qi0kwT7G2NH7dXLOQic-u6R3yeadup_QtvrjwWIggbM,435
20
25
  ominfra/deploy/remote.py,sha256=6ACmpXU1uBdyGs3Xsp97ktKFq30cJlzN9LRWNUWlGY4,2144
21
26
  ominfra/deploy/executor/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
@@ -30,7 +35,7 @@ ominfra/deploy/executor/concerns/systemd.py,sha256=MtsSEToEa1HNouern_JukcYTnypw_
30
35
  ominfra/deploy/executor/concerns/user.py,sha256=j5LDfQXquIp-eEM7t6aShsrYoQrM_ILXZycTmTcRVxA,686
31
36
  ominfra/deploy/executor/concerns/venv.py,sha256=jbRriqJHO4r9Zyo5Hfl_qVmcU6Qm6UgrouBroKcPn2g,775
32
37
  ominfra/deploy/poly/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
33
- ominfra/deploy/poly/_main.py,sha256=atzVWMa2FZlJYODcRxu5zN5CHOLiVW9aIS9f012QKWA,23569
38
+ ominfra/deploy/poly/_main.py,sha256=EtMN9Cmn4plMLTXq3u_NHUUhaa8qjsyldN61AbjDQEg,24025
34
39
  ominfra/deploy/poly/base.py,sha256=Bd-CzUTaDvTRbdXKiTxMxs77WCEXItwNoBYCRnTk1u4,4167
35
40
  ominfra/deploy/poly/configs.py,sha256=9bzWdbxhOk_Q4KokDjmRz254KHnUU71Vl1frLlhQyU4,584
36
41
  ominfra/deploy/poly/deploy.py,sha256=tMYKslXLjstcv86siRt5j37USsS0Wd6lsfeGRE26zio,544
@@ -42,18 +47,18 @@ ominfra/deploy/poly/site.py,sha256=QJwDDJoVm2-kxi4bxIrp-mn4y2qDLuW3CAUax3W8gv8,2
42
47
  ominfra/deploy/poly/supervisor.py,sha256=zkl6VQBcAZaMAhyR9DbbbqULcgFCDZoe9S_vP-mMFQ8,2289
43
48
  ominfra/deploy/poly/venv.py,sha256=BoipDEa4NTeodjf3L57KJfq9eGKLagFNKwD8pS4yrzA,1552
44
49
  ominfra/journald/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
45
- ominfra/journald/genmessages.py,sha256=3lB3W_Xl4GLAutNu1KvihdtMvkkukYqrfsamcqOS204,1583
50
+ ominfra/journald/genmessages.py,sha256=rLTS-K2v7otNOtTz4RoOEVYCm0fQuuBzf47e0T61tA8,1857
46
51
  ominfra/journald/messages.py,sha256=2iMY4k63XGNcN3LPvBmmK55ftjupnNh8f_ijlW9mkhQ,2208
47
- ominfra/journald/tailer.py,sha256=4CzBTQcAzlW9OQ--61fIdClZVgbMQQnYe2OD1d5P7e4,36780
52
+ ominfra/journald/tailer.py,sha256=-CTQPkDQUBJJOpQCueFDsF5VmlfPSaSrbrGB505SUuM,36819
48
53
  ominfra/manage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
49
54
  ominfra/manage/manage.py,sha256=BttL8LFEknHZE_h2Pt5dAqbfUkv6qy43WI0raXBZ1a8,151
50
55
  ominfra/pyremote/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
51
- ominfra/pyremote/_runcommands.py,sha256=2UVHaUJjmWP8jMZE79j2Qk1E5IOyVV1qNSUbdr-zKYM,26670
56
+ ominfra/pyremote/_runcommands.py,sha256=IGFDDcmXJDmhGv7AFAAjkCJc615YQGUsNvn5vTAYReY,27878
52
57
  ominfra/pyremote/bootstrap.py,sha256=RvMO3YGaN1E4sgUi1JEtiPak8cjvqtc_vRCq1yqbeZg,3370
53
58
  ominfra/pyremote/runcommands.py,sha256=bviS0_TDIoZVAe4h-_iavbvJtVSFu8lnk7fQ5iasCWE,1571
54
59
  ominfra/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
- ominfra/scripts/journald2aws.py,sha256=AgOHKPujUo4SqTFoz_EiN-oJ-HwZJB-UNyCFJypsNus,91403
56
- ominfra/scripts/supervisor.py,sha256=iWTZQIrzqNjlmuDH489AlfXGb0i_0sfoYIYP7h1LH-E,115374
60
+ ominfra/scripts/journald2aws.py,sha256=ZI6SppxsDEwnjk0zaBmAmhyi3-3VVbWubDkeGz_DEU8,98035
61
+ ominfra/scripts/supervisor.py,sha256=Qf6WKD_4EkC_5QWimApONAAs3lvcAKK2X7nOaYDex48,116162
57
62
  ominfra/supervisor/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
58
63
  ominfra/supervisor/__main__.py,sha256=usW9jjq5JPe_2SL8H5PrjDdksO75MX85Ir0HFfb35eM,72
59
64
  ominfra/supervisor/compat.py,sha256=Y1d_pk4eN18AbVYjDHAXMMnPwOKTFpc7JDb1uClYMsQ,5064
@@ -73,9 +78,9 @@ ominfra/tailscale/api.py,sha256=C5-t_b6jZXUWcy5k8bXm7CFnk73pSdrlMOgGDeGVrpw,1370
73
78
  ominfra/tailscale/cli.py,sha256=DSGp4hn5xwOW-l_u_InKlSF6kIobxtUtVssf_73STs0,3567
74
79
  ominfra/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
75
80
  ominfra/tools/listresources.py,sha256=4qVg5txsb10EHhvqXXeM6gJ2jx9LbroEnPydDv1uXs0,6176
76
- ominfra-0.0.0.dev102.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
77
- ominfra-0.0.0.dev102.dist-info/METADATA,sha256=204uohL25Cyu3_Op6fWaH6j4qlPBlc60pKcNBCjU8SU,742
78
- ominfra-0.0.0.dev102.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
79
- ominfra-0.0.0.dev102.dist-info/entry_points.txt,sha256=kgecQ2MgGrM9qK744BoKS3tMesaC3yjLnl9pa5CRczg,37
80
- ominfra-0.0.0.dev102.dist-info/top_level.txt,sha256=E-b2OHkk_AOBLXHYZQ2EOFKl-_6uOGd8EjeG-Zy6h_w,8
81
- ominfra-0.0.0.dev102.dist-info/RECORD,,
81
+ ominfra-0.0.0.dev104.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
82
+ ominfra-0.0.0.dev104.dist-info/METADATA,sha256=6dWv52GEcIq4huozhiXk8aClmrjz-5u0kcanUmUIiQs,742
83
+ ominfra-0.0.0.dev104.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
84
+ ominfra-0.0.0.dev104.dist-info/entry_points.txt,sha256=kgecQ2MgGrM9qK744BoKS3tMesaC3yjLnl9pa5CRczg,37
85
+ ominfra-0.0.0.dev104.dist-info/top_level.txt,sha256=E-b2OHkk_AOBLXHYZQ2EOFKl-_6uOGd8EjeG-Zy6h_w,8
86
+ ominfra-0.0.0.dev104.dist-info/RECORD,,
ominfra/threadworker.py DELETED
@@ -1,67 +0,0 @@
1
- # ruff: noqa: UP007
2
- # @omlish-lite
3
- """
4
- TODO:
5
- - implement stop lol
6
- - collective heartbeat monitoring - ThreadWorkerGroups
7
- """
8
- import abc
9
- import threading
10
- import time
11
- import typing as ta
12
-
13
- from omlish.lite.logs import log
14
-
15
-
16
- class ThreadWorker(abc.ABC):
17
- def __init__(
18
- self,
19
- *,
20
- stop_event: ta.Optional[threading.Event] = None,
21
- ) -> None:
22
- super().__init__()
23
-
24
- if stop_event is None:
25
- stop_event = threading.Event()
26
- self._stop_event = stop_event
27
-
28
- self._thread: ta.Optional[threading.Thread] = None
29
-
30
- self._last_heartbeat: ta.Optional[float] = None
31
-
32
- #
33
-
34
- def should_stop(self) -> bool:
35
- return self._stop_event.is_set()
36
-
37
- #
38
-
39
- @property
40
- def last_heartbeat(self) -> ta.Optional[float]:
41
- return self._last_heartbeat
42
-
43
- def _heartbeat(self) -> bool:
44
- self._last_heartbeat = time.time()
45
-
46
- if self.should_stop():
47
- log.info('Stopping: %s', self)
48
- return False
49
-
50
- return True
51
-
52
- #
53
-
54
- def is_alive(self) -> bool:
55
- return (thr := self._thread) is not None and thr.is_alive()
56
-
57
- def start(self) -> None:
58
- thr = threading.Thread(target=self._run)
59
- self._thread = thr
60
- thr.start()
61
-
62
- @abc.abstractmethod
63
- def _run(self) -> None:
64
- raise NotImplementedError
65
-
66
- def stop(self) -> None:
67
- raise NotImplementedError