ominfra 0.0.0.dev102__py3-none-any.whl → 0.0.0.dev103__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)
@@ -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.dev103
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.dev103
16
+ Requires-Dist: omlish ==0.0.0.dev103
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,22 @@ 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
17
20
  ominfra/deploy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
- ominfra/deploy/_executor.py,sha256=zHn4zAz6Ch1i5R_EdKTfJv_4SE0QPNuQEk7O1ptB_7A,32834
21
+ ominfra/deploy/_executor.py,sha256=w3qpyRtoIfpm9HgygGb4jo1Wx8-Nz8U3CXSuwBcTFl4,33258
19
22
  ominfra/deploy/configs.py,sha256=qi0kwT7G2NH7dXLOQic-u6R3yeadup_QtvrjwWIggbM,435
20
23
  ominfra/deploy/remote.py,sha256=6ACmpXU1uBdyGs3Xsp97ktKFq30cJlzN9LRWNUWlGY4,2144
21
24
  ominfra/deploy/executor/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
@@ -30,7 +33,7 @@ ominfra/deploy/executor/concerns/systemd.py,sha256=MtsSEToEa1HNouern_JukcYTnypw_
30
33
  ominfra/deploy/executor/concerns/user.py,sha256=j5LDfQXquIp-eEM7t6aShsrYoQrM_ILXZycTmTcRVxA,686
31
34
  ominfra/deploy/executor/concerns/venv.py,sha256=jbRriqJHO4r9Zyo5Hfl_qVmcU6Qm6UgrouBroKcPn2g,775
32
35
  ominfra/deploy/poly/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
33
- ominfra/deploy/poly/_main.py,sha256=atzVWMa2FZlJYODcRxu5zN5CHOLiVW9aIS9f012QKWA,23569
36
+ ominfra/deploy/poly/_main.py,sha256=EtMN9Cmn4plMLTXq3u_NHUUhaa8qjsyldN61AbjDQEg,24025
34
37
  ominfra/deploy/poly/base.py,sha256=Bd-CzUTaDvTRbdXKiTxMxs77WCEXItwNoBYCRnTk1u4,4167
35
38
  ominfra/deploy/poly/configs.py,sha256=9bzWdbxhOk_Q4KokDjmRz254KHnUU71Vl1frLlhQyU4,584
36
39
  ominfra/deploy/poly/deploy.py,sha256=tMYKslXLjstcv86siRt5j37USsS0Wd6lsfeGRE26zio,544
@@ -42,18 +45,18 @@ ominfra/deploy/poly/site.py,sha256=QJwDDJoVm2-kxi4bxIrp-mn4y2qDLuW3CAUax3W8gv8,2
42
45
  ominfra/deploy/poly/supervisor.py,sha256=zkl6VQBcAZaMAhyR9DbbbqULcgFCDZoe9S_vP-mMFQ8,2289
43
46
  ominfra/deploy/poly/venv.py,sha256=BoipDEa4NTeodjf3L57KJfq9eGKLagFNKwD8pS4yrzA,1552
44
47
  ominfra/journald/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
45
- ominfra/journald/genmessages.py,sha256=3lB3W_Xl4GLAutNu1KvihdtMvkkukYqrfsamcqOS204,1583
48
+ ominfra/journald/genmessages.py,sha256=rLTS-K2v7otNOtTz4RoOEVYCm0fQuuBzf47e0T61tA8,1857
46
49
  ominfra/journald/messages.py,sha256=2iMY4k63XGNcN3LPvBmmK55ftjupnNh8f_ijlW9mkhQ,2208
47
- ominfra/journald/tailer.py,sha256=4CzBTQcAzlW9OQ--61fIdClZVgbMQQnYe2OD1d5P7e4,36780
50
+ ominfra/journald/tailer.py,sha256=-CTQPkDQUBJJOpQCueFDsF5VmlfPSaSrbrGB505SUuM,36819
48
51
  ominfra/manage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
49
52
  ominfra/manage/manage.py,sha256=BttL8LFEknHZE_h2Pt5dAqbfUkv6qy43WI0raXBZ1a8,151
50
53
  ominfra/pyremote/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
51
- ominfra/pyremote/_runcommands.py,sha256=2UVHaUJjmWP8jMZE79j2Qk1E5IOyVV1qNSUbdr-zKYM,26670
54
+ ominfra/pyremote/_runcommands.py,sha256=xA-wRpLtGha6ZZyatGokL9kyz43GOB_ZB_WLZcd8gFE,27094
52
55
  ominfra/pyremote/bootstrap.py,sha256=RvMO3YGaN1E4sgUi1JEtiPak8cjvqtc_vRCq1yqbeZg,3370
53
56
  ominfra/pyremote/runcommands.py,sha256=bviS0_TDIoZVAe4h-_iavbvJtVSFu8lnk7fQ5iasCWE,1571
54
57
  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
58
+ ominfra/scripts/journald2aws.py,sha256=4DzyNn8KjrBfHNtENgp7EVL569PLqzQnQu6PQXgqPgg,97251
59
+ ominfra/scripts/supervisor.py,sha256=2rf7CCgqpYY6Pt7Yq69n4V7CY-Sas_0MyDO3SIv2tPw,115378
57
60
  ominfra/supervisor/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
58
61
  ominfra/supervisor/__main__.py,sha256=usW9jjq5JPe_2SL8H5PrjDdksO75MX85Ir0HFfb35eM,72
59
62
  ominfra/supervisor/compat.py,sha256=Y1d_pk4eN18AbVYjDHAXMMnPwOKTFpc7JDb1uClYMsQ,5064
@@ -73,9 +76,9 @@ ominfra/tailscale/api.py,sha256=C5-t_b6jZXUWcy5k8bXm7CFnk73pSdrlMOgGDeGVrpw,1370
73
76
  ominfra/tailscale/cli.py,sha256=DSGp4hn5xwOW-l_u_InKlSF6kIobxtUtVssf_73STs0,3567
74
77
  ominfra/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
75
78
  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,,
79
+ ominfra-0.0.0.dev103.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
80
+ ominfra-0.0.0.dev103.dist-info/METADATA,sha256=p_SRGaoGDeFXyv_pvHCMjqaDP6umkRhGCsrtly5uJQs,742
81
+ ominfra-0.0.0.dev103.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
82
+ ominfra-0.0.0.dev103.dist-info/entry_points.txt,sha256=kgecQ2MgGrM9qK744BoKS3tMesaC3yjLnl9pa5CRczg,37
83
+ ominfra-0.0.0.dev103.dist-info/top_level.txt,sha256=E-b2OHkk_AOBLXHYZQ2EOFKl-_6uOGd8EjeG-Zy6h_w,8
84
+ ominfra-0.0.0.dev103.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