omlish 0.0.0.dev1__py3-none-any.whl → 0.0.0.dev2__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 (102) hide show
  1. omlish/__about__.py +2 -2
  2. omlish/argparse.py +4 -4
  3. omlish/asyncs/anyio.py +62 -1
  4. omlish/asyncs/futures.py +6 -6
  5. omlish/c3.py +4 -4
  6. omlish/check.py +6 -6
  7. omlish/collections/__init__.py +98 -63
  8. omlish/collections/cache/descriptor.py +5 -5
  9. omlish/collections/cache/impl.py +4 -4
  10. omlish/collections/coerce.py +43 -43
  11. omlish/collections/frozen.py +3 -3
  12. omlish/collections/identity.py +1 -1
  13. omlish/collections/mappings.py +3 -3
  14. omlish/collections/ordered.py +1 -1
  15. omlish/collections/skiplist.py +6 -6
  16. omlish/collections/sorted.py +3 -3
  17. omlish/collections/treap.py +17 -17
  18. omlish/collections/treapmap.py +2 -2
  19. omlish/collections/unmodifiable.py +28 -27
  20. omlish/configs/flattening.py +1 -1
  21. omlish/configs/props.py +1 -1
  22. omlish/dataclasses/impl/__init__.py +2 -0
  23. omlish/dataclasses/impl/api.py +5 -13
  24. omlish/dataclasses/impl/fields.py +1 -1
  25. omlish/dataclasses/impl/init.py +1 -1
  26. omlish/dataclasses/impl/internals.py +15 -0
  27. omlish/dataclasses/impl/main.py +4 -4
  28. omlish/dataclasses/impl/metaclass.py +1 -1
  29. omlish/dataclasses/impl/metadata.py +1 -1
  30. omlish/dataclasses/impl/order.py +1 -1
  31. omlish/dataclasses/impl/params.py +4 -38
  32. omlish/dataclasses/impl/reflect.py +1 -7
  33. omlish/dataclasses/impl/repr.py +23 -5
  34. omlish/dataclasses/impl/simple.py +2 -2
  35. omlish/dataclasses/impl/slots.py +2 -2
  36. omlish/dataclasses/impl/utils.py +4 -4
  37. omlish/dispatch/dispatch.py +9 -8
  38. omlish/dispatch/methods.py +2 -2
  39. omlish/docker.py +8 -6
  40. omlish/dynamic.py +5 -5
  41. omlish/graphs/dot/items.py +1 -1
  42. omlish/graphs/trees.py +15 -21
  43. omlish/inject/elements.py +1 -1
  44. omlish/inject/exceptions.py +1 -1
  45. omlish/inject/impl/injector.py +1 -1
  46. omlish/inject/impl/inspect.py +1 -1
  47. omlish/inject/injector.py +1 -1
  48. omlish/inject/providers.py +2 -2
  49. omlish/iterators.py +43 -2
  50. omlish/lang/__init__.py +167 -112
  51. omlish/lang/cached.py +13 -5
  52. omlish/lang/classes/__init__.py +35 -24
  53. omlish/lang/classes/abstract.py +1 -1
  54. omlish/lang/classes/simple.py +1 -1
  55. omlish/lang/clsdct.py +1 -1
  56. omlish/lang/contextmanagers.py +23 -15
  57. omlish/lang/datetimes.py +1 -1
  58. omlish/lang/descriptors.py +35 -2
  59. omlish/lang/exceptions.py +2 -0
  60. omlish/lang/functions.py +43 -13
  61. omlish/lang/imports.py +8 -8
  62. omlish/lang/iterables.py +1 -1
  63. omlish/lang/maybes.py +1 -1
  64. omlish/lang/objects.py +2 -2
  65. omlish/lang/timeouts.py +53 -0
  66. omlish/lang/typing.py +2 -2
  67. omlish/libc.py +6 -6
  68. omlish/marshal/base.py +6 -6
  69. omlish/marshal/dataclasses.py +2 -2
  70. omlish/marshal/enums.py +2 -2
  71. omlish/marshal/factories.py +10 -10
  72. omlish/marshal/iterables.py +2 -2
  73. omlish/marshal/mappings.py +2 -2
  74. omlish/marshal/optionals.py +4 -4
  75. omlish/marshal/polymorphism.py +4 -4
  76. omlish/marshal/standard.py +6 -6
  77. omlish/marshal/utils.py +1 -1
  78. omlish/os.py +13 -4
  79. omlish/procfs.py +336 -0
  80. omlish/reflect.py +2 -12
  81. omlish/replserver/console.py +9 -9
  82. omlish/replserver/server.py +4 -4
  83. omlish/sql/__init__.py +0 -0
  84. omlish/sql/_abcs.py +65 -0
  85. omlish/sql/dbs.py +90 -0
  86. omlish/stats.py +3 -3
  87. omlish/testing/pydevd.py +4 -6
  88. omlish/testing/pytest/inject/__init__.py +7 -0
  89. omlish/testing/pytest/inject/harness.py +23 -1
  90. omlish/testing/pytest/plugins/__init__.py +1 -1
  91. omlish/testing/pytest/plugins/pydevd.py +12 -0
  92. omlish/testing/pytest/plugins/switches.py +2 -2
  93. omlish/testing/testing.py +5 -5
  94. omlish/text/parts.py +3 -3
  95. omlish-0.0.0.dev2.dist-info/METADATA +31 -0
  96. omlish-0.0.0.dev2.dist-info/RECORD +193 -0
  97. {omlish-0.0.0.dev1.dist-info → omlish-0.0.0.dev2.dist-info}/WHEEL +1 -1
  98. omlish/testing/pytest/plugins/pycharm.py +0 -54
  99. omlish-0.0.0.dev1.dist-info/METADATA +0 -17
  100. omlish-0.0.0.dev1.dist-info/RECORD +0 -187
  101. {omlish-0.0.0.dev1.dist-info → omlish-0.0.0.dev2.dist-info}/LICENSE +0 -0
  102. {omlish-0.0.0.dev1.dist-info → omlish-0.0.0.dev2.dist-info}/top_level.txt +0 -0
@@ -12,14 +12,11 @@ from .main import process_class
12
12
  from .metadata import METADATA_ATTR
13
13
  from .metadata import Metadata
14
14
  from .params import FieldExtras
15
- from .params import Params12
16
15
  from .params import ParamsExtras
17
16
 
18
17
 
19
18
  MISSING = dc.MISSING
20
19
 
21
- IS_12 = sys.version_info[1] >= 12
22
-
23
20
 
24
21
  def field(
25
22
  default=MISSING,
@@ -32,10 +29,11 @@ def field(
32
29
  metadata=None,
33
30
  kw_only=MISSING,
34
31
 
35
- coerce: ta.Optional[ta.Callable[[ta.Any], ta.Any]] = None,
36
- check: ta.Optional[ta.Callable[[ta.Any], bool]] = None,
37
- check_type: ta.Optional[bool] = None,
32
+ coerce: ta.Callable[[ta.Any], ta.Any] | None = None,
33
+ check: ta.Callable[[ta.Any], bool] | None = None,
34
+ check_type: bool | None = None,
38
35
  override: bool = False,
36
+ repr_fn: ta.Callable[[ta.Any], str | None] | None = None
39
37
  ): # -> dc.Field
40
38
  if default is not MISSING and default_factory is not MISSING:
41
39
  raise ValueError('cannot specify both default and default_factory')
@@ -45,6 +43,7 @@ def field(
45
43
  check=check,
46
44
  check_type=check_type,
47
45
  override=override,
46
+ repr_fn=repr_fn,
48
47
  )
49
48
 
50
49
  md: ta.Mapping = {FieldExtras: fx}
@@ -96,8 +95,6 @@ def dataclass(
96
95
  order=order,
97
96
  unsafe_hash=unsafe_hash,
98
97
  frozen=frozen,
99
- )
100
- p12kw = dict(
101
98
  match_args=match_args,
102
99
  kw_only=kw_only,
103
100
  slots=slots,
@@ -118,11 +115,6 @@ def dataclass(
118
115
  ParamsExtras: pex,
119
116
  }
120
117
 
121
- if IS_12:
122
- pkw.update(p12kw)
123
- else:
124
- mmd[Params12] = Params12(**p12kw)
125
-
126
118
  md: Metadata = mmd
127
119
  cmds = []
128
120
  if metadata is not None:
@@ -112,7 +112,7 @@ def field_init(
112
112
  locals[cn] = f.type
113
113
  lines.append(
114
114
  f'if not __dataclass_builtins_isinstance__({f.name}, {cn}): '
115
- f'raise __dataclass_builtins_TypeError__({f.name}, {cn})'
115
+ f'raise __dataclass_builtins_TypeError__({f.name}, {cn})',
116
116
  )
117
117
 
118
118
  value: str | None = None
@@ -109,7 +109,7 @@ class InitBuilder:
109
109
  self._info.params.frozen,
110
110
  locals,
111
111
  self._self_name,
112
- self._info.params12.slots,
112
+ self._info.params.slots,
113
113
  )
114
114
 
115
115
  if f_lines:
@@ -17,6 +17,21 @@ POST_INIT_NAME = dc._POST_INIT_NAME # type: ignore # noqa
17
17
 
18
18
  Params = dc._DataclassParams # type: ignore # noqa
19
19
 
20
+ """
21
+ @dc.dataclass(frozen=True)
22
+ class Params:
23
+ init = True
24
+ repr = True
25
+ eq = True
26
+ order = False
27
+ unsafe_hash = False
28
+ frozen = False
29
+ match_args = True
30
+ kw_only = False
31
+ slots = False
32
+ weakref_slot = False
33
+ """
34
+
20
35
 
21
36
  ##
22
37
 
@@ -84,7 +84,7 @@ class MainProcessor:
84
84
 
85
85
  cls_fields: list[dc.Field] = []
86
86
 
87
- kw_only = self._info.params12.kw_only
87
+ kw_only = self._info.params.kw_only
88
88
  kw_only_seen = False
89
89
  for name, ann in self._info.cls_annotations.items():
90
90
  if is_kw_only(self._cls, ann):
@@ -111,11 +111,11 @@ class MainProcessor:
111
111
 
112
112
  @lang.cached_function
113
113
  def _transform_slots(self) -> None:
114
- if self._info.params12.weakref_slot and not self._info.params12.slots:
114
+ if self._info.params.weakref_slot and not self._info.params.slots:
115
115
  raise TypeError('weakref_slot is True but slots is False')
116
- if not self._info.params12.slots:
116
+ if not self._info.params.slots:
117
117
  return
118
- self._cls = add_slots(self._cls, self._info.params.frozen, self._info.params12.weakref_slot)
118
+ self._cls = add_slots(self._cls, self._info.params.frozen, self._info.params.weakref_slot)
119
119
 
120
120
  @lang.cached_function
121
121
  def process(self) -> type:
@@ -59,7 +59,7 @@ class DataMeta(abc.ABCMeta):
59
59
  # confer=frozenset(),
60
60
 
61
61
  metadata=None,
62
- **kwargs
62
+ **kwargs,
63
63
  ):
64
64
  cls = lang.super_meta(
65
65
  super(),
@@ -58,7 +58,7 @@ class Check(lang.Marker):
58
58
  pass
59
59
 
60
60
 
61
- def check(fn: ta.Union[ta.Callable[..., bool], staticmethod]) -> None:
61
+ def check(fn: ta.Callable[..., bool] | staticmethod) -> None:
62
62
  _append_cls_md(Check, fn)
63
63
 
64
64
 
@@ -43,5 +43,5 @@ class OrderProcessor(Processor):
43
43
  if set_new_attribute(self._cls, name, cmp_fn(name, op, self_tuple, other_tuple, globals=self._info.globals)): # noqa
44
44
  raise TypeError(
45
45
  f'Cannot overwrite attribute {name} in class {self._cls.__name__}. '
46
- f'Consider using functools.total_ordering'
46
+ f'Consider using functools.total_ordering',
47
47
  )
@@ -28,7 +28,6 @@ Params:
28
28
  weakref_slot: bool = False
29
29
  """
30
30
  import dataclasses as dc
31
- import sys
32
31
  import typing as ta
33
32
 
34
33
  from ... import lang
@@ -38,18 +37,16 @@ from .metadata import EMPTY_METADATA
38
37
  from .metadata import METADATA_ATTR
39
38
 
40
39
 
41
- IS_12 = sys.version_info[1] >= 12
42
-
43
-
44
40
  ##
45
41
 
46
42
 
47
43
  @dc.dataclass(frozen=True)
48
44
  class FieldExtras(lang.Final):
49
- coerce: ta.Optional[ta.Union[bool, ta.Callable[[ta.Any], ta.Any]]] = None
50
- check: ta.Optional[ta.Callable[[ta.Any], bool]] = None
51
- check_type: ta.Optional[bool] = None
45
+ coerce: bool | ta.Callable[[ta.Any], ta.Any] | None = None
46
+ check: ta.Callable[[ta.Any], bool] | None = None
47
+ check_type: bool | None = None
52
48
  override: bool = False
49
+ repr_fn: ta.Callable[[ta.Any], str | None] | None = None
53
50
 
54
51
 
55
52
  DEFAULT_FIELD_EXTRAS = FieldExtras()
@@ -82,37 +79,6 @@ def get_params(obj: ta.Any) -> Params:
82
79
  ##
83
80
 
84
81
 
85
- @dc.dataclass(frozen=True)
86
- class Params12(lang.Final):
87
- match_args: bool = True
88
- kw_only: bool = False
89
- slots: bool = False
90
- weakref_slot: bool = False
91
-
92
-
93
- DEFAULT_PARAMS12 = Params12()
94
-
95
-
96
- def get_params12(obj: ta.Any) -> Params12:
97
- if IS_12:
98
- p = get_params(obj)
99
- return Params12(
100
- match_args=p.match_args,
101
- kw_only=p.kw_only,
102
- slots=p.slots,
103
- weakref_slot=p.weakref_slot,
104
- )
105
-
106
- if (pcls := get_params_cls(obj)) is None:
107
- raise TypeError(pcls)
108
-
109
- md = pcls.__dict__.get(METADATA_ATTR, EMPTY_METADATA)
110
- return md.get(Params12, DEFAULT_PARAMS12)
111
-
112
-
113
- ##
114
-
115
-
116
82
  @dc.dataclass(frozen=True)
117
83
  class ParamsExtras(lang.Final):
118
84
  reorder: bool = False
@@ -22,10 +22,8 @@ from .metadata import METADATA_ATTR
22
22
  from .metadata import Metadata
23
23
  from .metadata import get_merged_metadata
24
24
  from .params import PARAMS_ATTR
25
- from .params import Params12
26
25
  from .params import ParamsExtras
27
26
  from .params import get_params
28
- from .params import get_params12
29
27
  from .params import get_params_extras
30
28
  from .utils import Namespace
31
29
 
@@ -55,7 +53,7 @@ class ClassInfo:
55
53
  return {}
56
54
 
57
55
  @cached.property
58
- def cls_annotations(self) -> dict[str, ta.Any]:
56
+ def cls_annotations(self) -> ta.Mapping[str, ta.Any]:
59
57
  return inspect.get_annotations(self._cls)
60
58
 
61
59
  ##
@@ -68,10 +66,6 @@ class ClassInfo:
68
66
  def cls_params(self) -> Params | None:
69
67
  return self._cls.__dict__.get(PARAMS_ATTR)
70
68
 
71
- @cached.property
72
- def params12(self) -> Params12:
73
- return get_params12(self._cls)
74
-
75
69
  @cached.property
76
70
  def params_extras(self) -> ParamsExtras:
77
71
  return get_params_extras(self._cls)
@@ -2,6 +2,7 @@ import dataclasses as dc
2
2
  import reprlib
3
3
  import typing as ta
4
4
 
5
+ from .params import get_field_extras
5
6
  from .processing import Processor
6
7
  from .utils import Namespace
7
8
  from .utils import create_fn
@@ -12,15 +13,32 @@ def repr_fn(
12
13
  fields: ta.Sequence[dc.Field],
13
14
  globals: Namespace,
14
15
  ) -> ta.Callable:
16
+ locals: dict[str, ta.Any] = {}
17
+ if any(get_field_extras(f).repr_fn is not None for f in fields):
18
+ lst: list[str] = []
19
+ for f in fields:
20
+ if (fex := get_field_extras(f)).repr_fn is not None:
21
+ locals[fn_name := f'__repr_fn__{f.name}'] = fex.repr_fn
22
+ lst.append(f"if (r := {fn_name}(self.{f.name})) is not None: l.append(f'{f.name}={{r}}')")
23
+ else:
24
+ lst.append(f"l.append(f'{f.name}={{self.{f.name}!r}}')")
25
+ src = [
26
+ 'l = []',
27
+ *lst,
28
+ 'return f"{self.__class__.__qualname__}({\", \".join(l)})"',
29
+ ]
30
+ else:
31
+ src = [
32
+ 'return f"{self.__class__.__qualname__}(' +
33
+ ', '.join([f"{f.name}={{self.{f.name}!r}}" for f in fields]) +
34
+ ')"',
35
+ ]
15
36
  fn = create_fn(
16
37
  '__repr__',
17
38
  ('self',),
18
- [
19
- 'return f"{self.__class__.__qualname__}(' +
20
- ', '.join([f"{f.name}={{self.{f.name}!r}}" for f in fields]) +
21
- ')"'
22
- ],
39
+ src,
23
40
  globals=globals,
41
+ locals=locals,
24
42
  )
25
43
  return reprlib.recursive_repr()(fn)
26
44
 
@@ -16,7 +16,7 @@ class OverridesProcessor(Processor):
16
16
  if not fx.override:
17
17
  continue
18
18
 
19
- if self._info.params12.slots:
19
+ if self._info.params.slots:
20
20
  raise TypeError
21
21
 
22
22
  self_name = '__dataclass_self__' if 'self' in self._info.fields else 'self'
@@ -85,7 +85,7 @@ class DocProcessor(Processor):
85
85
 
86
86
  class MatchArgsProcessor(Processor):
87
87
  def _process(self) -> None:
88
- if not self._info.params12.match_args:
88
+ if not self._info.params.match_args:
89
89
  return
90
90
 
91
91
  ifs = get_init_fields(self._info.fields.values())
@@ -55,8 +55,8 @@ def add_slots(
55
55
  inherited_slots.__contains__,
56
56
  itertools.chain(
57
57
  field_names,
58
- ('__weakref__',) if weakref_slot else ()
59
- )
58
+ ('__weakref__',) if weakref_slot else (),
59
+ ),
60
60
  ),
61
61
  )
62
62
 
@@ -16,8 +16,8 @@ def create_fn(
16
16
  args: ta.Sequence[str],
17
17
  body: ta.Sequence[str],
18
18
  *,
19
- globals: ta.Optional[Namespace] = None,
20
- locals: ta.Optional[Namespace] = None,
19
+ globals: Namespace | None = None,
20
+ locals: Namespace | None = None,
21
21
  return_type: lang.Maybe[ta.Any] = lang.empty(),
22
22
  ) -> ta.Callable:
23
23
  check.not_isinstance(args, str)
@@ -59,11 +59,11 @@ class FuncBuilder:
59
59
  args: ta.Sequence[str],
60
60
  body: ta.Sequence[str],
61
61
  *,
62
- locals: ta.Optional[Namespace] = None,
62
+ locals: Namespace | None = None,
63
63
  return_type: lang.Maybe[ta.Any] = lang.empty(),
64
64
  overwrite_error: bool = False,
65
65
  unconditional_add: bool = False,
66
- decorator: ta.Optional[str] = None,
66
+ decorator: str | None = None,
67
67
  ) -> None:
68
68
  if locals is not None:
69
69
  self.locals.update(locals)
@@ -27,19 +27,20 @@ def get_impl_func_cls_set(func: ta.Callable) -> ta.FrozenSet[type]:
27
27
  raise TypeError(f'Invalid impl func: {func!r}')
28
28
 
29
29
  _, cls = next(iter(ta.get_type_hints(func).items()))
30
- if rfl.is_union_type(cls):
31
- ret = frozenset(check.isinstance(arg, type) for arg in ta.get_args(cls))
30
+ rty = rfl.type_(cls)
31
+ if isinstance(rty, rfl.Union):
32
+ ret = frozenset(check.isinstance(arg, type) for arg in rty.args)
32
33
  else:
33
- ret = frozenset([check.isinstance(cls, type)])
34
+ ret = frozenset([check.isinstance(rty, type)])
34
35
 
35
36
  _IMPL_FUNC_CLS_SET_CACHE[func] = ret
36
37
  return ret
37
38
 
38
39
 
39
- def find_impl(cls: type, registry: ta.Mapping[type, T]) -> ta.Optional[T]:
40
+ def find_impl(cls: type, registry: ta.Mapping[type, T]) -> T | None:
40
41
  mro = c3.compose_mro(cls, registry.keys())
41
42
 
42
- match: ta.Optional[type] = None
43
+ match: type | None = None
43
44
  for t in mro:
44
45
  if match is not None:
45
46
  # If *match* is an implicit ABC but there is another unrelated, equally matching implicit ABC, refuse the
@@ -71,7 +72,7 @@ class Dispatcher(ta.Generic[T]):
71
72
  impls_by_arg_cls: dict[type, T] = {}
72
73
  self._impls_by_arg_cls = impls_by_arg_cls
73
74
 
74
- dispatch_cache: dict[ta.Any, ta.Optional[T]] = {}
75
+ dispatch_cache: dict[ta.Any, T | None] = {}
75
76
  self._get_dispatch_cache = lambda: dispatch_cache
76
77
 
77
78
  def cache_remove(k, self_ref=weakref.ref(self)):
@@ -87,7 +88,7 @@ class Dispatcher(ta.Generic[T]):
87
88
 
88
89
  weakref_ref_ = weakref.ref
89
90
 
90
- def dispatch(cls: type) -> ta.Optional[T]:
91
+ def dispatch(cls: type) -> T | None:
91
92
  nonlocal cache_token
92
93
 
93
94
  if cache_token is not None and (current_token := abc.get_cache_token()) != cache_token:
@@ -132,6 +133,6 @@ class Dispatcher(ta.Generic[T]):
132
133
  def cache_size(self) -> int:
133
134
  return len(self._get_dispatch_cache())
134
135
 
135
- dispatch: ta.Callable[[type], ta.Optional[T]]
136
+ dispatch: ta.Callable[[type], T | None]
136
137
 
137
138
  register: ta.Callable[[T, ta.Iterable[type]], T]
@@ -16,7 +16,7 @@ from .dispatch import get_impl_func_cls_set
16
16
  T = ta.TypeVar('T')
17
17
 
18
18
 
19
- def build_mro_dct(instance_cls: type, owner_cls: ta.Optional[type] = None) -> ta.Mapping[str, ta.Any]:
19
+ def build_mro_dct(instance_cls: type, owner_cls: type | None = None) -> ta.Mapping[str, ta.Any]:
20
20
  if owner_cls is None:
21
21
  owner_cls = instance_cls
22
22
  mro = instance_cls.__mro__[-2::-1]
@@ -89,7 +89,7 @@ class Method:
89
89
 
90
90
  return impl
91
91
 
92
- def build_attr_dispatcher(self, instance_cls: type, owner_cls: ta.Optional[type] = None) -> Dispatcher[str]:
92
+ def build_attr_dispatcher(self, instance_cls: type, owner_cls: type | None = None) -> Dispatcher[str]:
93
93
  disp: Dispatcher[str] = Dispatcher()
94
94
 
95
95
  mro_dct = build_mro_dct(instance_cls, owner_cls)
omlish/docker.py CHANGED
@@ -118,28 +118,30 @@ class ComposeConfig:
118
118
  self,
119
119
  prefix: str,
120
120
  *,
121
- compose_path: str | None = None,
121
+ file_path: str | None = None,
122
122
  ) -> None:
123
123
  super().__init__()
124
124
 
125
125
  self._prefix = prefix
126
- self._compose_path = compose_path
126
+ self._file_path = file_path
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._compose_path), 'r') as f:
130
+ with open(check.not_none(self._file_path), 'r') as f:
131
131
  buf = f.read()
132
- dct = yaml.safe_load(buf)
132
+ return yaml.safe_load(buf)
133
133
 
134
+ @lang.cached_function
135
+ def get_services(self) -> ta.Mapping[str, ta.Any]:
134
136
  ret = {}
135
- for n, c in dct['services'].items():
137
+ for n, c in self.get_config()['services'].items():
136
138
  check.state(n.startswith(self._prefix))
137
139
  ret[n[len(self._prefix):]] = c
138
140
 
139
141
  return ret
140
142
 
141
143
 
142
- def timebomb_payload(delay_s: int | float, name: str = 'omlish-timebomb') -> str:
144
+ def timebomb_payload(delay_s: float, name: str = 'omlish-docker-timebomb') -> str:
143
145
  return (
144
146
  '('
145
147
  f'echo {shlex.quote(name)} && '
omlish/dynamic.py CHANGED
@@ -49,10 +49,10 @@ class Var(ta.Generic[T]):
49
49
 
50
50
  def __init__(
51
51
  self,
52
- default: ta.Union[type[MISSING], T] = MISSING, # type: ignore
52
+ default: type[MISSING] | T = MISSING, # type: ignore
53
53
  *,
54
- new: ta.Union[ta.Callable[[], T], type[MISSING]] = MISSING,
55
- validate: ta.Optional[ta.Callable[[T], None]] = None,
54
+ new: ta.Callable[[], T] | type[MISSING] = MISSING,
55
+ validate: ta.Callable[[T], None] | None = None,
56
56
  ) -> None:
57
57
  super().__init__()
58
58
 
@@ -60,7 +60,7 @@ class Var(ta.Generic[T]):
60
60
  raise TypeError('Cannot set both default and new')
61
61
  elif default is not MISSING:
62
62
  new = lambda: default # type: ignore
63
- self._new: ta.Union[type[MISSING], ta.Callable[[], T]] = new
63
+ self._new: type[MISSING] | ta.Callable[[], T] = new
64
64
  self._validate = validate
65
65
  self._bindings_by_frame: ta.MutableMapping[types.FrameType, ta.MutableMapping[int, Binding]] = weakref.WeakValueDictionary() # noqa
66
66
 
@@ -166,7 +166,7 @@ class Binding(ta.Generic[T]):
166
166
 
167
167
  def __enter__(self) -> T:
168
168
  frame = sys._getframe(self._offset).f_back # noqa
169
- lag_frame: ta.Optional[types.FrameType] = frame
169
+ lag_frame: types.FrameType | None = frame
170
170
  while lag_frame is not None:
171
171
  for cur_depth in range(_MAX_HOIST_DEPTH + 1):
172
172
  if lag_frame is None:
@@ -115,7 +115,7 @@ class Attrs(Item):
115
115
  coerce=lambda o: col.frozendict(
116
116
  (check.not_empty(check.isinstance(k, str)), Value.of(v)) # type: ignore
117
117
  for k, v in check.isinstance(o, ta.Mapping).items()
118
- )
118
+ ),
119
119
  )
120
120
 
121
121
  @classmethod
omlish/graphs/trees.py CHANGED
@@ -57,7 +57,7 @@ class BasicTreeAnalysis(ta.Generic[NodeT]):
57
57
  self._dict_fac: ta.Callable[..., ta.MutableMapping[NodeT, ta.Any]] = col.IdentityKeyDict if identity else dict
58
58
  self._idx_seq_fac: ta.Callable[..., col.IndexedSeq[NodeT]] = functools.partial(col.IndexedSeq, identity=identity) # noqa
59
59
 
60
- def walk(cur: NodeT, parent: ta.Optional[NodeT]) -> None:
60
+ def walk(cur: NodeT, parent: NodeT | None) -> None:
61
61
  check.not_none(cur)
62
62
  if cur in node_set:
63
63
  raise DuplicateNodeException(cur)
@@ -78,9 +78,9 @@ class BasicTreeAnalysis(ta.Generic[NodeT]):
78
78
 
79
79
  nodes: list[NodeT] = []
80
80
  node_set: ta.MutableSet[NodeT] = self._set_fac() # type: ignore
81
- children_by_node: ta.MutableMapping[ta.Optional[NodeT], ta.Sequence[NodeT]] = self._dict_fac() # type: ignore
81
+ children_by_node: ta.MutableMapping[NodeT | None, ta.Sequence[NodeT]] = self._dict_fac() # type: ignore
82
82
  child_sets_by_node: ta.MutableMapping[ta.Optional[NodeT], ta.AbstractSet[NodeT]] = self._dict_fac() # type: ignore # noqa
83
- parents_by_node: ta.MutableMapping[NodeT, ta.Optional[NodeT]] = self._dict_fac() # type: ignore
83
+ parents_by_node: ta.MutableMapping[NodeT, NodeT | None] = self._dict_fac() # type: ignore
84
84
 
85
85
  children_by_node[None] = [root]
86
86
  child_sets_by_node[None] = self._set_fac([root]) # type: ignore
@@ -89,10 +89,10 @@ class BasicTreeAnalysis(ta.Generic[NodeT]):
89
89
 
90
90
  self._nodes = self._idx_seq_fac(nodes) # type: ignore
91
91
  self._node_set: ta.AbstractSet[NodeT] = node_set
92
- self._children_by_node: ta.Mapping[ta.Optional[NodeT], col.IndexedSeq[NodeT]] = self._dict_fac( # type: ignore
92
+ self._children_by_node: ta.Mapping[NodeT | None, col.IndexedSeq[NodeT]] = self._dict_fac( # type: ignore
93
93
  [(n, self._idx_seq_fac(cs)) for n, cs in children_by_node.items()])
94
- self._child_sets_by_node: ta.Mapping[ta.Optional[NodeT], ta.AbstractSet[NodeT]] = child_sets_by_node
95
- self._parents_by_node: ta.Mapping[NodeT, ta.Optional[NodeT]] = parents_by_node
94
+ self._child_sets_by_node: ta.Mapping[NodeT | None, ta.AbstractSet[NodeT]] = child_sets_by_node
95
+ self._parents_by_node: ta.Mapping[NodeT, NodeT | None] = parents_by_node
96
96
 
97
97
  @property
98
98
  def root(self) -> NodeT:
@@ -115,27 +115,24 @@ class BasicTreeAnalysis(ta.Generic[NodeT]):
115
115
  return self._node_set
116
116
 
117
117
  @property
118
- def children_by_node(self) -> ta.Mapping[ta.Optional[NodeT], col.IndexedSeq[NodeT]]:
118
+ def children_by_node(self) -> ta.Mapping[NodeT | None, col.IndexedSeq[NodeT]]:
119
119
  return self._children_by_node
120
120
 
121
121
  @property
122
- def child_sets_by_node(self) -> ta.Mapping[ta.Optional[NodeT], ta.AbstractSet[NodeT]]:
122
+ def child_sets_by_node(self) -> ta.Mapping[NodeT | None, ta.AbstractSet[NodeT]]:
123
123
  return self._child_sets_by_node
124
124
 
125
125
  @property
126
- def parents_by_node(self) -> ta.Mapping[NodeT, ta.Optional[NodeT]]:
126
+ def parents_by_node(self) -> ta.Mapping[NodeT, NodeT | None]:
127
127
  return self._parents_by_node
128
128
 
129
129
  @classmethod
130
130
  def from_parents(
131
131
  cls,
132
- src: ta.Union[
133
- ta.Mapping[NodeT, ta.Optional[NodeT]],
134
- ta.Iterable[tuple[NodeT, ta.Optional[NodeT]]],
135
- ],
132
+ src: ta.Mapping[NodeT, NodeT | None] | ta.Iterable[tuple[NodeT, NodeT | None]],
136
133
  *,
137
134
  identity: bool = False,
138
- **kwargs
135
+ **kwargs,
139
136
  ) -> 'BasicTreeAnalysis[NodeT]':
140
137
  pairs: ta.Sequence[tuple[NodeT, NodeT]]
141
138
  if isinstance(src, ta.Mapping):
@@ -166,13 +163,10 @@ class BasicTreeAnalysis(ta.Generic[NodeT]):
166
163
  @classmethod
167
164
  def from_children(
168
165
  cls,
169
- src: ta.Union[
170
- ta.Mapping[NodeT, ta.Iterable[NodeT]],
171
- ta.Iterable[tuple[NodeT, ta.Iterable[NodeT]]],
172
- ],
166
+ src: ta.Mapping[NodeT, ta.Iterable[NodeT]] | ta.Iterable[tuple[NodeT, ta.Iterable[NodeT]]],
173
167
  *,
174
168
  identity: bool = False,
175
- **kwargs
169
+ **kwargs,
176
170
  ) -> 'BasicTreeAnalysis[NodeT]':
177
171
  pairs: ta.Sequence[tuple[NodeT, ta.Sequence[NodeT]]]
178
172
  if isinstance(src, ta.Mapping):
@@ -222,7 +216,7 @@ class BasicTreeAnalysis(ta.Generic[NodeT]):
222
216
  return ret # type: ignore
223
217
 
224
218
  def iter_ancestors(self, node: NodeT) -> NodeGenerator[NodeT]:
225
- cur: ta.Optional[NodeT] = node
219
+ cur: NodeT | None = node
226
220
  while True:
227
221
  cur = self.parents_by_node.get(cur) # type: ignore
228
222
  if cur is None:
@@ -232,7 +226,7 @@ class BasicTreeAnalysis(ta.Generic[NodeT]):
232
226
  def get_lineage(self, node: NodeT) -> col.IndexedSeq[NodeT]:
233
227
  return self._idx_seq_fac(reversed([node, *self.iter_ancestors(node)]))
234
228
 
235
- def get_first_parent_of_type(self, node: NodeT, ty: type[T]) -> ta.Optional[T]:
229
+ def get_first_parent_of_type(self, node: NodeT, ty: type[T]) -> T | None:
236
230
  for cur in self.iter_ancestors(node):
237
231
  if isinstance(cur, ty):
238
232
  return cur
omlish/inject/elements.py CHANGED
@@ -25,7 +25,7 @@ class Elements(lang.Final):
25
25
  yield from c
26
26
 
27
27
 
28
- def as_elements(*args: ta.Union[Element, Elements]) -> Elements:
28
+ def as_elements(*args: Element | Elements) -> Elements:
29
29
  es: set[Element] = set()
30
30
  cs: set['Elements'] = set()
31
31
  for a in args:
@@ -13,7 +13,7 @@ class KeyException(Exception):
13
13
  key: Key
14
14
 
15
15
  source: ta.Any = None
16
- name: ta.Optional[str] = None
16
+ name: str | None = None
17
17
 
18
18
 
19
19
  @dc.dataclass()
@@ -45,7 +45,7 @@ class InjectorImpl(Injector, lang.Final):
45
45
  super().__init__()
46
46
 
47
47
  self._ec = check.isinstance(ec, ElementCollection)
48
- self._p: ta.Optional[InjectorImpl] = check.isinstance(p, (InjectorImpl, None))
48
+ self._p: InjectorImpl | None = check.isinstance(p, (InjectorImpl, None))
49
49
 
50
50
  self._internal_consts: dict[Key, ta.Any] = {
51
51
  Key(Injector): self,
@@ -52,7 +52,7 @@ def build_kwargs_target(
52
52
  obj: ta.Any,
53
53
  *,
54
54
  skip_args: int = 0,
55
- skip_kwargs: ta.Optional[ta.Iterable[ta.Any]] = None,
55
+ skip_kwargs: ta.Iterable[ta.Any] | None = None,
56
56
  raw_optional: bool = False,
57
57
  ) -> KwargsTarget:
58
58
  sig = signature(obj)
omlish/inject/injector.py CHANGED
@@ -31,7 +31,7 @@ class Injector(lang.Abstract):
31
31
 
32
32
  def __getitem__(
33
33
  self,
34
- target: ta.Union[Key[T], type[T]],
34
+ target: Key[T] | type[T],
35
35
  ) -> T:
36
36
  return self.provide(target)
37
37