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 +12 -0
- omlish/__about__.py +4 -4
- omlish/codecs/registry.py +1 -1
- omlish/daemons/daemon.py +17 -91
- omlish/daemons/launching.py +121 -0
- omlish/lang/functions.py +10 -0
- omlish/manifests/load.py +31 -1
- omlish/os/pidfiles/__main__.py +11 -0
- omlish/os/pidfiles/cli.py +88 -0
- omlish/os/pidfiles/pidfile.py +6 -1
- omlish/os/pidfiles/pinning.py +10 -1
- omlish/os/signals.py +15 -0
- {omlish-0.0.0.dev231.dist-info → omlish-0.0.0.dev233.dist-info}/METADATA +5 -5
- {omlish-0.0.0.dev231.dist-info → omlish-0.0.0.dev233.dist-info}/RECORD +18 -14
- {omlish-0.0.0.dev231.dist-info → omlish-0.0.0.dev233.dist-info}/LICENSE +0 -0
- {omlish-0.0.0.dev231.dist-info → omlish-0.0.0.dev233.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev231.dist-info → omlish-0.0.0.dev233.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev231.dist-info → omlish-0.0.0.dev233.dist-info}/top_level.txt +0 -0
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.
|
2
|
-
__revision__ = '
|
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.
|
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 ~=
|
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.
|
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 .
|
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
|
-
|
195
|
-
|
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
|
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,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()
|
omlish/os/pidfiles/pidfile.py
CHANGED
@@ -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
|
-
|
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:
|
omlish/os/pidfiles/pinning.py
CHANGED
@@ -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(
|
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.
|
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.
|
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~=
|
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.
|
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~=
|
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=
|
2
|
-
omlish/__about__.py,sha256=
|
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=
|
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=
|
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=
|
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=
|
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=
|
530
|
-
omlish/os/pidfiles/pinning.py,sha256=
|
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.
|
705
|
-
omlish-0.0.0.
|
706
|
-
omlish-0.0.0.
|
707
|
-
omlish-0.0.0.
|
708
|
-
omlish-0.0.0.
|
709
|
-
omlish-0.0.0.
|
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,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|