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.

Files changed (118) hide show
  1. omlish/__about__.py +1 -2
  2. omlish/argparse.py +4 -4
  3. omlish/asyncs/__init__.py +2 -2
  4. omlish/asyncs/anyio.py +13 -11
  5. omlish/asyncs/asyncs.py +1 -3
  6. omlish/asyncs/futures.py +10 -9
  7. omlish/c3.py +1 -1
  8. omlish/check.py +3 -3
  9. omlish/collections/_abc.py +2 -0
  10. omlish/collections/_io_abc.py +4 -2
  11. omlish/collections/cache/__init__.py +1 -1
  12. omlish/collections/cache/descriptor.py +8 -8
  13. omlish/collections/cache/impl.py +24 -17
  14. omlish/collections/cache/types.py +1 -1
  15. omlish/collections/coerce.py +1 -1
  16. omlish/collections/frozen.py +6 -6
  17. omlish/collections/identity.py +3 -4
  18. omlish/collections/mappings.py +2 -2
  19. omlish/collections/ordered.py +7 -7
  20. omlish/collections/skiplist.py +1 -1
  21. omlish/collections/sorted.py +1 -1
  22. omlish/collections/treap.py +25 -0
  23. omlish/collections/treapmap.py +57 -5
  24. omlish/collections/unmodifiable.py +9 -9
  25. omlish/collections/utils.py +1 -1
  26. omlish/configs/flattening.py +7 -6
  27. omlish/configs/props.py +3 -3
  28. omlish/dataclasses/__init__.py +1 -1
  29. omlish/dataclasses/impl/__init__.py +17 -1
  30. omlish/dataclasses/impl/api.py +10 -11
  31. omlish/dataclasses/impl/as_.py +4 -4
  32. omlish/dataclasses/impl/exceptions.py +1 -1
  33. omlish/dataclasses/impl/fields.py +7 -7
  34. omlish/dataclasses/impl/frozen.py +2 -2
  35. omlish/dataclasses/impl/init.py +5 -5
  36. omlish/dataclasses/impl/internals.py +1 -1
  37. omlish/dataclasses/impl/metaclass.py +1 -1
  38. omlish/dataclasses/impl/order.py +1 -1
  39. omlish/dataclasses/impl/replace.py +1 -1
  40. omlish/dataclasses/impl/repr.py +4 -4
  41. omlish/dataclasses/impl/utils.py +6 -6
  42. omlish/defs.py +13 -17
  43. omlish/{procfs.py → diag/procfs.py} +22 -24
  44. omlish/diag/ps.py +47 -0
  45. omlish/{replserver → diag/replserver}/console.py +18 -20
  46. omlish/{replserver → diag/replserver}/server.py +8 -8
  47. omlish/dispatch/dispatch.py +5 -8
  48. omlish/dispatch/functions.py +1 -1
  49. omlish/dispatch/methods.py +4 -5
  50. omlish/docker.py +1 -1
  51. omlish/dynamic.py +8 -8
  52. omlish/fnpairs.py +311 -0
  53. omlish/graphs/trees.py +13 -13
  54. omlish/inject/__init__.py +7 -7
  55. omlish/inject/elements.py +1 -1
  56. omlish/inject/exceptions.py +7 -7
  57. omlish/inject/impl/elements.py +4 -4
  58. omlish/inject/impl/injector.py +5 -5
  59. omlish/inject/impl/inspect.py +2 -2
  60. omlish/inject/impl/scopes.py +9 -9
  61. omlish/inject/proxy.py +5 -5
  62. omlish/iterators.py +19 -24
  63. omlish/json.py +7 -6
  64. omlish/lang/__init__.py +9 -4
  65. omlish/lang/cached.py +2 -5
  66. omlish/lang/classes/__init__.py +2 -2
  67. omlish/lang/classes/abstract.py +2 -2
  68. omlish/lang/classes/restrict.py +14 -14
  69. omlish/lang/classes/simple.py +1 -1
  70. omlish/lang/classes/virtual.py +5 -5
  71. omlish/lang/clsdct.py +1 -1
  72. omlish/lang/cmp.py +2 -2
  73. omlish/lang/contextmanagers.py +12 -14
  74. omlish/lang/descriptors.py +16 -4
  75. omlish/lang/exceptions.py +1 -1
  76. omlish/lang/functions.py +58 -22
  77. omlish/lang/imports.py +22 -27
  78. omlish/lang/iterables.py +2 -2
  79. omlish/lang/maybes.py +1 -0
  80. omlish/lang/objects.py +15 -9
  81. omlish/lang/resolving.py +1 -1
  82. omlish/lang/strings.py +1 -1
  83. omlish/lang/typing.py +3 -3
  84. omlish/libc.py +9 -5
  85. omlish/logs/_abc.py +5 -1
  86. omlish/logs/filters.py +2 -0
  87. omlish/logs/formatters.py +6 -2
  88. omlish/logs/utils.py +1 -1
  89. omlish/marshal/base.py +3 -3
  90. omlish/marshal/exceptions.py +1 -1
  91. omlish/marshal/global_.py +10 -4
  92. omlish/marshal/objects.py +1 -2
  93. omlish/marshal/registries.py +3 -3
  94. omlish/marshal/utils.py +2 -2
  95. omlish/marshal/values.py +1 -1
  96. omlish/math.py +9 -9
  97. omlish/reflect.py +3 -3
  98. omlish/stats.py +4 -5
  99. omlish/term.py +1 -1
  100. omlish/testing/pydevd.py +26 -6
  101. omlish/testing/pytest/inject/harness.py +1 -1
  102. omlish/testing/pytest/plugins/pydevd.py +1 -1
  103. omlish/testing/pytest/plugins/switches.py +1 -1
  104. omlish/text/delimit.py +3 -6
  105. {omlish-0.0.0.dev2.dist-info → omlish-0.0.0.dev3.dist-info}/METADATA +1 -1
  106. omlish-0.0.0.dev3.dist-info/RECORD +191 -0
  107. {omlish-0.0.0.dev2.dist-info → omlish-0.0.0.dev3.dist-info}/WHEEL +1 -1
  108. omlish/lang/classes/test/test_abstract.py +0 -89
  109. omlish/lang/classes/test/test_restrict.py +0 -71
  110. omlish/lang/classes/test/test_simple.py +0 -58
  111. omlish/lang/classes/test/test_virtual.py +0 -72
  112. omlish-0.0.0.dev2.dist-info/RECORD +0 -193
  113. /omlish/{lang/classes/test → diag}/__init__.py +0 -0
  114. /omlish/{replserver → diag/replserver}/__init__.py +0 -0
  115. /omlish/{replserver → diag/replserver}/__main__.py +0 -0
  116. /omlish/sql/{_abcs.py → _abc.py} +0 -0
  117. {omlish-0.0.0.dev2.dist-info → omlish-0.0.0.dev3.dist-info}/LICENSE +0 -0
  118. {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
- return '%s@%s(%s)' % (
70
- type(obj).__name__,
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 '%s@%s(%s)' % (
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 . import iterators as it
15
- from . import json
16
- from . import lang
17
- from . import os as oos
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') -> ta.List[str]:
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/%s/stat' % (pid,)) as f:
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] + r.strip().split(' ')
109
+ return [pid.strip(), comm, *r.strip().split(' ')]
110
110
 
111
111
 
112
- def get_process_chain(pid: PidLike = 'self') -> ta.List[ta.Tuple[int, str]]:
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/%s/oom_score_adj' % (pid,), 'w') as f:
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[ta.Dict[str, ta.Any]]:
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/%s/%s' % (pid, 'smaps' if sharing else 'maps'), 'r') as map_file:
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[ta.Dict[str, int]]:
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/%s/pagemap' % (pid,), 'rb') as pagemap_file:
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[ta.Dict[str, int]]:
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
- for p in get_process_range_pagemaps(m['address'], m['end_address'], pid):
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
- for pm in get_process_range_pagemaps(m['address'], m['end_address'], pid):
279
- yield pm
277
+ yield from get_process_range_pagemaps(m['address'], m['end_address'], pid)
280
278
 
281
- lpms, rpms = [g(pid) for pid in (lpid, rpid)]
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 .. import check
28
+ from ... import check
29
29
 
30
30
 
31
31
  log = logging.getLogger(__name__)
32
32
 
33
33
 
34
- class DisconnectException(Exception):
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('%s\n' % (str(banner),))
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 %s...\n' % self.__class__.__name__)
105
+ self.write(f'now exiting {self.__class__.__name__}...\n')
108
106
 
109
107
  elif exitmsg != '':
110
- self.write('%s\n' % exitmsg)
108
+ self.write(f'{exitmsg}\n')
111
109
 
112
- except DisconnectException:
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 DisconnectException
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
- type, value, tb = sys.exc_info()
232
- sys.last_type = type
233
- sys.last_value = 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 type is SyntaxError:
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) = value.args # type: ignore
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
- value = SyntaxError(msg, (filename, lineno, offset, line))
245
- sys.last_value = value
246
- lines = traceback.format_exception_only(type, value)
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 .. import check
27
- from .. import dataclasses as dc
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 sock.timeout:
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 thread, console in self._consoles_by_threads.items():
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.keys():
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()
@@ -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, ta.FrozenSet[type]] = weakref.WeakKeyDictionary()
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) -> ta.FrozenSet[type]:
20
- try:
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
- try:
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
@@ -10,7 +10,7 @@ from .dispatch import get_impl_func_cls_set
10
10
  USE_EXTENSION = False
11
11
 
12
12
 
13
- def function(func):
13
+ def function(func): # noqa
14
14
  disp = Dispatcher() # type: ignore
15
15
  disp.register(func, [object])
16
16
 
@@ -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
- try:
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), 'r') as f:
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 = dict((k, getattr(fn, k)) for k in functools.WRAPPER_ASSIGNMENTS)
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)