omlish 0.0.0.dev231__py3-none-any.whl → 0.0.0.dev233__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.
omlish/.manifests.json CHANGED
@@ -307,6 +307,18 @@
307
307
  }
308
308
  }
309
309
  },
310
+ {
311
+ "module": ".os.pidfiles.__main__",
312
+ "attr": "_CLI_MODULE",
313
+ "file": "omlish/os/pidfiles/__main__.py",
314
+ "line": 1,
315
+ "value": {
316
+ "$omdev.cli.types.CliModule": {
317
+ "cmd_name": "pidfiles",
318
+ "mod_name": "omlish.os.pidfiles.__main__"
319
+ }
320
+ }
321
+ },
310
322
  {
311
323
  "module": ".secrets.pwgen",
312
324
  "attr": "_CLI_MODULE",
omlish/__about__.py CHANGED
@@ -1,5 +1,5 @@
1
- __version__ = '0.0.0.dev231'
2
- __revision__ = '2eb4140ac802af2814bc4b4d5a8d37613083ae32'
1
+ __version__ = '0.0.0.dev233'
2
+ __revision__ = '104fc39d3a0d5ea92881a45333cbcb1810f6b7ff'
3
3
 
4
4
 
5
5
  #
@@ -37,7 +37,7 @@ class Project(ProjectBase):
37
37
 
38
38
  'greenlet ~= 3.1',
39
39
 
40
- 'trio ~= 0.27',
40
+ 'trio ~= 0.29',
41
41
  'trio-asyncio ~= 0.15',
42
42
  ],
43
43
 
@@ -56,7 +56,7 @@ class Project(ProjectBase):
56
56
  'asttokens ~= 3.0',
57
57
  'executing ~= 2.2',
58
58
 
59
- 'psutil ~= 6.0',
59
+ 'psutil ~= 7.0',
60
60
  ],
61
61
 
62
62
  'formats': [
omlish/codecs/registry.py CHANGED
@@ -105,7 +105,7 @@ def _install_standard_codecs(registry: CodecRegistry) -> None:
105
105
  @cached.function
106
106
  def _build_manifest_lazy_loaded_codecs() -> ta.Sequence[LazyLoadedCodec]:
107
107
  ldr = manifest_load.MANIFEST_LOADER
108
- pkgs = {__package__.split('.')[0], *ldr.discover()}
108
+ pkgs = {__package__.split('.')[0], *ldr.discover_pkgs()}
109
109
  mns = ldr.load(*pkgs, only=[LazyLoadedCodec])
110
110
  return [m.value for m in mns]
111
111
 
omlish/daemons/daemon.py CHANGED
@@ -15,28 +15,17 @@ TODO:
15
15
  - timebomb
16
16
  - pickle protocol, revision / venv check, multiprocessing manager support
17
17
  """
18
- import contextlib
19
- import functools
20
18
  import logging
21
19
  import os.path
22
- import threading
23
20
  import time
24
- import typing as ta
25
21
 
26
22
  from .. import check
27
23
  from .. import dataclasses as dc
28
24
  from .. import lang
29
- from ..os.pidfiles.manager import _PidfileManager # noqa
30
- from ..os.pidfiles.manager import open_inheritable_pidfile
31
25
  from ..os.pidfiles.pidfile import Pidfile
32
- from .reparent import reparent_process
33
- from .spawning import InProcessSpawner
34
- from .spawning import Spawn
35
- from .spawning import Spawner
26
+ from .launching import Launcher
36
27
  from .spawning import Spawning
37
- from .spawning import spawner_for
38
28
  from .targets import Target
39
- from .targets import target_runner_for
40
29
  from .waiting import Wait
41
30
  from .waiting import waiter_for
42
31
 
@@ -55,19 +44,20 @@ class Daemon:
55
44
 
56
45
  #
57
46
 
58
- reparent_process: bool = False
59
-
60
47
  pid_file: str | None = None
61
48
 
62
49
  #
63
50
 
51
+ reparent_process: bool = False
52
+ launched_timeout_s: float = 5.
53
+
54
+ #
55
+
64
56
  wait: Wait | None = None
65
57
 
66
58
  wait_timeout: lang.TimeoutLike = 10.
67
59
  wait_sleep_s: float = .1
68
60
 
69
- launched_timeout_s: float = 5.
70
-
71
61
  #
72
62
 
73
63
  def __post_init__(self) -> None:
@@ -106,79 +96,6 @@ class Daemon:
106
96
 
107
97
  #
108
98
 
109
- def _inner_launch(
110
- self,
111
- *,
112
- pidfile_manager: ta.ContextManager | None,
113
- launched_callback: ta.Callable[[], None] | None = None,
114
- ) -> None:
115
- try:
116
- if self._config.reparent_process:
117
- log.info('Reparenting')
118
- reparent_process()
119
-
120
- with contextlib.ExitStack() as es:
121
- pidfile: Pidfile | None = None # noqa
122
- if pidfile_manager is not None:
123
- pidfile = check.isinstance(es.enter_context(pidfile_manager), Pidfile)
124
- pidfile.write()
125
-
126
- if launched_callback is not None:
127
- launched_callback()
128
-
129
- runner = target_runner_for(self._config.target)
130
- runner.run()
131
-
132
- finally:
133
- if launched_callback is not None:
134
- launched_callback()
135
-
136
- def launch_no_wait(self) -> bool:
137
- with contextlib.ExitStack() as es:
138
- spawner: Spawner = es.enter_context(spawner_for(self._config.spawning))
139
-
140
- #
141
-
142
- inherit_fds: set[int] = set()
143
- launched_event: threading.Event | None = None
144
-
145
- pidfile: Pidfile | None = None # noqa
146
- pidfile_manager: ta.ContextManager | None = None
147
-
148
- if (pid_file := self._config.pid_file) is not None:
149
- if not isinstance(spawner, InProcessSpawner):
150
- pidfile = es.enter_context(open_inheritable_pidfile(pid_file))
151
- pidfile_manager = lang.NopContextManager(pidfile)
152
-
153
- else:
154
- check.state(not self._config.reparent_process)
155
- pidfile = es.enter_context(Pidfile(pid_file))
156
- pidfile_manager = pidfile.dup()
157
- launched_event = threading.Event()
158
-
159
- if not pidfile.try_acquire_lock():
160
- return False
161
-
162
- inherit_fds.add(check.isinstance(pidfile.fileno(), int))
163
-
164
- #
165
-
166
- spawner.spawn(Spawn(
167
- functools.partial(
168
- self._inner_launch,
169
- pidfile_manager=pidfile_manager,
170
- launched_callback=launched_event.set if launched_event is not None else None,
171
- ),
172
- inherit_fds=inherit_fds,
173
- ))
174
-
175
- if launched_event is not None:
176
- check.state(launched_event.wait(timeout=self._config.launched_timeout_s))
177
-
178
- return True
179
-
180
- #
181
-
182
99
  def wait_sync(self, timeout: lang.TimeoutLike = lang.Timeout.Default) -> None:
183
100
  if self._config.wait is None:
184
101
  return
@@ -191,8 +108,17 @@ class Daemon:
191
108
 
192
109
  #
193
110
 
194
- class _NOT_SET(lang.Marker): # noqa
195
- pass
111
+ def launch_no_wait(self) -> None:
112
+ launcher = Launcher(
113
+ target=self._config.target,
114
+ spawning=self._config.spawning,
115
+
116
+ pid_file=self._config.pid_file,
117
+ reparent_process=self._config.reparent_process,
118
+ launched_timeout_s=self._config.launched_timeout_s,
119
+ )
120
+
121
+ launcher.launch()
196
122
 
197
123
  def launch(self, timeout: lang.TimeoutLike = lang.Timeout.Default) -> None:
198
124
  self.launch_no_wait()
@@ -0,0 +1,121 @@
1
+ """
2
+ TODO:
3
+ - Config? dedupe defaults with Daemon
4
+ - ExitStacked? hold ref to Spawner, which holds refs to thread/proc - which will likely outlive it, but still
5
+ """
6
+ import contextlib
7
+ import functools
8
+ import logging
9
+ import threading
10
+ import typing as ta
11
+
12
+ from .. import check
13
+ from .. import lang
14
+ from ..os.pidfiles.manager import open_inheritable_pidfile
15
+ from ..os.pidfiles.pidfile import Pidfile
16
+ from .reparent import reparent_process
17
+ from .spawning import InProcessSpawner
18
+ from .spawning import Spawn
19
+ from .spawning import Spawner
20
+ from .spawning import Spawning
21
+ from .spawning import spawner_for
22
+ from .targets import Target
23
+ from .targets import target_runner_for
24
+
25
+
26
+ log = logging.getLogger(__name__)
27
+
28
+
29
+ ##
30
+
31
+
32
+ class Launcher:
33
+ def __init__(
34
+ self,
35
+ *,
36
+ target: Target,
37
+ spawning: Spawning,
38
+
39
+ pid_file: str | None = None,
40
+ reparent_process: bool = False, # noqa
41
+ launched_timeout_s: float = 5.,
42
+ ) -> None:
43
+ super().__init__()
44
+
45
+ self._target = target
46
+ self._spawning = spawning
47
+
48
+ self._pid_file = pid_file
49
+ self._reparent_process = reparent_process
50
+ self._launched_timeout_s = launched_timeout_s
51
+
52
+ def _inner_launch(
53
+ self,
54
+ *,
55
+ pidfile_manager: ta.ContextManager | None,
56
+ launched_callback: ta.Callable[[], None] | None = None,
57
+ ) -> None:
58
+ try:
59
+ if self._reparent_process:
60
+ log.info('Reparenting')
61
+ reparent_process()
62
+
63
+ with contextlib.ExitStack() as es:
64
+ pidfile: Pidfile | None = None # noqa
65
+ if pidfile_manager is not None:
66
+ pidfile = check.isinstance(es.enter_context(pidfile_manager), Pidfile)
67
+ pidfile.write()
68
+
69
+ if launched_callback is not None:
70
+ launched_callback()
71
+
72
+ runner = target_runner_for(self._target)
73
+ runner.run()
74
+
75
+ finally:
76
+ if launched_callback is not None:
77
+ launched_callback()
78
+
79
+ def launch(self) -> bool:
80
+ with contextlib.ExitStack() as es:
81
+ spawner: Spawner = es.enter_context(spawner_for(self._spawning))
82
+
83
+ #
84
+
85
+ inherit_fds: set[int] = set()
86
+ launched_event: threading.Event | None = None
87
+
88
+ pidfile: Pidfile | None = None # noqa
89
+ pidfile_manager: ta.ContextManager | None = None
90
+
91
+ if (pid_file := self._pid_file) is not None:
92
+ if not isinstance(spawner, InProcessSpawner):
93
+ pidfile = es.enter_context(open_inheritable_pidfile(pid_file))
94
+ pidfile_manager = lang.NopContextManager(pidfile)
95
+
96
+ else:
97
+ check.state(not self._reparent_process)
98
+ pidfile = es.enter_context(Pidfile(pid_file))
99
+ pidfile_manager = pidfile.dup()
100
+ launched_event = threading.Event()
101
+
102
+ if not pidfile.try_acquire_lock():
103
+ return False
104
+
105
+ inherit_fds.add(check.isinstance(pidfile.fileno(), int))
106
+
107
+ #
108
+
109
+ spawner.spawn(Spawn(
110
+ functools.partial(
111
+ self._inner_launch,
112
+ pidfile_manager=pidfile_manager,
113
+ launched_callback=launched_event.set if launched_event is not None else None,
114
+ ),
115
+ inherit_fds=inherit_fds,
116
+ ))
117
+
118
+ if launched_event is not None:
119
+ check.state(launched_event.wait(timeout=self._launched_timeout_s))
120
+
121
+ return True
omlish/lang/functions.py CHANGED
@@ -190,6 +190,16 @@ class Args:
190
190
  self.args = args
191
191
  self.kwargs = kwargs
192
192
 
193
+ def update(self, *args: ta.Any, **kwargs: ta.Any) -> 'Args':
194
+ return Args(
195
+ *self.args,
196
+ *args,
197
+ **{
198
+ **self.kwargs,
199
+ **kwargs,
200
+ },
201
+ )
202
+
193
203
  def __call__(self, fn: ta.Callable[..., T]) -> T:
194
204
  return fn(*self.args, **self.kwargs)
195
205
 
omlish/manifests/load.py CHANGED
@@ -9,6 +9,7 @@ import dataclasses as dc
9
9
  import importlib.machinery
10
10
  import importlib.resources
11
11
  import json
12
+ import os.path
12
13
  import threading
13
14
  import typing as ta
14
15
 
@@ -193,7 +194,7 @@ class ManifestLoader:
193
194
 
194
195
  ENTRY_POINT_GROUP = 'omlish.manifests'
195
196
 
196
- def discover(self) -> ta.Sequence[str]:
197
+ def discover_pkgs(self) -> ta.Sequence[str]:
197
198
  # This is a fat dep so do it late.
198
199
  import importlib.metadata
199
200
 
@@ -202,6 +203,35 @@ class ManifestLoader:
202
203
  for ep in importlib.metadata.entry_points(group=self.ENTRY_POINT_GROUP)
203
204
  ]
204
205
 
206
+ def scan_pkg_root(self, root: str) -> ta.Sequence[str]:
207
+ pkgs: ta.List[str] = []
208
+ for n in os.listdir(root):
209
+ if os.path.isdir(p := os.path.join(root, n)) and os.path.exists(os.path.join(p, '__init__.py')):
210
+ pkgs.append(n)
211
+ return pkgs
212
+
213
+ def scan_or_discover_pkgs(
214
+ self,
215
+ *,
216
+ specified_roots: ta.Optional[ta.Sequence[str]] = None,
217
+ fallback_root: ta.Optional[str] = None,
218
+ ) -> ta.Sequence[str]:
219
+ pkgs: list[str] = []
220
+
221
+ if specified_roots is not None:
222
+ if isinstance(specified_roots, str):
223
+ raise TypeError(specified_roots)
224
+ for r in specified_roots:
225
+ pkgs.extend(self.scan_pkg_root(r))
226
+
227
+ else:
228
+ pkgs.extend(self.discover_pkgs())
229
+
230
+ if not pkgs and fallback_root is not None:
231
+ pkgs.extend(self.scan_pkg_root(fallback_root))
232
+
233
+ return pkgs
234
+
205
235
 
206
236
  ##
207
237
 
@@ -0,0 +1,11 @@
1
+ # @omlish-manifest
2
+ _CLI_MODULE = {'$omdev.cli.types.CliModule': {
3
+ 'cmd_name': 'pidfiles',
4
+ 'mod_name': __name__,
5
+ }}
6
+
7
+
8
+ if __name__ == '__main__':
9
+ from .cli import _main # noqa
10
+
11
+ _main()
@@ -0,0 +1,88 @@
1
+ """
2
+ TODO:
3
+ - F_SETLK mode
4
+ """
5
+ import os
6
+ import typing as ta
7
+
8
+ from ... import lang
9
+ from ...argparse import all as ap
10
+ from ..pidfiles.pidfile import Pidfile
11
+ from ..pidfiles.pinning import PidfilePinner
12
+ from ..signals import parse_signal
13
+
14
+
15
+ class Cli(ap.Cli):
16
+ _PIDFILE_ARGS: ta.ClassVar[ta.Sequence[ap.Arg]] = [
17
+ ap.arg('pid-file'),
18
+ ap.arg('--create', action='store_true'),
19
+ ]
20
+
21
+ def _pidfile_args(self) -> lang.Args:
22
+ return lang.Args(
23
+ self.args.pid_file,
24
+ inheritable=False,
25
+ no_create=not self._args.create,
26
+ )
27
+
28
+ def _args_pidfile(self) -> Pidfile:
29
+ return self._pidfile_args()(Pidfile)
30
+
31
+ #
32
+
33
+ @ap.cmd(*_PIDFILE_ARGS)
34
+ def read_no_verify(self) -> None:
35
+ with self._args_pidfile() as pidfile:
36
+ print(pidfile.read())
37
+
38
+ @ap.cmd(*_PIDFILE_ARGS)
39
+ def lock(self) -> None:
40
+ with self._args_pidfile() as pidfile:
41
+ pidfile.acquire_lock()
42
+ print(os.getpid())
43
+ input()
44
+
45
+ #
46
+
47
+ _PIDFILE_PINNER_ARGS: ta.ClassVar[ta.Sequence[ap.Arg]] = [
48
+ *_PIDFILE_ARGS,
49
+ ap.arg('--timeout', type=float),
50
+ ]
51
+
52
+ def _pidfile_pinner_args(self) -> lang.Args:
53
+ return self._pidfile_args().update(
54
+ timeout=self._args.timeout,
55
+ )
56
+
57
+ def _args_pidfile_pinner(self) -> ta.ContextManager[int]:
58
+ return self._pidfile_pinner_args()(PidfilePinner.default_impl()().pin_pidfile_owner)
59
+
60
+ #
61
+
62
+ @ap.cmd(*_PIDFILE_PINNER_ARGS)
63
+ def read(self) -> None:
64
+ with self._args_pidfile_pinner() as pid:
65
+ print(pid)
66
+
67
+ @ap.cmd(*_PIDFILE_PINNER_ARGS)
68
+ def pin(self) -> None:
69
+ with self._args_pidfile_pinner() as pid:
70
+ print(pid)
71
+ input()
72
+
73
+ @ap.cmd(
74
+ *_PIDFILE_PINNER_ARGS,
75
+ ap.arg('signal'),
76
+ )
77
+ def kill(self) -> None:
78
+ sig = parse_signal(self._args.signal)
79
+ with self._args_pidfile_pinner() as pid:
80
+ os.kill(pid, sig)
81
+
82
+
83
+ def _main() -> None:
84
+ Cli().cli_run_and_exit()
85
+
86
+
87
+ if __name__ == '__main__':
88
+ _main()
@@ -27,11 +27,13 @@ class Pidfile:
27
27
  path: str,
28
28
  *,
29
29
  inheritable: bool = True,
30
+ no_create: bool = False,
30
31
  ) -> None:
31
32
  super().__init__()
32
33
 
33
34
  self._path = path
34
35
  self._inheritable = inheritable
36
+ self._no_create = no_create
35
37
 
36
38
  @property
37
39
  def path(self) -> str:
@@ -74,7 +76,10 @@ class Pidfile:
74
76
  fd = os.dup(self._fd_to_dup)
75
77
  del self._fd_to_dup
76
78
  else:
77
- fd = os.open(self._path, os.O_RDWR | os.O_CREAT, 0o600)
79
+ ofl = os.O_RDWR
80
+ if not self._no_create:
81
+ ofl |= os.O_CREAT
82
+ fd = os.open(self._path, ofl, 0o600)
78
83
 
79
84
  try:
80
85
  if self._inheritable:
@@ -27,6 +27,7 @@ import typing as ta
27
27
 
28
28
  from ...diag.lslocks import LslocksCommand
29
29
  from ...diag.lsof import LsofCommand
30
+ from ...lite.check import check
30
31
  from ...lite.timeouts import Timeout
31
32
  from ...lite.timeouts import TimeoutLike
32
33
  from ...subprocesses.sync import subprocesses # noqa
@@ -64,13 +65,21 @@ class PidfilePinner(abc.ABC):
64
65
  path: str,
65
66
  *,
66
67
  timeout: ta.Optional[TimeoutLike] = None,
68
+ inheritable: bool = False, # Present to match Pidfile kwargs for convenience, but enforced to be False.
69
+ **kwargs: ta.Any,
67
70
  ) -> ta.Iterator[int]:
71
+ check.arg(not inheritable)
72
+
68
73
  timeout = Timeout.of(timeout)
69
74
 
70
75
  if not os.path.isfile(path):
71
76
  raise self.NoOwnerError
72
77
 
73
- with Pidfile(path, inheritable=False) as pf:
78
+ with Pidfile(
79
+ path,
80
+ inheritable=False,
81
+ **kwargs,
82
+ ) as pf:
74
83
  try:
75
84
  with self._pin_pidfile_owner(pf, timeout) as pid:
76
85
  yield pid
omlish/os/signals.py ADDED
@@ -0,0 +1,15 @@
1
+ # ruff: noqa: UP006 UP007
2
+ # @omlish-lite
3
+ import signal
4
+
5
+
6
+ def parse_signal(s: str) -> int:
7
+ try:
8
+ return int(s)
9
+ except ValueError:
10
+ pass
11
+
12
+ s = s.upper()
13
+ if not s.startswith('SIG'):
14
+ s = 'SIG' + s
15
+ return signal.Signals[s] # noqa
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: omlish
3
- Version: 0.0.0.dev231
3
+ Version: 0.0.0.dev233
4
4
  Summary: omlish
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -16,7 +16,7 @@ Provides-Extra: all
16
16
  Requires-Dist: anyio~=4.8; extra == "all"
17
17
  Requires-Dist: sniffio~=1.3; extra == "all"
18
18
  Requires-Dist: greenlet~=3.1; extra == "all"
19
- Requires-Dist: trio~=0.27; extra == "all"
19
+ Requires-Dist: trio~=0.29; extra == "all"
20
20
  Requires-Dist: trio-asyncio~=0.15; extra == "all"
21
21
  Requires-Dist: lz4~=4.4; extra == "all"
22
22
  Requires-Dist: python-snappy~=0.7; extra == "all"
@@ -24,7 +24,7 @@ Requires-Dist: zstandard~=0.23; extra == "all"
24
24
  Requires-Dist: brotli~=1.1; extra == "all"
25
25
  Requires-Dist: asttokens~=3.0; extra == "all"
26
26
  Requires-Dist: executing~=2.2; extra == "all"
27
- Requires-Dist: psutil~=6.0; extra == "all"
27
+ Requires-Dist: psutil~=7.0; extra == "all"
28
28
  Requires-Dist: orjson~=3.10; extra == "all"
29
29
  Requires-Dist: ujson~=5.10; extra == "all"
30
30
  Requires-Dist: pyyaml~=6.0; extra == "all"
@@ -54,7 +54,7 @@ Provides-Extra: async
54
54
  Requires-Dist: anyio~=4.8; extra == "async"
55
55
  Requires-Dist: sniffio~=1.3; extra == "async"
56
56
  Requires-Dist: greenlet~=3.1; extra == "async"
57
- Requires-Dist: trio~=0.27; extra == "async"
57
+ Requires-Dist: trio~=0.29; extra == "async"
58
58
  Requires-Dist: trio-asyncio~=0.15; extra == "async"
59
59
  Provides-Extra: compress
60
60
  Requires-Dist: lz4~=4.4; extra == "compress"
@@ -64,7 +64,7 @@ Requires-Dist: brotli~=1.1; extra == "compress"
64
64
  Provides-Extra: diag
65
65
  Requires-Dist: asttokens~=3.0; extra == "diag"
66
66
  Requires-Dist: executing~=2.2; extra == "diag"
67
- Requires-Dist: psutil~=6.0; extra == "diag"
67
+ Requires-Dist: psutil~=7.0; extra == "diag"
68
68
  Provides-Extra: formats
69
69
  Requires-Dist: orjson~=3.10; extra == "formats"
70
70
  Requires-Dist: ujson~=5.10; extra == "formats"
@@ -1,5 +1,5 @@
1
- omlish/.manifests.json,sha256=YGmAnUBszmosQQ_7Hh2wwtDiYdYZ4unNKYzOtALuels,7968
2
- omlish/__about__.py,sha256=ZBkJyvFWxZFNvvD7zkGGThXCoE7JjItJdlIadSjnLho,3380
1
+ omlish/.manifests.json,sha256=vQTAIvR8OblSq-uP2GUfnbei0RnmAnM5j0T1-OToh9E,8253
2
+ omlish/__about__.py,sha256=hETL5TQrI5YAv_0oaMECavt9Vu8jjHjGR0tqTGZ353U,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
@@ -131,7 +131,7 @@ omlish/codecs/base.py,sha256=uFrDvP7SZdeBbpuUzGHvyOdFNAmhjkBG2cVaVydRsjw,2221
131
131
  omlish/codecs/bytes.py,sha256=jlZ87OmZ52HhQDNyL87R3OIviK2qV5iU2jZYOTOLWjk,2157
132
132
  omlish/codecs/chain.py,sha256=DrBi5vbaFfObfoppo6alwOmyW2XbrH2051cjExwr2Gs,527
133
133
  omlish/codecs/funcs.py,sha256=p4imNt7TobyZVXWC-WhntHVu9KfJrO4QwdtPRh-cVOk,850
134
- omlish/codecs/registry.py,sha256=Ald3fs707cJsUovYjNmxdT2zAQworvDxwMFk7DBT8r0,3995
134
+ omlish/codecs/registry.py,sha256=yDkDpRJXD7owFCa4b0R4MMf3Le6KxknNBewjSrehepw,4000
135
135
  omlish/codecs/standard.py,sha256=eiZ4u9ep0XrA4Z_D1zJI0vmWyuN8HLrX4Se_r_Cq_ZM,60
136
136
  omlish/codecs/text.py,sha256=JzrdwMpQPo2NBBg3K1EZszzQy5vEWmd82SIerJd4yeQ,5723
137
137
  omlish/collections/__init__.py,sha256=ddzZS3C2rvDo65hspO9KlFsrinElxPWvYEgVyBUZdb0,2164
@@ -176,7 +176,8 @@ omlish/configs/processing/names.py,sha256=weHmaTclzgM9lUn3aBtw-kwZ3mc2N-CZlFg3Kd
176
176
  omlish/configs/processing/rewriting.py,sha256=v7PfHtuTn5v_5Y6Au7oMN2Z0nxAMy1iYyO5CXnTvZhs,4226
177
177
  omlish/configs/processing/strings.py,sha256=qFS2oh6z02IaM_q4lTKLdufzkJqAJ6J-Qjrz5S-QJoM,826
178
178
  omlish/daemons/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
179
- omlish/daemons/daemon.py,sha256=rK5T_ZbQPwwF-yLgS03fmJ0cZsVGSjTF5M4xSq_YiM0,5534
179
+ omlish/daemons/daemon.py,sha256=lnMgGrPeZ3pjhuXPU-7DX2XGEdNG0kP6HAejCQPSGtk,2976
180
+ omlish/daemons/launching.py,sha256=mhtkuAO16STcznUl3rrX9pacfrKbPQRCP2AllKL4B70,3664
180
181
  omlish/daemons/reparent.py,sha256=UaG2X6VJHJPOlUwHPNRH3aWGgF0Fg771jjO9IRPLlyY,280
181
182
  omlish/daemons/spawning.py,sha256=cx00xeqSrfhlFbjCtKqaBHvMuHwB9hdjuKNHzAAo_dw,4030
182
183
  omlish/daemons/targets.py,sha256=scq6BYgzi0H2apfgD74U0D8_msQuYAel3Qiij74YWVo,1501
@@ -399,7 +400,7 @@ omlish/lang/contextmanagers.py,sha256=Mrn8NJ3pP0Zxi-IoGqSjZDdWUctsyee2vrZ2FtZvNm
399
400
  omlish/lang/datetimes.py,sha256=ehI_DhQRM-bDxAavnp470XcekbbXc4Gdw9y1KpHDJT0,223
400
401
  omlish/lang/descriptors.py,sha256=njkYDS1gn5p4-3v1jr-s_srauC7tvvt571RjE7Q4LXE,6616
401
402
  omlish/lang/exceptions.py,sha256=qJBo3NU1mOWWm-NhQUHCY5feYXR3arZVyEHinLsmRH4,47
402
- omlish/lang/functions.py,sha256=t9nsnWwhsibG0w908VMx-_pRM5tZfruE3faPxrCWTbI,4160
403
+ omlish/lang/functions.py,sha256=0ql9EXA_gEEhvUVzMJCjVhEnVtHecsLKmfmAXuQqeGY,4388
403
404
  omlish/lang/generators.py,sha256=5LX17j-Ej3QXhwBgZvRTm_dq3n9veC4IOUcVmvSu2vU,5243
404
405
  omlish/lang/imports.py,sha256=FMPz1lIDmuoapM88uabXeZbeJX1uCT8pkHeukC3X4qc,10129
405
406
  omlish/lang/iterables.py,sha256=HOjcxOwyI5bBApDLsxRAGGhTTmw7fdZl2kEckxRVl-0,1994
@@ -460,7 +461,7 @@ omlish/logs/standard.py,sha256=FbKdF2Z4Na5i2TNwKn0avLJXyICe2JKsPufjvKCHGn0,3162
460
461
  omlish/logs/timing.py,sha256=XrFUHIPT4EHDujLKbGs9fGFMmoM3NEP8xPRaESJr7bQ,1513
461
462
  omlish/logs/utils.py,sha256=mzHrZ9ji75p5A8qR29eUr05CBAHMb8J753MSkID_VaQ,393
462
463
  omlish/manifests/__init__.py,sha256=P2B0dpT8D7l5lJwRGPA92IcQj6oeXfd90X5-q9BJrKg,51
463
- omlish/manifests/load.py,sha256=LrWAvBfdzDkFdLuVwfw2RwFvLjxx-rvfkpU9eBsWeIc,5626
464
+ omlish/manifests/load.py,sha256=u84sAHhDgHefTDK8S50W5czRnqfwm0obqiOzNBCBP9Q,6603
464
465
  omlish/manifests/types.py,sha256=d8bv5tknCJqclRfxCpao_8XxHo2yofhLpVHQTB-MfNw,260
465
466
  omlish/marshal/__init__.py,sha256=00D3S6qwUld1TUWd67hVHuNcrj3c_FAFSkCVXgGWT-s,2607
466
467
  omlish/marshal/base.py,sha256=tJ4iNuD7cW2GpGMznOhkAf2hugqp2pF2em0FaQcekrk,6740
@@ -518,6 +519,7 @@ omlish/os/forkhooks.py,sha256=yjodOvs90ClXskv5oBIJbHn0Y7dzajLmZmOpRMKbyxM,5656
518
519
  omlish/os/journald.py,sha256=2nI8Res1poXkbLc31--MPUlzYMESnCcPUkIxDOCjZW0,3903
519
520
  omlish/os/linux.py,sha256=whJ6scwMKSFBdXiVhJW0BCpJV4jOGMr-a_a3Bhwz6Ls,18938
520
521
  omlish/os/paths.py,sha256=hqPiyg_eYaRoIVPdAeX4oeLEV4Kpln_XsH0tHvbOf8Q,844
522
+ omlish/os/signals.py,sha256=FtzkovLb58N3vNdfxflUeXWFCqqKzseCjk5kBdWT-ds,267
521
523
  omlish/os/sizes.py,sha256=ohkALLvqSqBX4iR-7DMKJ4pfOCRdZXV8htH4QywUNM0,152
522
524
  omlish/os/temp.py,sha256=P97KiVeNB7rfGn4tlgU5ro86JUxAsiphLMlxsjQgfB0,1198
523
525
  omlish/os/deathpacts/__init__.py,sha256=IFJkHVWff-VhBbQX38th1RlmjUF2ptKh5TPIzP9Ei2M,229
@@ -525,9 +527,11 @@ omlish/os/deathpacts/base.py,sha256=EGN3BWSXPv0s9kl_QLrWE31hTybDHCmsLc_w3U2VyHc,
525
527
  omlish/os/deathpacts/heartbeatfile.py,sha256=OybdvhM2kxBTuoJWOJJ5LcX-0lg3jTOvvD2HUunxDWU,1731
526
528
  omlish/os/deathpacts/pipe.py,sha256=ZH-l-fIKyurocCehqOgvaYRurxIEMWe8D7l2dsJeGws,3214
527
529
  omlish/os/pidfiles/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
530
+ omlish/os/pidfiles/__main__.py,sha256=AF8TwjK4xgHVnoLAP9dIWgKvT0vGhHJlfDW0tKZ7tx4,200
531
+ omlish/os/pidfiles/cli.py,sha256=2SSsP4O3VdpsDIMAkWgWSjh_YNIPzCD9l5LNN2qrIjo,2074
528
532
  omlish/os/pidfiles/manager.py,sha256=qSEwNaWT1KOAnU0KxliwvU_uowme5jyf1FyIPsGwnTY,2391
529
- omlish/os/pidfiles/pidfile.py,sha256=wrttUQB7rk2SJ7MqtaRlqVGii5Kg6LWm3eV2auHb3zA,4125
530
- omlish/os/pidfiles/pinning.py,sha256=_AwYjJc1UGX7mdCOk4mItJJcsOJo3RW2ebBOm2noW5Y,6359
533
+ omlish/os/pidfiles/pidfile.py,sha256=yy14NCjvsCdXzlJjZzkw4vbzjt_FXEaUS5SbYT3dGY0,4277
534
+ omlish/os/pidfiles/pinning.py,sha256=v9RlJ4BnJZcaZZXiiRqbmzLluaSOkeeEb_WrbKEClBQ,6643
531
535
  omlish/reflect/__init__.py,sha256=Er2yBHibVO16hFNA1szQF2_f43Y3HRCBWtS-fjsOIYc,798
532
536
  omlish/reflect/inspect.py,sha256=WCo2YpBYauKw6k758FLlZ_H4Q05rgVPs96fEv9w6zHQ,1538
533
537
  omlish/reflect/ops.py,sha256=RJ6jzrM4ieFsXzWyNXWV43O_WgzEaUvlHSc5N2ezW2A,2044
@@ -701,9 +705,9 @@ omlish/text/indent.py,sha256=YjtJEBYWuk8--b9JU_T6q4yxV85_TR7VEVr5ViRCFwk,1336
701
705
  omlish/text/minja.py,sha256=jZC-fp3Xuhx48ppqsf2Sf1pHbC0t8XBB7UpUUoOk2Qw,5751
702
706
  omlish/text/parts.py,sha256=JkNZpyR2tv2CNcTaWJJhpQ9E4F0yPR8P_YfDbZfMtwQ,6182
703
707
  omlish/text/random.py,sha256=jNWpqiaKjKyTdMXC-pWAsSC10AAP-cmRRPVhm59ZWLk,194
704
- omlish-0.0.0.dev231.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
705
- omlish-0.0.0.dev231.dist-info/METADATA,sha256=glvhjWJ8XJlRwe1JuGQQYJBpwdsJhjPFHEWn7Z985oE,4176
706
- omlish-0.0.0.dev231.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
707
- omlish-0.0.0.dev231.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
708
- omlish-0.0.0.dev231.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
709
- omlish-0.0.0.dev231.dist-info/RECORD,,
708
+ omlish-0.0.0.dev233.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
709
+ omlish-0.0.0.dev233.dist-info/METADATA,sha256=0YKyq7oO-djATl7sDOSc7EmgfhqGDWCX7iWI3ND1lpo,4176
710
+ omlish-0.0.0.dev233.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
711
+ omlish-0.0.0.dev233.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
712
+ omlish-0.0.0.dev233.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
713
+ omlish-0.0.0.dev233.dist-info/RECORD,,