omlish 0.0.0.dev231__py3-none-any.whl → 0.0.0.dev233__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
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,,