omlish 0.0.0.dev2__py3-none-any.whl → 0.0.0.dev3__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.
Potentially problematic release.
This version of omlish might be problematic. Click here for more details.
- omlish/__about__.py +1 -2
- omlish/argparse.py +4 -4
- omlish/asyncs/__init__.py +2 -2
- omlish/asyncs/anyio.py +13 -11
- omlish/asyncs/asyncs.py +1 -3
- omlish/asyncs/futures.py +10 -9
- omlish/c3.py +1 -1
- omlish/check.py +3 -3
- omlish/collections/_abc.py +2 -0
- omlish/collections/_io_abc.py +4 -2
- omlish/collections/cache/__init__.py +1 -1
- omlish/collections/cache/descriptor.py +8 -8
- omlish/collections/cache/impl.py +24 -17
- omlish/collections/cache/types.py +1 -1
- omlish/collections/coerce.py +1 -1
- omlish/collections/frozen.py +6 -6
- omlish/collections/identity.py +3 -4
- omlish/collections/mappings.py +2 -2
- omlish/collections/ordered.py +7 -7
- omlish/collections/skiplist.py +1 -1
- omlish/collections/sorted.py +1 -1
- omlish/collections/treap.py +25 -0
- omlish/collections/treapmap.py +57 -5
- omlish/collections/unmodifiable.py +9 -9
- omlish/collections/utils.py +1 -1
- omlish/configs/flattening.py +7 -6
- omlish/configs/props.py +3 -3
- omlish/dataclasses/__init__.py +1 -1
- omlish/dataclasses/impl/__init__.py +17 -1
- omlish/dataclasses/impl/api.py +10 -11
- omlish/dataclasses/impl/as_.py +4 -4
- omlish/dataclasses/impl/exceptions.py +1 -1
- omlish/dataclasses/impl/fields.py +7 -7
- omlish/dataclasses/impl/frozen.py +2 -2
- omlish/dataclasses/impl/init.py +5 -5
- omlish/dataclasses/impl/internals.py +1 -1
- omlish/dataclasses/impl/metaclass.py +1 -1
- omlish/dataclasses/impl/order.py +1 -1
- omlish/dataclasses/impl/replace.py +1 -1
- omlish/dataclasses/impl/repr.py +4 -4
- omlish/dataclasses/impl/utils.py +6 -6
- omlish/defs.py +13 -17
- omlish/{procfs.py → diag/procfs.py} +22 -24
- omlish/diag/ps.py +47 -0
- omlish/{replserver → diag/replserver}/console.py +18 -20
- omlish/{replserver → diag/replserver}/server.py +8 -8
- omlish/dispatch/dispatch.py +5 -8
- omlish/dispatch/functions.py +1 -1
- omlish/dispatch/methods.py +4 -5
- omlish/docker.py +1 -1
- omlish/dynamic.py +8 -8
- omlish/fnpairs.py +311 -0
- omlish/graphs/trees.py +13 -13
- omlish/inject/__init__.py +7 -7
- omlish/inject/elements.py +1 -1
- omlish/inject/exceptions.py +7 -7
- omlish/inject/impl/elements.py +4 -4
- omlish/inject/impl/injector.py +5 -5
- omlish/inject/impl/inspect.py +2 -2
- omlish/inject/impl/scopes.py +9 -9
- omlish/inject/proxy.py +5 -5
- omlish/iterators.py +19 -24
- omlish/json.py +7 -6
- omlish/lang/__init__.py +9 -4
- omlish/lang/cached.py +2 -5
- omlish/lang/classes/__init__.py +2 -2
- omlish/lang/classes/abstract.py +2 -2
- omlish/lang/classes/restrict.py +14 -14
- omlish/lang/classes/simple.py +1 -1
- omlish/lang/classes/virtual.py +5 -5
- omlish/lang/clsdct.py +1 -1
- omlish/lang/cmp.py +2 -2
- omlish/lang/contextmanagers.py +12 -14
- omlish/lang/descriptors.py +16 -4
- omlish/lang/exceptions.py +1 -1
- omlish/lang/functions.py +58 -22
- omlish/lang/imports.py +22 -27
- omlish/lang/iterables.py +2 -2
- omlish/lang/maybes.py +1 -0
- omlish/lang/objects.py +15 -9
- omlish/lang/resolving.py +1 -1
- omlish/lang/strings.py +1 -1
- omlish/lang/typing.py +3 -3
- omlish/libc.py +9 -5
- omlish/logs/_abc.py +5 -1
- omlish/logs/filters.py +2 -0
- omlish/logs/formatters.py +6 -2
- omlish/logs/utils.py +1 -1
- omlish/marshal/base.py +3 -3
- omlish/marshal/exceptions.py +1 -1
- omlish/marshal/global_.py +10 -4
- omlish/marshal/objects.py +1 -2
- omlish/marshal/registries.py +3 -3
- omlish/marshal/utils.py +2 -2
- omlish/marshal/values.py +1 -1
- omlish/math.py +9 -9
- omlish/reflect.py +3 -3
- omlish/stats.py +4 -5
- omlish/term.py +1 -1
- omlish/testing/pydevd.py +26 -6
- omlish/testing/pytest/inject/harness.py +1 -1
- omlish/testing/pytest/plugins/pydevd.py +1 -1
- omlish/testing/pytest/plugins/switches.py +1 -1
- omlish/text/delimit.py +3 -6
- {omlish-0.0.0.dev2.dist-info → omlish-0.0.0.dev3.dist-info}/METADATA +1 -1
- omlish-0.0.0.dev3.dist-info/RECORD +191 -0
- {omlish-0.0.0.dev2.dist-info → omlish-0.0.0.dev3.dist-info}/WHEEL +1 -1
- omlish/lang/classes/test/test_abstract.py +0 -89
- omlish/lang/classes/test/test_restrict.py +0 -71
- omlish/lang/classes/test/test_simple.py +0 -58
- omlish/lang/classes/test/test_virtual.py +0 -72
- omlish-0.0.0.dev2.dist-info/RECORD +0 -193
- /omlish/{lang/classes/test → diag}/__init__.py +0 -0
- /omlish/{replserver → diag/replserver}/__init__.py +0 -0
- /omlish/{replserver → diag/replserver}/__main__.py +0 -0
- /omlish/sql/{_abcs.py → _abc.py} +0 -0
- {omlish-0.0.0.dev2.dist-info → omlish-0.0.0.dev3.dist-info}/LICENSE +0 -0
- {omlish-0.0.0.dev2.dist-info → omlish-0.0.0.dev3.dist-info}/top_level.txt +0 -0
omlish/defs.py
CHANGED
|
@@ -4,6 +4,8 @@ class definitions. Should be used sparingly for methods not directly used by hum
|
|
|
4
4
|
remain @property's for type annotation, tool assistance, debugging, and otherwise, but these are still nice to have in
|
|
5
5
|
certain circumstances (the real-world alternative usually being simply not adding them).
|
|
6
6
|
"""
|
|
7
|
+
# ruff: noqa: ANN201
|
|
8
|
+
|
|
7
9
|
import abc
|
|
8
10
|
import functools
|
|
9
11
|
import operator
|
|
@@ -62,29 +64,23 @@ def build_attr_repr(obj, *, mro=False):
|
|
|
62
64
|
if mro:
|
|
63
65
|
attrs = [
|
|
64
66
|
attr
|
|
65
|
-
for ty in sorted(reversed(type(obj).__mro__), key=lambda _ty: _ty.__dict__.get('__repr_priority__', 0))
|
|
67
|
+
for ty in sorted(reversed(type(obj).__mro__), key=lambda _ty: _ty.__dict__.get('__repr_priority__', 0)) # noqa
|
|
66
68
|
for attr in ty.__dict__.get('__repr_attrs__', [])]
|
|
67
69
|
else:
|
|
68
70
|
attrs = obj.__repr_attrs__
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
hex(id(obj))[2:],
|
|
72
|
-
', '.join('%s=%s' % (attr, '<self>' if value is obj else _repr(value))
|
|
73
|
-
for attr in attrs for value in [getattr(obj, attr)]))
|
|
71
|
+
s = ', '.join(f'{a}={"<self>" if v is obj else _repr(v)}' for a in attrs for v in [getattr(obj, a)])
|
|
72
|
+
return f'{type(obj).__name__}@{hex(id(obj))[2:]}({s})'
|
|
74
73
|
|
|
75
74
|
|
|
76
75
|
@_repr_guard
|
|
77
76
|
def build_repr(obj, *attrs):
|
|
78
|
-
return '
|
|
79
|
-
type(obj).__name__,
|
|
80
|
-
hex(id(obj))[2:],
|
|
81
|
-
', '.join('%s=%r' % (attr, getattr(obj, attr)) for attr in attrs))
|
|
77
|
+
return f'{type(obj).__name__}@{hex(id(obj))[2:]}({", ".join(f"{attr}={getattr(obj, attr)!r}" for attr in attrs)})'
|
|
82
78
|
|
|
83
79
|
|
|
84
80
|
@_basic
|
|
85
81
|
@lang.cls_dct_fn()
|
|
86
|
-
def repr(cls_dct, *attrs, mro=False, priority=None):
|
|
87
|
-
def __repr__(self):
|
|
82
|
+
def repr(cls_dct, *attrs, mro=False, priority=None): # noqa
|
|
83
|
+
def __repr__(self): # noqa
|
|
88
84
|
return build_attr_repr(self, mro=mro)
|
|
89
85
|
|
|
90
86
|
cls_dct['__repr_attrs__'] = attrs
|
|
@@ -95,7 +91,7 @@ def repr(cls_dct, *attrs, mro=False, priority=None):
|
|
|
95
91
|
|
|
96
92
|
@lang.cls_dct_fn()
|
|
97
93
|
def bare_repr(cls_dct, *attrs):
|
|
98
|
-
def __repr__(self):
|
|
94
|
+
def __repr__(self): # noqa
|
|
99
95
|
return lang.attr_repr(self, *attrs)
|
|
100
96
|
|
|
101
97
|
cls_dct['__repr__'] = __repr__
|
|
@@ -103,7 +99,7 @@ def bare_repr(cls_dct, *attrs):
|
|
|
103
99
|
|
|
104
100
|
@lang.cls_dct_fn()
|
|
105
101
|
def name_repr(cls_dct):
|
|
106
|
-
def __repr__(self):
|
|
102
|
+
def __repr__(self): # noqa
|
|
107
103
|
return self.__name__
|
|
108
104
|
|
|
109
105
|
cls_dct['__repr__'] = __repr__
|
|
@@ -111,7 +107,7 @@ def name_repr(cls_dct):
|
|
|
111
107
|
|
|
112
108
|
@lang.cls_dct_fn()
|
|
113
109
|
def ne(cls_dct):
|
|
114
|
-
def __ne__(self, other):
|
|
110
|
+
def __ne__(self, other): # noqa
|
|
115
111
|
return not (self == other)
|
|
116
112
|
|
|
117
113
|
cls_dct['__ne__'] = __ne__
|
|
@@ -137,12 +133,12 @@ def no_order(cls_dct, *, raise_=None):
|
|
|
137
133
|
@_basic
|
|
138
134
|
@lang.cls_dct_fn()
|
|
139
135
|
def hash_eq(cls_dct, *attrs):
|
|
140
|
-
def __hash__(self):
|
|
136
|
+
def __hash__(self): # noqa
|
|
141
137
|
return hash(tuple(getattr(self, attr) for attr in attrs))
|
|
142
138
|
|
|
143
139
|
cls_dct['__hash__'] = __hash__
|
|
144
140
|
|
|
145
|
-
def __eq__(self, other):
|
|
141
|
+
def __eq__(self, other): # noqa
|
|
146
142
|
if type(other) is not type(self):
|
|
147
143
|
return False
|
|
148
144
|
for attr in attrs:
|
|
@@ -11,10 +11,10 @@ import struct
|
|
|
11
11
|
import sys
|
|
12
12
|
import typing as ta
|
|
13
13
|
|
|
14
|
-
from
|
|
15
|
-
from
|
|
16
|
-
from
|
|
17
|
-
from
|
|
14
|
+
from .. import iterators as it
|
|
15
|
+
from .. import json
|
|
16
|
+
from .. import lang
|
|
17
|
+
from .. import os as oos
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
log = logging.getLogger(__name__)
|
|
@@ -98,18 +98,18 @@ def _check_linux() -> None:
|
|
|
98
98
|
raise OSError
|
|
99
99
|
|
|
100
100
|
|
|
101
|
-
def get_process_stats(pid: PidLike = 'self') ->
|
|
101
|
+
def get_process_stats(pid: PidLike = 'self') -> list[str]:
|
|
102
102
|
"""http://man7.org/linux/man-pages/man5/proc.5.html -> /proc/[pid]/stat"""
|
|
103
103
|
|
|
104
104
|
_check_linux()
|
|
105
|
-
with open('/proc
|
|
105
|
+
with open(f'/proc/{pid}/stat') as f:
|
|
106
106
|
buf = f.read()
|
|
107
107
|
l, _, r = buf.rpartition(')')
|
|
108
108
|
pid, _, comm = l.partition('(')
|
|
109
|
-
return [pid.strip(), comm
|
|
109
|
+
return [pid.strip(), comm, *r.strip().split(' ')]
|
|
110
110
|
|
|
111
111
|
|
|
112
|
-
def get_process_chain(pid: PidLike = 'self') ->
|
|
112
|
+
def get_process_chain(pid: PidLike = 'self') -> list[tuple[int, str]]:
|
|
113
113
|
_check_linux()
|
|
114
114
|
lst = []
|
|
115
115
|
while pid:
|
|
@@ -144,7 +144,7 @@ def get_process_rss(pid: PidLike = 'self') -> int:
|
|
|
144
144
|
|
|
145
145
|
def set_process_oom_score_adj(score: str, pid: PidLike = 'self') -> None:
|
|
146
146
|
_check_linux()
|
|
147
|
-
with open('/proc
|
|
147
|
+
with open(f'/proc/{pid}/oom_score_adj', 'w') as f:
|
|
148
148
|
f.write(str(score))
|
|
149
149
|
|
|
150
150
|
|
|
@@ -160,11 +160,11 @@ MAP_LINE_RX = re.compile(
|
|
|
160
160
|
)
|
|
161
161
|
|
|
162
162
|
|
|
163
|
-
def get_process_maps(pid: PidLike = 'self', sharing: bool = False) -> ta.Iterator[
|
|
163
|
+
def get_process_maps(pid: PidLike = 'self', sharing: bool = False) -> ta.Iterator[dict[str, ta.Any]]:
|
|
164
164
|
"""http://man7.org/linux/man-pages/man5/proc.5.html -> /proc/[pid]/maps"""
|
|
165
165
|
|
|
166
166
|
_check_linux()
|
|
167
|
-
with open('/proc
|
|
167
|
+
with open(f'/proc/{pid}/{"smaps" if sharing else "maps"}') as map_file:
|
|
168
168
|
while True:
|
|
169
169
|
line = map_file.readline()
|
|
170
170
|
if not line:
|
|
@@ -210,14 +210,14 @@ PAGEMAP_KEYS = (
|
|
|
210
210
|
)
|
|
211
211
|
|
|
212
212
|
|
|
213
|
-
def get_process_range_pagemaps(start: int, end: int, pid: PidLike = 'self') -> ta.Iterable[
|
|
213
|
+
def get_process_range_pagemaps(start: int, end: int, pid: PidLike = 'self') -> ta.Iterable[dict[str, int]]:
|
|
214
214
|
"""https://www.kernel.org/doc/Documentation/vm/pagemap.txt"""
|
|
215
215
|
|
|
216
216
|
_check_linux()
|
|
217
217
|
offset = (start // oos.PAGE_SIZE) * 8
|
|
218
218
|
npages = ((end - start) // oos.PAGE_SIZE)
|
|
219
219
|
size = npages * 8
|
|
220
|
-
with open('/proc
|
|
220
|
+
with open(f'/proc/{pid}/pagemap', 'rb') as pagemap_file:
|
|
221
221
|
pagemap_file.seek(offset)
|
|
222
222
|
pagemap_buf = pagemap_file.read(size)
|
|
223
223
|
if not pagemap_buf:
|
|
@@ -237,14 +237,13 @@ def get_process_range_pagemaps(start: int, end: int, pid: PidLike = 'self') -> t
|
|
|
237
237
|
}
|
|
238
238
|
|
|
239
239
|
|
|
240
|
-
def get_process_pagemaps(pid: PidLike = 'self') -> ta.Iterable[
|
|
240
|
+
def get_process_pagemaps(pid: PidLike = 'self') -> ta.Iterable[dict[str, int]]:
|
|
241
241
|
_check_linux()
|
|
242
242
|
for m in get_process_maps(pid):
|
|
243
|
-
|
|
244
|
-
yield p
|
|
243
|
+
yield from get_process_range_pagemaps(m['address'], m['end_address'], pid)
|
|
245
244
|
|
|
246
245
|
|
|
247
|
-
def _dump_cmd(args):
|
|
246
|
+
def _dump_cmd(args: ta.Any) -> None:
|
|
248
247
|
total = 0
|
|
249
248
|
dirty_total = 0
|
|
250
249
|
for m in get_process_maps(args.pid, sharing=True):
|
|
@@ -264,7 +263,7 @@ def _dump_cmd(args):
|
|
|
264
263
|
sys.stdout.write('\n')
|
|
265
264
|
|
|
266
265
|
|
|
267
|
-
def _cmp_cmd(args):
|
|
266
|
+
def _cmp_cmd(args: ta.Any) -> None:
|
|
268
267
|
if len(args.pids) == 1:
|
|
269
268
|
[rpid] = args.pids
|
|
270
269
|
lpid = get_process_chain(rpid)[1][0]
|
|
@@ -273,12 +272,11 @@ def _cmp_cmd(args):
|
|
|
273
272
|
else:
|
|
274
273
|
raise TypeError('Invalid arguments')
|
|
275
274
|
|
|
276
|
-
def g(pid):
|
|
275
|
+
def g(pid: int) -> ta.Iterator[dict[str, int]]:
|
|
277
276
|
for m in get_process_maps(pid, sharing=True):
|
|
278
|
-
|
|
279
|
-
yield pm
|
|
277
|
+
yield from get_process_range_pagemaps(m['address'], m['end_address'], pid)
|
|
280
278
|
|
|
281
|
-
lpms, rpms =
|
|
279
|
+
lpms, rpms = (g(pid) for pid in (lpid, rpid))
|
|
282
280
|
|
|
283
281
|
l_pages = 0
|
|
284
282
|
r_pages = 0
|
|
@@ -289,7 +287,7 @@ def _cmp_cmd(args):
|
|
|
289
287
|
l_pages += 1
|
|
290
288
|
elif l is None and r is not None:
|
|
291
289
|
r_pages += 1
|
|
292
|
-
elif l['pfn'] != r['pfn']:
|
|
290
|
+
elif l['pfn'] != r['pfn']: # type: ignore
|
|
293
291
|
c_pages += 1
|
|
294
292
|
else:
|
|
295
293
|
continue
|
|
@@ -310,7 +308,7 @@ def _cmp_cmd(args):
|
|
|
310
308
|
sys.stdout.write('\n')
|
|
311
309
|
|
|
312
310
|
|
|
313
|
-
def _main():
|
|
311
|
+
def _main() -> None:
|
|
314
312
|
_check_linux()
|
|
315
313
|
|
|
316
314
|
arg_parser = argparse.ArgumentParser()
|
omlish/diag/ps.py
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import dataclasses as dc
|
|
2
|
+
import os
|
|
3
|
+
import subprocess
|
|
4
|
+
|
|
5
|
+
from .. import lang
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dc.dataclass(frozen=True)
|
|
9
|
+
class PsItem:
|
|
10
|
+
pid: int
|
|
11
|
+
ppid: int
|
|
12
|
+
cmd: str
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def get_ps_item(pid: int, timeout: lang.Timeout | None = None) -> PsItem:
|
|
16
|
+
timeout = lang.timeout(timeout)
|
|
17
|
+
out = subprocess.check_output(
|
|
18
|
+
['ps', '-o', 'pid=,ppid=,command=', str(int(pid))],
|
|
19
|
+
timeout=timeout.or_(None),
|
|
20
|
+
).decode().strip()
|
|
21
|
+
opid, _, rest = out.partition(' ')
|
|
22
|
+
ppid, _, cmd = rest.strip().partition(' ')
|
|
23
|
+
return PsItem(
|
|
24
|
+
int(opid),
|
|
25
|
+
int(ppid),
|
|
26
|
+
cmd.strip(),
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def get_ps_lineage(pid: int, timeout: lang.Timeout | None = None) -> list[PsItem]:
|
|
31
|
+
timeout = lang.timeout(timeout)
|
|
32
|
+
ret: list[PsItem] = []
|
|
33
|
+
while True:
|
|
34
|
+
cur = get_ps_item(pid, timeout)
|
|
35
|
+
if cur.ppid < 1:
|
|
36
|
+
break
|
|
37
|
+
ret.append(cur)
|
|
38
|
+
pid = cur.ppid
|
|
39
|
+
return ret
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _main() -> None:
|
|
43
|
+
print(get_ps_lineage(os.getpid()))
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
if __name__ == '__main__':
|
|
47
|
+
_main()
|
|
@@ -25,13 +25,13 @@ import traceback
|
|
|
25
25
|
import types
|
|
26
26
|
import typing as ta
|
|
27
27
|
|
|
28
|
-
from
|
|
28
|
+
from ... import check
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
log = logging.getLogger(__name__)
|
|
32
32
|
|
|
33
33
|
|
|
34
|
-
class
|
|
34
|
+
class DisconnectError(Exception):
|
|
35
35
|
pass
|
|
36
36
|
|
|
37
37
|
|
|
@@ -43,13 +43,13 @@ class InteractiveSocketConsole:
|
|
|
43
43
|
def __init__(
|
|
44
44
|
self,
|
|
45
45
|
conn: sock.socket,
|
|
46
|
-
locals: dict[str, ta.Any] | None = None,
|
|
46
|
+
locals: dict[str, ta.Any] | None = None, # noqa
|
|
47
47
|
filename: str = '<console>',
|
|
48
48
|
) -> None:
|
|
49
49
|
super().__init__()
|
|
50
50
|
|
|
51
51
|
if locals is None:
|
|
52
|
-
locals = {
|
|
52
|
+
locals = { # noqa
|
|
53
53
|
'__name__': '__console__',
|
|
54
54
|
'__doc__': None,
|
|
55
55
|
'__console__': self,
|
|
@@ -81,11 +81,9 @@ class InteractiveSocketConsole:
|
|
|
81
81
|
ps2 = getattr(sys, 'ps2', '... ')
|
|
82
82
|
|
|
83
83
|
if banner is None:
|
|
84
|
-
self.write(
|
|
85
|
-
'Python %s on %s\n%s\n(%s)\n' %
|
|
86
|
-
(sys.version, sys.platform, self.CPRT, self.__class__.__name__))
|
|
84
|
+
self.write(f'Python {sys.version} on {sys.platform}\n{self.CPRT}\n({self.__class__.__name__})\n')
|
|
87
85
|
elif banner:
|
|
88
|
-
self.write('
|
|
86
|
+
self.write(f'{banner!s}\n')
|
|
89
87
|
|
|
90
88
|
more = False
|
|
91
89
|
while True:
|
|
@@ -104,12 +102,12 @@ class InteractiveSocketConsole:
|
|
|
104
102
|
more = False
|
|
105
103
|
|
|
106
104
|
if exitmsg is None:
|
|
107
|
-
self.write('now exiting
|
|
105
|
+
self.write(f'now exiting {self.__class__.__name__}...\n')
|
|
108
106
|
|
|
109
107
|
elif exitmsg != '':
|
|
110
|
-
self.write('
|
|
108
|
+
self.write(f'{exitmsg}\n')
|
|
111
109
|
|
|
112
|
-
except
|
|
110
|
+
except DisconnectError:
|
|
113
111
|
pass
|
|
114
112
|
|
|
115
113
|
except OSError as oe:
|
|
@@ -133,7 +131,7 @@ class InteractiveSocketConsole:
|
|
|
133
131
|
while True:
|
|
134
132
|
b = self._conn.recv(1)
|
|
135
133
|
if not b:
|
|
136
|
-
raise
|
|
134
|
+
raise DisconnectError
|
|
137
135
|
if b == b'\n':
|
|
138
136
|
break
|
|
139
137
|
buf += b
|
|
@@ -228,20 +226,20 @@ class InteractiveSocketConsole:
|
|
|
228
226
|
last_tb = ei = None # type: ignore # noqa
|
|
229
227
|
|
|
230
228
|
def show_syntax_error(self, filename: str | None = None) -> None:
|
|
231
|
-
|
|
232
|
-
sys.last_type =
|
|
233
|
-
sys.last_value =
|
|
229
|
+
et, e, tb = sys.exc_info()
|
|
230
|
+
sys.last_type = et
|
|
231
|
+
sys.last_value = e
|
|
234
232
|
sys.last_traceback = tb
|
|
235
|
-
if filename and
|
|
233
|
+
if filename and et is SyntaxError:
|
|
236
234
|
# Work hard to stuff the correct filename in the exception
|
|
237
235
|
try:
|
|
238
|
-
msg, (dummy_filename, lineno, offset, line) =
|
|
236
|
+
msg, (dummy_filename, lineno, offset, line) = e.args # type: ignore
|
|
239
237
|
except ValueError:
|
|
240
238
|
# Not the format we expect; leave it alone
|
|
241
239
|
pass
|
|
242
240
|
else:
|
|
243
241
|
# Stuff in the right filename
|
|
244
|
-
|
|
245
|
-
sys.last_value =
|
|
246
|
-
lines = traceback.format_exception_only(
|
|
242
|
+
e = SyntaxError(msg, (filename, lineno, offset, line))
|
|
243
|
+
sys.last_value = e
|
|
244
|
+
lines = traceback.format_exception_only(et, e)
|
|
247
245
|
self.write(''.join(lines))
|
|
@@ -23,8 +23,8 @@ import threading
|
|
|
23
23
|
import typing as ta
|
|
24
24
|
import weakref
|
|
25
25
|
|
|
26
|
-
from
|
|
27
|
-
from
|
|
26
|
+
from ... import check
|
|
27
|
+
from ... import dataclasses as dc
|
|
28
28
|
from .console import InteractiveSocketConsole
|
|
29
29
|
|
|
30
30
|
|
|
@@ -62,12 +62,12 @@ class ReplServer:
|
|
|
62
62
|
def path(self) -> str:
|
|
63
63
|
return self._config.path
|
|
64
64
|
|
|
65
|
-
def __enter__(self):
|
|
65
|
+
def __enter__(self) -> ta.Self:
|
|
66
66
|
check.state(not self._is_running)
|
|
67
67
|
check.state(not self._is_shutdown.is_set())
|
|
68
68
|
return self
|
|
69
69
|
|
|
70
|
-
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
70
|
+
def __exit__(self, exc_type, exc_val, exc_tb) -> None:
|
|
71
71
|
if not self._is_shutdown.is_set():
|
|
72
72
|
self.shutdown(True, self._config.exit_timeout)
|
|
73
73
|
|
|
@@ -91,7 +91,7 @@ class ReplServer:
|
|
|
91
91
|
while not self._should_shutdown:
|
|
92
92
|
try:
|
|
93
93
|
conn, _ = self._socket.accept()
|
|
94
|
-
except
|
|
94
|
+
except TimeoutError:
|
|
95
95
|
continue
|
|
96
96
|
|
|
97
97
|
log.info(f'Got repl server connection on file {self._config.path}')
|
|
@@ -117,13 +117,13 @@ class ReplServer:
|
|
|
117
117
|
name=self.CONNECTION_THREAD_NAME)
|
|
118
118
|
thread.start()
|
|
119
119
|
|
|
120
|
-
for
|
|
120
|
+
for console in self._consoles_by_threads.values():
|
|
121
121
|
try:
|
|
122
122
|
console.conn.close()
|
|
123
123
|
except Exception:
|
|
124
124
|
log.exception('Error shutting down')
|
|
125
125
|
|
|
126
|
-
for thread in self._consoles_by_threads
|
|
126
|
+
for thread in self._consoles_by_threads:
|
|
127
127
|
try:
|
|
128
128
|
thread.join(self._config.exit_timeout)
|
|
129
129
|
except Exception:
|
|
@@ -141,6 +141,6 @@ class ReplServer:
|
|
|
141
141
|
self._is_shutdown.wait(timeout=timeout)
|
|
142
142
|
|
|
143
143
|
|
|
144
|
-
def run():
|
|
144
|
+
def run() -> None:
|
|
145
145
|
with ReplServer(ReplServer.Config('repl.sock')) as repl_server:
|
|
146
146
|
repl_server.run()
|
omlish/dispatch/dispatch.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import abc
|
|
2
|
+
import contextlib
|
|
2
3
|
import typing as ta
|
|
3
4
|
import weakref
|
|
4
5
|
|
|
@@ -13,14 +14,12 @@ T = ta.TypeVar('T')
|
|
|
13
14
|
##
|
|
14
15
|
|
|
15
16
|
|
|
16
|
-
_IMPL_FUNC_CLS_SET_CACHE: ta.MutableMapping[ta.Callable,
|
|
17
|
+
_IMPL_FUNC_CLS_SET_CACHE: ta.MutableMapping[ta.Callable, frozenset[type]] = weakref.WeakKeyDictionary()
|
|
17
18
|
|
|
18
19
|
|
|
19
|
-
def get_impl_func_cls_set(func: ta.Callable) ->
|
|
20
|
-
|
|
20
|
+
def get_impl_func_cls_set(func: ta.Callable) -> frozenset[type]:
|
|
21
|
+
with contextlib.suppress(KeyError):
|
|
21
22
|
return _IMPL_FUNC_CLS_SET_CACHE[func]
|
|
22
|
-
except KeyError:
|
|
23
|
-
pass
|
|
24
23
|
|
|
25
24
|
ann = getattr(func, '__annotations__', {})
|
|
26
25
|
if not ann:
|
|
@@ -78,10 +77,8 @@ class Dispatcher(ta.Generic[T]):
|
|
|
78
77
|
def cache_remove(k, self_ref=weakref.ref(self)):
|
|
79
78
|
if (ref_self := self_ref()) is not None:
|
|
80
79
|
cache = ref_self._get_dispatch_cache() # noqa
|
|
81
|
-
|
|
80
|
+
with contextlib.suppress(KeyError):
|
|
82
81
|
del cache[k]
|
|
83
|
-
except KeyError:
|
|
84
|
-
pass
|
|
85
82
|
|
|
86
83
|
cache_token: ta.Any = None
|
|
87
84
|
self._get_cache_token = lambda: cache_token
|
omlish/dispatch/functions.py
CHANGED
omlish/dispatch/methods.py
CHANGED
|
@@ -4,6 +4,7 @@ TODO:
|
|
|
4
4
|
- ALT: A.f(super(), ... ? :/
|
|
5
5
|
- classmethod/staticmethod
|
|
6
6
|
"""
|
|
7
|
+
import contextlib
|
|
7
8
|
import functools
|
|
8
9
|
import typing as ta
|
|
9
10
|
import weakref
|
|
@@ -23,7 +24,7 @@ def build_mro_dct(instance_cls: type, owner_cls: type | None = None) -> ta.Mappi
|
|
|
23
24
|
try:
|
|
24
25
|
pos = mro.index(owner_cls)
|
|
25
26
|
except ValueError:
|
|
26
|
-
raise TypeError(f'Owner class {owner_cls} not in mro of instance class {instance_cls}')
|
|
27
|
+
raise TypeError(f'Owner class {owner_cls} not in mro of instance class {instance_cls}') from None
|
|
27
28
|
dct: dict[str, ta.Any] = {}
|
|
28
29
|
for cur_cls in mro[:pos + 1]:
|
|
29
30
|
dct.update(cur_cls.__dict__)
|
|
@@ -55,10 +56,8 @@ class Method:
|
|
|
55
56
|
def dispatch_func_cache_remove(k, self_ref=weakref.ref(self)):
|
|
56
57
|
if (ref_self := self_ref()) is not None:
|
|
57
58
|
cache = ref_self._dispatch_func_cache # noqa
|
|
58
|
-
|
|
59
|
+
with contextlib.suppress(KeyError):
|
|
59
60
|
del cache[k]
|
|
60
|
-
except KeyError:
|
|
61
|
-
pass
|
|
62
61
|
|
|
63
62
|
self._dispatch_func_cache_remove = dispatch_func_cache_remove
|
|
64
63
|
|
|
@@ -158,5 +157,5 @@ class Method:
|
|
|
158
157
|
return func.__get__(instance)(*args, **kwargs) # noqa
|
|
159
158
|
|
|
160
159
|
|
|
161
|
-
def method(func):
|
|
160
|
+
def method(func): # noqa
|
|
162
161
|
return Method(func)
|
omlish/docker.py
CHANGED
|
@@ -127,7 +127,7 @@ class ComposeConfig:
|
|
|
127
127
|
|
|
128
128
|
@lang.cached_function
|
|
129
129
|
def get_config(self) -> ta.Mapping[str, ta.Any]:
|
|
130
|
-
with open(check.not_none(self._file_path)
|
|
130
|
+
with open(check.not_none(self._file_path)) as f:
|
|
131
131
|
buf = f.read()
|
|
132
132
|
return yaml.safe_load(buf)
|
|
133
133
|
|
omlish/dynamic.py
CHANGED
|
@@ -25,7 +25,7 @@ _HOISTED_CODE_DEPTH: ta.MutableMapping[types.CodeType, int] = weakref.WeakKeyDic
|
|
|
25
25
|
_MAX_HOIST_DEPTH = 0
|
|
26
26
|
|
|
27
27
|
|
|
28
|
-
def hoist(depth=0):
|
|
28
|
+
def hoist(depth=0): # noqa
|
|
29
29
|
def inner(fn):
|
|
30
30
|
_HOISTED_CODE_DEPTH[fn.__code__] = depth
|
|
31
31
|
global _MAX_HOIST_DEPTH
|
|
@@ -87,7 +87,7 @@ class Var(ta.Generic[T]):
|
|
|
87
87
|
self._validate(self.value)
|
|
88
88
|
return Binding(self, value, offset=offset)
|
|
89
89
|
|
|
90
|
-
def with_binding(self, value):
|
|
90
|
+
def with_binding(self, value): # noqa
|
|
91
91
|
def outer(fn):
|
|
92
92
|
@functools.wraps(fn)
|
|
93
93
|
def inner(*args, **kwargs):
|
|
@@ -96,7 +96,7 @@ class Var(ta.Generic[T]):
|
|
|
96
96
|
return inner
|
|
97
97
|
return outer
|
|
98
98
|
|
|
99
|
-
def with_binding_fn(self, binding_fn):
|
|
99
|
+
def with_binding_fn(self, binding_fn): # noqa
|
|
100
100
|
this = self
|
|
101
101
|
|
|
102
102
|
def outer(fn):
|
|
@@ -104,7 +104,7 @@ class Var(ta.Generic[T]):
|
|
|
104
104
|
|
|
105
105
|
@staticmethod
|
|
106
106
|
@functools.wraps(fn)
|
|
107
|
-
def __call__(*args, **kwargs):
|
|
107
|
+
def __call__(*args, **kwargs): # noqa
|
|
108
108
|
with this.binding(binding_fn(*args, **kwargs)):
|
|
109
109
|
return fn(*args, **kwargs)
|
|
110
110
|
|
|
@@ -119,7 +119,7 @@ class Var(ta.Generic[T]):
|
|
|
119
119
|
|
|
120
120
|
return inner
|
|
121
121
|
|
|
122
|
-
dct =
|
|
122
|
+
dct: dict[str, ta.Any] = {k: getattr(fn, k) for k in functools.WRAPPER_ASSIGNMENTS}
|
|
123
123
|
return lang.new_type(fn.__name__, (Descriptor,), dct)()
|
|
124
124
|
|
|
125
125
|
return outer
|
|
@@ -133,7 +133,7 @@ class Var(ta.Generic[T]):
|
|
|
133
133
|
except KeyError:
|
|
134
134
|
pass
|
|
135
135
|
else:
|
|
136
|
-
for level, frame_binding in sorted(frame_bindings.items()):
|
|
136
|
+
for level, frame_binding in sorted(frame_bindings.items()): # noqa
|
|
137
137
|
yield frame_binding._value # noqa
|
|
138
138
|
frame = frame.f_back
|
|
139
139
|
|
|
@@ -148,7 +148,7 @@ class Var(ta.Generic[T]):
|
|
|
148
148
|
try:
|
|
149
149
|
return next(self.values)
|
|
150
150
|
except StopIteration:
|
|
151
|
-
raise UnboundVarError
|
|
151
|
+
raise UnboundVarError from None
|
|
152
152
|
|
|
153
153
|
|
|
154
154
|
class Binding(ta.Generic[T]):
|
|
@@ -213,7 +213,7 @@ class _GeneratorContextManager(contextlib._GeneratorContextManager): # noqa
|
|
|
213
213
|
return super().__enter__()
|
|
214
214
|
|
|
215
215
|
|
|
216
|
-
def contextmanager(fn):
|
|
216
|
+
def contextmanager(fn): # noqa
|
|
217
217
|
@functools.wraps(fn)
|
|
218
218
|
def helper(*args, **kwds):
|
|
219
219
|
return _GeneratorContextManager(fn, args, kwds)
|