omlish 0.0.0.dev226__py3-none-any.whl → 0.0.0.dev228__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.
Files changed (50) hide show
  1. omlish/__about__.py +3 -3
  2. omlish/diag/lslocks.py +4 -4
  3. omlish/diag/lsof.py +3 -4
  4. omlish/diag/ps.py +9 -0
  5. omlish/lite/timeouts.py +1 -1
  6. omlish/marshal/__init__.py +39 -24
  7. omlish/marshal/composite/__init__.py +0 -0
  8. omlish/marshal/{iterables.py → composite/iterables.py} +10 -10
  9. omlish/marshal/{literals.py → composite/literals.py} +9 -9
  10. omlish/marshal/{mappings.py → composite/mappings.py} +10 -10
  11. omlish/marshal/{maybes.py → composite/maybes.py} +11 -11
  12. omlish/marshal/{newtypes.py → composite/newtypes.py} +8 -8
  13. omlish/marshal/{optionals.py → composite/optionals.py} +9 -9
  14. omlish/marshal/objects/__init__.py +7 -0
  15. omlish/marshal/{dataclasses.py → objects/dataclasses.py} +24 -24
  16. omlish/marshal/{helpers.py → objects/helpers.py} +6 -3
  17. omlish/marshal/objects/marshal.py +108 -0
  18. omlish/marshal/objects/metadata.py +124 -0
  19. omlish/marshal/{namedtuples.py → objects/namedtuples.py} +16 -16
  20. omlish/marshal/objects/unmarshal.py +141 -0
  21. omlish/marshal/polymorphism/__init__.py +7 -0
  22. omlish/marshal/polymorphism/marshal.py +66 -0
  23. omlish/marshal/polymorphism/metadata.py +140 -0
  24. omlish/marshal/{unions.py → polymorphism/unions.py} +18 -18
  25. omlish/marshal/polymorphism/unmarshal.py +73 -0
  26. omlish/marshal/singular/__init__.py +0 -0
  27. omlish/marshal/{any.py → singular/any.py} +8 -8
  28. omlish/marshal/{base64.py → singular/base64.py} +9 -9
  29. omlish/marshal/{datetimes.py → singular/datetimes.py} +9 -9
  30. omlish/marshal/{enums.py → singular/enums.py} +9 -9
  31. omlish/marshal/{numbers.py → singular/numbers.py} +8 -8
  32. omlish/marshal/{primitives.py → singular/primitives.py} +8 -8
  33. omlish/marshal/{uuids.py → singular/uuids.py} +8 -8
  34. omlish/marshal/standard.py +32 -32
  35. omlish/os/death.py +70 -4
  36. omlish/os/fcntl.py +11 -12
  37. omlish/os/files.py +18 -3
  38. omlish/os/forkhooks.py +215 -0
  39. omlish/os/pidfiles/manager.py +4 -1
  40. omlish/os/pidfiles/pidfile.py +31 -11
  41. omlish/os/pidfiles/pinning.py +250 -0
  42. omlish/sockets/bind.py +4 -4
  43. {omlish-0.0.0.dev226.dist-info → omlish-0.0.0.dev228.dist-info}/METADATA +3 -3
  44. {omlish-0.0.0.dev226.dist-info → omlish-0.0.0.dev228.dist-info}/RECORD +48 -38
  45. omlish/marshal/objects.py +0 -317
  46. omlish/marshal/polymorphism.py +0 -267
  47. {omlish-0.0.0.dev226.dist-info → omlish-0.0.0.dev228.dist-info}/LICENSE +0 -0
  48. {omlish-0.0.0.dev226.dist-info → omlish-0.0.0.dev228.dist-info}/WHEEL +0 -0
  49. {omlish-0.0.0.dev226.dist-info → omlish-0.0.0.dev228.dist-info}/entry_points.txt +0 -0
  50. {omlish-0.0.0.dev226.dist-info → omlish-0.0.0.dev228.dist-info}/top_level.txt +0 -0
@@ -109,7 +109,7 @@ class Pidfile:
109
109
  del self._f
110
110
  return True
111
111
 
112
- def try_lock(self) -> bool:
112
+ def try_acquire_lock(self) -> bool:
113
113
  try:
114
114
  fcntl.flock(self._f, fcntl.LOCK_EX | fcntl.LOCK_NB)
115
115
  return True
@@ -117,14 +117,29 @@ class Pidfile:
117
117
  except OSError:
118
118
  return False
119
119
 
120
- def ensure_locked(self) -> None:
121
- if not self.try_lock():
122
- raise RuntimeError('Could not get lock')
120
+ #
121
+
122
+ class Error(Exception):
123
+ pass
124
+
125
+ class LockedError(Error):
126
+ pass
127
+
128
+ def acquire_lock(self) -> None:
129
+ if not self.try_acquire_lock():
130
+ raise self.LockedError
131
+
132
+ class NotLockedError(Error):
133
+ pass
134
+
135
+ def ensure_cannot_lock(self) -> None:
136
+ if self.try_acquire_lock():
137
+ raise self.NotLockedError
123
138
 
124
139
  #
125
140
 
126
141
  def write(self, pid: ta.Optional[int] = None) -> None:
127
- self.ensure_locked()
142
+ self.acquire_lock()
128
143
 
129
144
  if pid is None:
130
145
  pid = os.getpid()
@@ -135,18 +150,23 @@ class Pidfile:
135
150
  self._f.flush()
136
151
 
137
152
  def clear(self) -> None:
138
- self.ensure_locked()
153
+ self.acquire_lock()
139
154
 
140
155
  self._f.seek(0)
141
156
  self._f.truncate()
142
157
 
143
- def read(self) -> int:
144
- if self.try_lock():
145
- raise RuntimeError('Got lock')
158
+ #
159
+
160
+ def read(self) -> ta.Optional[int]:
161
+ self.ensure_cannot_lock()
146
162
 
147
163
  self._f.seek(0)
148
- return int(self._f.read())
164
+ buf = self._f.read()
165
+ if not buf:
166
+ return None
167
+ return int(buf)
149
168
 
150
169
  def kill(self, sig: int = signal.SIGTERM) -> None:
151
- pid = self.read()
170
+ if (pid := self.read()) is None:
171
+ raise self.Error(f'Pidfile locked but empty')
152
172
  os.kill(pid, sig)
@@ -0,0 +1,250 @@
1
+ # ruff: noqa: UP006 UP007
2
+ # @omlish-lite
3
+ """
4
+ Notes:
5
+ - still racy as to if it's a different actual process as initial check, just with same pid, but due to 'identity' /
6
+ semantic meaning of the named pidfile the processes are considered equivalent
7
+
8
+ Strategies:
9
+ - linux
10
+ - get pid of owner (lslocks or F_GETLK)
11
+ - open pidfd to owner pid
12
+ - re-check pid of owner
13
+ - darwin
14
+ - get pids of referrers (lsof)
15
+ - read pid from file
16
+ - ensure pid is in referrers
17
+ - optionally loop
18
+ - ? setup pid death watcher? still a race
19
+ """
20
+ import abc
21
+ import contextlib
22
+ import os.path
23
+ import shutil
24
+ import sys
25
+ import time
26
+ import typing as ta
27
+
28
+ from ...diag.lslocks import LslocksCommand
29
+ from ...diag.lsof import LsofCommand
30
+ from ...lite.timeouts import Timeout
31
+ from ...lite.timeouts import TimeoutLike
32
+ from ...subprocesses.sync import subprocesses # noqa
33
+ from .pidfile import Pidfile
34
+
35
+
36
+ ##
37
+
38
+
39
+ class PidfilePinner(abc.ABC):
40
+ def __init__(
41
+ self,
42
+ *,
43
+ sleep_s: float = .1,
44
+ ) -> None:
45
+ super().__init__()
46
+
47
+ self._sleep_s = sleep_s
48
+
49
+ @classmethod
50
+ @abc.abstractmethod
51
+ def is_available(cls) -> bool:
52
+ raise NotImplementedError
53
+
54
+ class NoOwnerError(Exception):
55
+ pass
56
+
57
+ @abc.abstractmethod
58
+ def _pin_pidfile_owner(self, pidfile: Pidfile, timeout: Timeout) -> ta.ContextManager[int]:
59
+ raise NotImplementedError
60
+
61
+ @contextlib.contextmanager
62
+ def pin_pidfile_owner(
63
+ self,
64
+ path: str,
65
+ *,
66
+ timeout: ta.Optional[TimeoutLike] = None,
67
+ ) -> ta.Iterator[int]:
68
+ timeout = Timeout.of(timeout)
69
+
70
+ if not os.path.isfile(path):
71
+ raise self.NoOwnerError
72
+
73
+ with Pidfile(path, inheritable=False) as pf:
74
+ try:
75
+ with self._pin_pidfile_owner(pf, timeout) as pid:
76
+ yield pid
77
+
78
+ except Pidfile.NotLockedError:
79
+ raise self.NoOwnerError from None
80
+
81
+ @classmethod
82
+ def default_impl(cls) -> ta.Type['PidfilePinner']:
83
+ for impl in [
84
+ LslocksPidfdPidfilePinner,
85
+ LsofPidfilePinner,
86
+ ]:
87
+ if impl.is_available():
88
+ return impl
89
+ return UnverifiedPidfilePinner
90
+
91
+
92
+ ##
93
+
94
+
95
+ class UnverifiedPidfilePinner(PidfilePinner):
96
+ @classmethod
97
+ def is_available(cls) -> bool:
98
+ return True
99
+
100
+ @contextlib.contextmanager
101
+ def _pin_pidfile_owner(self, pidfile: Pidfile, timeout: Timeout) -> ta.Iterator[int]:
102
+ while (pid := pidfile.read()) is None:
103
+ time.sleep(self._sleep_s)
104
+ timeout()
105
+
106
+ yield pid
107
+
108
+
109
+ ##
110
+
111
+
112
+ class LsofPidfilePinner(PidfilePinner):
113
+ """
114
+ Fundamentally wrong, but still better than nothing. Simply reads the file contents and ensures a valid contained pid
115
+ has the file open via `lsof`.
116
+ """
117
+
118
+ @classmethod
119
+ def is_available(cls) -> bool:
120
+ return shutil.which('lsof') is not None
121
+
122
+ def _try_read_and_verify(self, pf: Pidfile, timeout: Timeout) -> ta.Optional[int]:
123
+ if (initial_pid := pf.read()) is None:
124
+ return None
125
+
126
+ lsof_output = LsofCommand(
127
+ # pid=initial_pid,
128
+ file=os.path.abspath(pf.path),
129
+ ).run(
130
+ timeout=timeout,
131
+ )
132
+
133
+ lsof_pids: ta.Set[int] = set()
134
+ for li in lsof_output:
135
+ if li.pid is None:
136
+ continue
137
+ try:
138
+ li_pid = int(li.pid)
139
+ except ValueError:
140
+ continue
141
+ lsof_pids.add(li_pid)
142
+
143
+ if initial_pid not in lsof_pids:
144
+ return None
145
+
146
+ if (reread_pid := pf.read()) is None or reread_pid != initial_pid:
147
+ return None
148
+
149
+ return reread_pid
150
+
151
+ @contextlib.contextmanager
152
+ def _pin_pidfile_owner(self, pidfile: Pidfile, timeout: Timeout) -> ta.Iterator[int]:
153
+ while (pid := self._try_read_and_verify(pidfile, timeout)) is None:
154
+ time.sleep(self._sleep_s)
155
+ timeout()
156
+
157
+ yield pid
158
+
159
+
160
+ ##
161
+
162
+
163
+ class LslocksPidfdPidfilePinner(PidfilePinner):
164
+ """
165
+ Finds the locking pid via `lslocks`, opens a pidfd, then re-runs `lslocks` and rechecks the locking pid is the same.
166
+ """
167
+
168
+ @classmethod
169
+ def is_available(cls) -> bool:
170
+ return sys.platform == 'linux' and shutil.which('lslocks') is not None
171
+
172
+ def _read_locking_pid(self, path: str, timeout: Timeout) -> int:
173
+ lsl_output = LslocksCommand().run(timeout=timeout)
174
+
175
+ lsl_pids = {
176
+ li.pid
177
+ for li in lsl_output
178
+ if li.path == path
179
+ and li.type == 'FLOCK'
180
+ }
181
+ if not lsl_pids:
182
+ raise self.NoOwnerError
183
+ if len(lsl_pids) != 1:
184
+ raise RuntimeError(f'Multiple locks on file: {path}')
185
+
186
+ [pid] = lsl_pids
187
+ return pid
188
+
189
+ class _Result(ta.NamedTuple):
190
+ pid: int
191
+ pidfd: int
192
+
193
+ def _try_read_and_verify(
194
+ self,
195
+ pidfile: Pidfile,
196
+ timeout: Timeout,
197
+ ) -> ta.Optional[_Result]:
198
+ path = os.path.abspath(pidfile.path)
199
+ initial_pid = self._read_locking_pid(path, timeout)
200
+
201
+ try:
202
+ pidfd = os.open(f'/proc/{initial_pid}', os.O_RDONLY)
203
+ except FileNotFoundError:
204
+ raise self.NoOwnerError from None
205
+
206
+ try:
207
+ reread_pid = self._read_locking_pid(path, timeout)
208
+ if reread_pid != initial_pid:
209
+ os.close(pidfd)
210
+ return None
211
+
212
+ return self._Result(initial_pid, pidfd)
213
+
214
+ except BaseException:
215
+ os.close(pidfd)
216
+ raise
217
+
218
+ @contextlib.contextmanager
219
+ def _pin_pidfile_owner(
220
+ self,
221
+ pidfile: Pidfile,
222
+ timeout: Timeout,
223
+ ) -> ta.Iterator[int]:
224
+ while (res := self._try_read_and_verify(pidfile, timeout)) is None:
225
+ time.sleep(self._sleep_s)
226
+ timeout()
227
+
228
+ try:
229
+ yield res.pid
230
+ finally:
231
+ os.close(res.pidfd)
232
+
233
+
234
+ ##
235
+
236
+
237
+ if __name__ == '__main__':
238
+ def _main() -> None:
239
+ argparse = __import__('argparse')
240
+ parser = argparse.ArgumentParser()
241
+ parser.add_argument('file')
242
+ args = parser.parse_args()
243
+
244
+ with PidfilePinner.default_impl()().pin_pidfile_owner(
245
+ args.file,
246
+ timeout=5.,
247
+ ) as pid:
248
+ print(pid)
249
+
250
+ _main()
omlish/sockets/bind.py CHANGED
@@ -15,10 +15,10 @@ import socket as socket_
15
15
  import stat
16
16
  import typing as ta
17
17
 
18
- from omlish.lite.check import check
19
- from omlish.lite.dataclasses import dataclass_maybe_post_init
20
- from omlish.sockets.addresses import SocketAddress
21
- from omlish.sockets.addresses import SocketAndAddress
18
+ from ..lite.check import check
19
+ from ..lite.dataclasses import dataclass_maybe_post_init
20
+ from .addresses import SocketAddress
21
+ from .addresses import SocketAndAddress
22
22
 
23
23
 
24
24
  SocketBinderT = ta.TypeVar('SocketBinderT', bound='SocketBinder')
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: omlish
3
- Version: 0.0.0.dev226
3
+ Version: 0.0.0.dev228
4
4
  Summary: omlish
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -32,7 +32,7 @@ Requires-Dist: cbor2~=5.6; extra == "all"
32
32
  Requires-Dist: cloudpickle~=3.1; extra == "all"
33
33
  Requires-Dist: httpx[http2]~=0.28; extra == "all"
34
34
  Requires-Dist: wrapt~=1.17; extra == "all"
35
- Requires-Dist: cryptography~=43.0; extra == "all"
35
+ Requires-Dist: cryptography~=44.0; extra == "all"
36
36
  Requires-Dist: sqlalchemy[asyncio]~=2.0; extra == "all"
37
37
  Requires-Dist: pg8000~=1.31; extra == "all"
38
38
  Requires-Dist: pymysql~=1.1; extra == "all"
@@ -76,7 +76,7 @@ Requires-Dist: httpx[http2]~=0.28; extra == "http"
76
76
  Provides-Extra: misc
77
77
  Requires-Dist: wrapt~=1.17; extra == "misc"
78
78
  Provides-Extra: secrets
79
- Requires-Dist: cryptography~=43.0; extra == "secrets"
79
+ Requires-Dist: cryptography~=44.0; extra == "secrets"
80
80
  Provides-Extra: sqlalchemy
81
81
  Requires-Dist: sqlalchemy[asyncio]~=2.0; extra == "sqlalchemy"
82
82
  Provides-Extra: sqldrivers
@@ -1,5 +1,5 @@
1
1
  omlish/.manifests.json,sha256=YGmAnUBszmosQQ_7Hh2wwtDiYdYZ4unNKYzOtALuels,7968
2
- omlish/__about__.py,sha256=QR1QmjxqAJ538XauJdEuHH505rJ9QF67p3blNgi6kwc,3380
2
+ omlish/__about__.py,sha256=7YnXltr9so9p-_7zMJK4FLVkWPEZyjsuxoimC7Jjpb4,3380
3
3
  omlish/__init__.py,sha256=SsyiITTuK0v74XpKV8dqNaCmjOlan1JZKrHQv5rWKPA,253
4
4
  omlish/c3.py,sha256=ubu7lHwss5V4UznbejAI0qXhXahrU01MysuHOZI9C4U,8116
5
5
  omlish/cached.py,sha256=UI-XTFBwA6YXWJJJeBn-WkwBkfzDjLBBaZf4nIJA9y0,510
@@ -203,11 +203,11 @@ omlish/dataclasses/impl/utils.py,sha256=aER2iL3UAtgS1BdLuEvTr9Tr2wC28wk1kiOeO-jI
203
203
  omlish/diag/__init__.py,sha256=4S8v0myJM4Zld6_FV6cPe_nSv0aJb6kXftEit0HkiGE,1141
204
204
  omlish/diag/asts.py,sha256=BveUUNUcaAm4Hg55f4ZxGSI313E4L8cCZ5XjHpEkKVI,3325
205
205
  omlish/diag/debug.py,sha256=ClED7kKXeVMyKrjGIxcq14kXk9kvUJfytBQwK9y7c4Q,1637
206
- omlish/diag/lslocks.py,sha256=7I_u-Vx0Dz0KN59Y6dk9nBZynHa6usvKIXVSywGCiWE,1722
207
- omlish/diag/lsof.py,sha256=gMtNmfBo1AlYmvZWBB51u4NfbfC6yJyEVwfr1HgktP8,9328
206
+ omlish/diag/lslocks.py,sha256=fWI3SZwgEkhipVfSqvzVzREJRShcDYmlYByHBT0LToc,1744
207
+ omlish/diag/lsof.py,sha256=DnowqvKYah-WCuBHS3DAcZCvlsWJdM9kYNFq97UZDDA,9127
208
208
  omlish/diag/procfs.py,sha256=KaGTAA2Gj8eEEp7MjClRe4aimwzd-HDABThFzvq2cBQ,9684
209
209
  omlish/diag/procstats.py,sha256=UkqxREqfd-38xPYZ9T1SIJISz5ARQCEhTtOZrxtm2dE,777
210
- omlish/diag/ps.py,sha256=mwraPO6Nze_2r9RiC4dyLL0aJ_lHR1_fSN9BlYNBoHw,1651
210
+ omlish/diag/ps.py,sha256=b7ai9O4mGZliNFvBu6PdQfMmct4qpcMTygEf1ISHBLQ,1666
211
211
  omlish/diag/pycharm.py,sha256=7-r_F-whXt8v-0dehxAX-MeMFPM3iZXX9IfeL0GfUtk,4643
212
212
  omlish/diag/pydevd.py,sha256=UN55ZjkWLCVyHxE2CNRRYamuvSKfzWsn0D5oczRTXO4,7536
213
213
  omlish/diag/threads.py,sha256=1-x02VCDZ407gfbtXm1pWK-ubqhqfePm9PMqkHCVoqk,3642
@@ -433,7 +433,7 @@ omlish/lite/resources.py,sha256=YNSmX1Ohck1aoWRs55a-o5ChVbFJIQhtbqE-XwF55Oc,326
433
433
  omlish/lite/runtime.py,sha256=XQo408zxTdJdppUZqOWHyeUR50VlCpNIExNGHz4U6O4,459
434
434
  omlish/lite/secrets.py,sha256=3Mz3V2jf__XU9qNHcH56sBSw95L3U2UPL24bjvobG0c,816
435
435
  omlish/lite/strings.py,sha256=QGxT1Yh4oI8ycsfeobxnjEhvDob_GiAKLeIhZwo1j24,1986
436
- omlish/lite/timeouts.py,sha256=Bd_XaEmaGTsKcORfPt-AJECmf8Bt9XwjBfjkMacpEdM,4954
436
+ omlish/lite/timeouts.py,sha256=wZ6PP1D3B8jpAI7-cQm7wkGTh2sE366XIn6FSMH6DZ4,4959
437
437
  omlish/lite/timing.py,sha256=aVu3hEDB_jyTF_ryZI7iU-xg4q8CNwqpp9Apfru_iwY,196
438
438
  omlish/lite/types.py,sha256=fP5EMyBdEp2LmDxcHjUDtwAMdR06ISr9lKOL7smWfHM,140
439
439
  omlish/lite/typing.py,sha256=U3-JaEnkDSYxK4tsu_MzUn3RP6qALBe5FXQXpD-licE,1090
@@ -455,37 +455,45 @@ omlish/logs/utils.py,sha256=mzHrZ9ji75p5A8qR29eUr05CBAHMb8J753MSkID_VaQ,393
455
455
  omlish/manifests/__init__.py,sha256=P2B0dpT8D7l5lJwRGPA92IcQj6oeXfd90X5-q9BJrKg,51
456
456
  omlish/manifests/load.py,sha256=LrWAvBfdzDkFdLuVwfw2RwFvLjxx-rvfkpU9eBsWeIc,5626
457
457
  omlish/manifests/types.py,sha256=d8bv5tknCJqclRfxCpao_8XxHo2yofhLpVHQTB-MfNw,260
458
- omlish/marshal/__init__.py,sha256=iVA7n31L08Bdub6HKPvYOXVvDhk2CMA6rPeKDL_u1to,2298
459
- omlish/marshal/any.py,sha256=e82OyYK3Emm1P1ClnsnxP7fIWC2iNVyW0H5nK4mLmWM,779
458
+ omlish/marshal/__init__.py,sha256=o7EtBHbciL3OLz6zsMny-UGjyAfFXO1zRGIqVOPEKw0,2591
460
459
  omlish/marshal/base.py,sha256=HEzfby-PgGzIhiRpBkFrkw5-hKacRSC5W_jwLjT8aYw,6740
461
- omlish/marshal/base64.py,sha256=F-3ogJdcFCtWINRgJgWT0rErqgx6f4qahhcg8OrkqhE,1089
462
- omlish/marshal/dataclasses.py,sha256=ZpfNaIdhKwWouWkoQGuequKwrEeehbz9QSQoW3acyPo,7756
463
- omlish/marshal/datetimes.py,sha256=0ffg8cEvx9SMKIXZGD9b7MqpLfmgw0uKKdn6YTfoqok,3714
464
- omlish/marshal/enums.py,sha256=CMAbx6RI2EcQoo7SoD-5q2l-3DFKreWMiOxs6mFpl_4,1472
465
460
  omlish/marshal/exceptions.py,sha256=jwQWn4LcPnadT2KRI_1JJCOSkwWh0yHnYK9BmSkNN4U,302
466
461
  omlish/marshal/factories.py,sha256=Q926jSVjaQLEmStnHLhm_c_vqEysN1LnDCwAsFLIzXw,2970
467
462
  omlish/marshal/forbidden.py,sha256=NDe828hqCQw-AgxcEm8MiDZNxWoBwf3o7sTyvQsSsQ0,867
468
463
  omlish/marshal/global_.py,sha256=K76wB1-pdg4VWgiqR7wyxRNYr-voJApexYW2nV-R4DM,1127
469
- omlish/marshal/helpers.py,sha256=-SOgYJmrURILHpPK6Wu3cCvhj8RJrqfJxuKhh9UMs7o,1102
470
- omlish/marshal/iterables.py,sha256=H9FoCB5RlJW0SVSi3SBD6sxOXN9XRTOUkHRwCYSqRb8,2632
471
- omlish/marshal/literals.py,sha256=m92biF9-PwHGVBx3zG3s2YvklLeOQ7T5IOdgwBJr-NU,1599
472
- omlish/marshal/mappings.py,sha256=XcNOaV708ZHeuIrWiFHC6F1O6U9NyyTKUurvXwIryJo,2789
473
- omlish/marshal/maybes.py,sha256=i-gOQJ-7tdt6sOazAeyCh4N71SK3jWv-BKlkx-fZm-s,2200
474
- omlish/marshal/namedtuples.py,sha256=H0icxcE5FrqgfI9dRc8LlXJy430g_yuILTCVD0Zvfd0,2799
475
464
  omlish/marshal/naming.py,sha256=lIklR_Od4x1ghltAgOzqcKhHs-leeSv2YmFhCHO7GIs,613
476
- omlish/marshal/newtypes.py,sha256=fRpXLoCpoiaqcvl7v92I1_Qt7udn4vsPc1P3UfcBu-8,841
477
465
  omlish/marshal/nop.py,sha256=2mWve_dicFAiUQ2Y5asKkUW-XGmEE9Qi2ClIasFad0c,461
478
- omlish/marshal/numbers.py,sha256=kFRIX9l1yofiYzafV6SnYfEg0PiCsAqeRHOeT6BSxlM,1672
479
- omlish/marshal/objects.py,sha256=74tUmMymimSqgd4a6kyMh_owJe6J7YQXwCXEF-JWt1c,8419
480
- omlish/marshal/optionals.py,sha256=r0XB5rqfasvgZJNrKYd6Unq2U4nHt3JURi26j0dYHlw,1499
481
- omlish/marshal/polymorphism.py,sha256=2SxrfneA9QdhNdxieEGFnHDHpUo3ftETA9dMbCbmbWY,6511
482
- omlish/marshal/primitives.py,sha256=f_6m24Cb-FDGsZpYSas11nLt3xCCEUXugw3Hv4-aNhg,1291
483
466
  omlish/marshal/registries.py,sha256=FvC6qXHCizNB2QmU_N3orxW7iqfGYkiUXYYdTRWS6HA,2353
484
- omlish/marshal/standard.py,sha256=-iA2o674AW1uNVabcA9Dtr6z0gyFS5yLP80nBQ8R5qY,3479
485
- omlish/marshal/unions.py,sha256=tT4W-mxuPi7s_kdl25_AUltsurYPO_0mQl2CiVmNonY,4357
467
+ omlish/marshal/standard.py,sha256=ncaoD_OyCzS5H8bt3WAp5z7k1mWPFeOgAYBVaBLq4Sg,3783
486
468
  omlish/marshal/utils.py,sha256=puKJpwPpuDlMOIrKMcLTRLJyMiL6n_Xs-p59AuDEymA,543
487
- omlish/marshal/uuids.py,sha256=H4B7UX_EPNmP2tC8bubcKrPLTS4aQu98huvbXQ3Zv2g,910
488
469
  omlish/marshal/values.py,sha256=ssHiWdg_L6M17kAn8GiGdPW7UeQOm3RDikWkvwblf5I,263
470
+ omlish/marshal/composite/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
471
+ omlish/marshal/composite/iterables.py,sha256=tOMjJ-nyYBrRnAGAlT2scV3iR9QSic8La-1qFcy9yNk,2642
472
+ omlish/marshal/composite/literals.py,sha256=0fTwQVSQJe9L17grcLq5hMuoYD7vHRFgdHR5-Teq0g8,1608
473
+ omlish/marshal/composite/mappings.py,sha256=92oAqYzzTdRNhFDtmukpJd8anoi3pt2nX5XhLTlM_Dg,2799
474
+ omlish/marshal/composite/maybes.py,sha256=4rxTv769Uk4gQGAnE6urVnMscF1vhcnwqP_lm5QzSoM,2211
475
+ omlish/marshal/composite/newtypes.py,sha256=lYCacdR2BlLWMT1kc8o08UjsmJ6aYlAHkrzG8BozWCM,849
476
+ omlish/marshal/composite/optionals.py,sha256=iQgSrb9Xyb_IP81YREAZ0xKYXImLgMILGLBnYL2lFWw,1508
477
+ omlish/marshal/objects/__init__.py,sha256=F4wej8L_tedC8ETYxAnmKfdPR9TjsqIus9Z3nZofYuc,182
478
+ omlish/marshal/objects/dataclasses.py,sha256=Fo15maLrWICq4H3YlZpa0PjnJTC4eqG1IF0C-88qCKs,7780
479
+ omlish/marshal/objects/helpers.py,sha256=85GZp4h3Yo0GYGmnZpKgNxkWnSk8h2R21nfDLU2DtM0,1110
480
+ omlish/marshal/objects/marshal.py,sha256=rdZsDWKgLBZxV0ZQlwHTJv9iUg0lC57trJHBOFKvuLo,2636
481
+ omlish/marshal/objects/metadata.py,sha256=QVD7DRhXbLda_Edgpc3OD1xT9fthmeaaj6l_nTE1PMM,3307
482
+ omlish/marshal/objects/namedtuples.py,sha256=ENWyiYZhTwDRqUkkWrHeNcoHGEo5GW634jMuBUc3654,2815
483
+ omlish/marshal/objects/unmarshal.py,sha256=-83sSgL6WX6C3JfXZr64ZLYi3SsJC9kyiGAbEQbVHQI,3620
484
+ omlish/marshal/polymorphism/__init__.py,sha256=e2UTrSL0qp7w_1vkdxDWd7sXlWhep2KPV49-BB64ma8,130
485
+ omlish/marshal/polymorphism/marshal.py,sha256=Lraih0Dhkcwu6Bb6QkrYOWoMIubh46VQkXxJQWisA8Y,1827
486
+ omlish/marshal/polymorphism/metadata.py,sha256=hbXqkYKXhfJeMllzI0Ubeeqbq201khVN8uprgVhMpHM,3046
487
+ omlish/marshal/polymorphism/unions.py,sha256=YwsK9T3okGiHj88LTFNdUvuH7VkCsD-aTnZseKzhpdA,4350
488
+ omlish/marshal/polymorphism/unmarshal.py,sha256=gdWTgpl4hXBqac1gHmg_23VMb7x42CE2x-3oRpCaLwU,2047
489
+ omlish/marshal/singular/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
490
+ omlish/marshal/singular/any.py,sha256=42XmUbX_AaiHGFwS2QmA-huPCcZ1_jzVyrnBUYVm21U,787
491
+ omlish/marshal/singular/base64.py,sha256=gQIkFN60lNEuSiu3MDQFoHwMZTtzDbrBRtNpFZ2HXew,1098
492
+ omlish/marshal/singular/datetimes.py,sha256=1PDVFF6TGkGxGUno8TaFGRof0DQUookYf_X2Nl8T4V0,3723
493
+ omlish/marshal/singular/enums.py,sha256=0FSRj8fiM9LrRrFtlWrMsjG-ualfirGNSP0H-36J4sA,1481
494
+ omlish/marshal/singular/numbers.py,sha256=12a8HxjDHMTgtJTxO7VY_h5llaPyYB-QEPY09dUFOec,1680
495
+ omlish/marshal/singular/primitives.py,sha256=EZi2AIi_Onw1pekAiL4ujz4w-ASuOGWCu4MUIE_dCnk,1299
496
+ omlish/marshal/singular/uuids.py,sha256=rZoE6NE5z6x_ZRmVMjjR2iK7CR8ijfDOvhMKgmm8Mgk,918
489
497
  omlish/math/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
490
498
  omlish/math/bits.py,sha256=yip1l8agOYzT7bFyMGc0RR3XlnGCfHMpjw_SECLLh1I,3477
491
499
  omlish/math/floats.py,sha256=UimhOT7KRl8LXTzOI5cQWoX_9h6WNWe_3vcOuO7-h_8,327
@@ -495,18 +503,20 @@ omlish/multiprocessing/proxies.py,sha256=bInhGds2rv6xT9q3qRMlZuSXFAjwfspkiohXZ36
495
503
  omlish/multiprocessing/spawn.py,sha256=sTvPLIJGYnjjI6ASqhFzHF-97tCnaOXX7u7s-33SUMw,1875
496
504
  omlish/os/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
497
505
  omlish/os/atomics.py,sha256=KhWNeh4mzU3M-TF0v8uR6hUqMfZJW42MeyIK9Jl6R0k,5246
498
- omlish/os/death.py,sha256=_JV88yxwYIalamIMuqmGTQ4KYd0t-UHLjVkdoliPWL8,2943
506
+ omlish/os/death.py,sha256=kxcAWw91zvvWT5qxXbKVg-YEOJXxx658VCdkCTNPTag,4825
499
507
  omlish/os/deathsig.py,sha256=hk9Yq2kyDdI-cI7OQH7mOfpRbOKzY_TfPKEqgrjVYbA,641
500
- omlish/os/fcntl.py,sha256=hSlCqzMu5iqEsxlp9me6KtoG9FK7g3sdjZIpDba-kLQ,1458
501
- omlish/os/files.py,sha256=O1Um1iCLeIzDSKQq2zByVC_4NZ3tLMqv6vICyU21U3Q,861
508
+ omlish/os/fcntl.py,sha256=riQf9iEEEIC28lJp8ud06MU56w2XJHJ9nBFtck_hdhc,1501
509
+ omlish/os/files.py,sha256=WJ_42vsZIZukQURN3TTccp-n74ZNhbux_ps3TLbHj18,1106
510
+ omlish/os/forkhooks.py,sha256=PbcMrPF_7D0QBm73e55I_XIk4yQzsdj-L6rpe_eyAFM,5024
502
511
  omlish/os/journald.py,sha256=2nI8Res1poXkbLc31--MPUlzYMESnCcPUkIxDOCjZW0,3903
503
512
  omlish/os/linux.py,sha256=whJ6scwMKSFBdXiVhJW0BCpJV4jOGMr-a_a3Bhwz6Ls,18938
504
513
  omlish/os/paths.py,sha256=hqPiyg_eYaRoIVPdAeX4oeLEV4Kpln_XsH0tHvbOf8Q,844
505
514
  omlish/os/sizes.py,sha256=ohkALLvqSqBX4iR-7DMKJ4pfOCRdZXV8htH4QywUNM0,152
506
515
  omlish/os/temp.py,sha256=P97KiVeNB7rfGn4tlgU5ro86JUxAsiphLMlxsjQgfB0,1198
507
516
  omlish/os/pidfiles/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
508
- omlish/os/pidfiles/manager.py,sha256=ssnxCvSoL3OapzcMmxSgiy9o1NogR6PTX4LLTJXuPkM,2830
509
- omlish/os/pidfiles/pidfile.py,sha256=833aPCV7cQqFqYnxwma8np0eoy0CJzVHRskn-YSQwis,3378
517
+ omlish/os/pidfiles/manager.py,sha256=XP_0ynjWDG2wjRN3sIKjmFafpf-er3AYm8E7aXs16fA,3209
518
+ omlish/os/pidfiles/pidfile.py,sha256=WmZt_c8fvztPgZQnYHhcQCKWgHqAEsaI3Ggz6Wqgkc8,3748
519
+ omlish/os/pidfiles/pinning.py,sha256=_AwYjJc1UGX7mdCOk4mItJJcsOJo3RW2ebBOm2noW5Y,6359
510
520
  omlish/reflect/__init__.py,sha256=JBWwxKwP4IEaomkK0PTju02STU1BVXT14SCrShT1Sm0,769
511
521
  omlish/reflect/inspect.py,sha256=veJ424-9oZrqyvhVpvxOi7hcKW-PDBkdYL2yjrFlk4o,495
512
522
  omlish/reflect/ops.py,sha256=RJ6jzrM4ieFsXzWyNXWV43O_WgzEaUvlHSc5N2ezW2A,2044
@@ -525,7 +535,7 @@ omlish/secrets/subprocesses.py,sha256=ffjfbgPbEE_Pwb_87vG4yYR2CGZy3I31mHNCo_0JtH
525
535
  omlish/secrets/tempssl.py,sha256=tlwRrbHHvgKJtNAC31I5sDKryya4fagqN6kGt-tV4Qg,1874
526
536
  omlish/sockets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
527
537
  omlish/sockets/addresses.py,sha256=vbVeQBkzI513H4vRv-JS89QtRbr9U8v5zqkm3oODl_s,1869
528
- omlish/sockets/bind.py,sha256=TnG5nm0pnuMxRA02TG2W40RbutrPA6tkOJtbZvBjDWU,8063
538
+ omlish/sockets/bind.py,sha256=uRHZJvBxWXadd3Qt7deDEJ1rWzjC-lVodRgPA6VMwNU,8025
529
539
  omlish/sockets/handlers.py,sha256=Gj6xZoo4vommge8XvkehYw3B7O4aql2P4qzZIIa0p24,462
530
540
  omlish/sockets/io.py,sha256=lfhTkB7NnAIx9kuQhAkwgsEUXY78Mp1_WtYrIQNS_k8,1408
531
541
  omlish/sockets/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -679,9 +689,9 @@ omlish/text/indent.py,sha256=YjtJEBYWuk8--b9JU_T6q4yxV85_TR7VEVr5ViRCFwk,1336
679
689
  omlish/text/minja.py,sha256=jZC-fp3Xuhx48ppqsf2Sf1pHbC0t8XBB7UpUUoOk2Qw,5751
680
690
  omlish/text/parts.py,sha256=7vPF1aTZdvLVYJ4EwBZVzRSy8XB3YqPd7JwEnNGGAOo,6495
681
691
  omlish/text/random.py,sha256=jNWpqiaKjKyTdMXC-pWAsSC10AAP-cmRRPVhm59ZWLk,194
682
- omlish-0.0.0.dev226.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
683
- omlish-0.0.0.dev226.dist-info/METADATA,sha256=0HcF368bfjlzkGzprdbRX4GJagL5c9PDPRUqiBYWIlY,4176
684
- omlish-0.0.0.dev226.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
685
- omlish-0.0.0.dev226.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
686
- omlish-0.0.0.dev226.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
687
- omlish-0.0.0.dev226.dist-info/RECORD,,
692
+ omlish-0.0.0.dev228.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
693
+ omlish-0.0.0.dev228.dist-info/METADATA,sha256=-HhLcpKh_NMYQIcIENf1Dyen3kQU2vxd2nAe_weG7wk,4176
694
+ omlish-0.0.0.dev228.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
695
+ omlish-0.0.0.dev228.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
696
+ omlish-0.0.0.dev228.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
697
+ omlish-0.0.0.dev228.dist-info/RECORD,,