omlish 0.0.0.dev273__py3-none-any.whl → 0.0.0.dev275__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 CHANGED
@@ -323,7 +323,7 @@
323
323
  "module": ".secrets.pwgen",
324
324
  "attr": "_CLI_MODULE",
325
325
  "file": "omlish/secrets/pwgen.py",
326
- "line": 75,
326
+ "line": 78,
327
327
  "value": {
328
328
  "$omdev.cli.types.CliModule": {
329
329
  "cmd_name": "pwgen",
omlish/__about__.py CHANGED
@@ -1,5 +1,5 @@
1
- __version__ = '0.0.0.dev273'
2
- __revision__ = '44a0fe838de0f8002790aea22f754c26ce424e79'
1
+ __version__ = '0.0.0.dev275'
2
+ __revision__ = 'fd5c964d07819bc7ca6e9da1e21d2032d1e2665c'
3
3
 
4
4
 
5
5
  #
@@ -1,4 +1,3 @@
1
- import contextlib
2
1
  import operator as op
3
2
  import typing as ta
4
3
  import weakref
@@ -17,6 +16,7 @@ V = ta.TypeVar('V')
17
16
  class IdentityWrapper(ta.Generic[T]):
18
17
  def __init__(self, value: T) -> None:
19
18
  super().__init__()
19
+
20
20
  self._value = value
21
21
 
22
22
  def __repr__(self) -> str:
@@ -39,6 +39,7 @@ class IdentityWrapper(ta.Generic[T]):
39
39
  class IdentityKeyDict(ta.MutableMapping[K, V]):
40
40
  def __init__(self, *args, **kwargs) -> None:
41
41
  super().__init__()
42
+
42
43
  self._dict: dict[int, tuple[K, V]] = {}
43
44
  for k, v in lang.yield_dict_init(*args, **kwargs):
44
45
  self[k] = v
@@ -75,6 +76,7 @@ class IdentityKeyDict(ta.MutableMapping[K, V]):
75
76
  class IdentitySet(ta.MutableSet[T]):
76
77
  def __init__(self, init: ta.Iterable[T] | None = None) -> None:
77
78
  super().__init__()
79
+
78
80
  self._dict: dict[int, T] = {}
79
81
  if init is not None:
80
82
  for item in init:
@@ -94,8 +96,10 @@ class IdentitySet(ta.MutableSet[T]):
94
96
  self._dict[id(item)] = item
95
97
 
96
98
  def discard(self, item: T) -> None:
97
- with contextlib.suppress(KeyError):
99
+ try:
98
100
  del self._dict[id(item)]
101
+ except KeyError:
102
+ pass
99
103
 
100
104
  def update(self, items: ta.Iterable[T]) -> None:
101
105
  for item in items:
@@ -111,7 +115,26 @@ class IdentitySet(ta.MutableSet[T]):
111
115
  return iter(self._dict.values())
112
116
 
113
117
 
114
- class IdentityWeakSet(weakref.WeakSet):
115
- def __init__(self, init=None):
118
+ class IdentityWeakSet(ta.MutableSet[T]):
119
+ def __init__(self, init: ta.Iterable[T] | None = None) -> None:
116
120
  super().__init__()
117
- self.data = IdentitySet(init) # type: ignore
121
+
122
+ self._dict: weakref.WeakValueDictionary[int, T] = weakref.WeakValueDictionary()
123
+
124
+ def add(self, value):
125
+ self._dict[id(value)] = value
126
+
127
+ def discard(self, value):
128
+ try:
129
+ del self._dict[id(value)]
130
+ except KeyError:
131
+ pass
132
+
133
+ def __contains__(self, x):
134
+ return id(x) in self._dict
135
+
136
+ def __len__(self):
137
+ return len(self._dict)
138
+
139
+ def __iter__(self):
140
+ return self._dict.values()
@@ -103,6 +103,7 @@ def dataclass( # noqa
103
103
  cache_hash=MISSING,
104
104
  generic_init=MISSING,
105
105
  override=MISSING,
106
+ repr_id=MISSING,
106
107
  ):
107
108
  def wrap(cls):
108
109
  pkw = dict(
@@ -126,6 +127,7 @@ def dataclass( # noqa
126
127
  cache_hash=cache_hash,
127
128
  generic_init=generic_init,
128
129
  override=override,
130
+ repr_id=repr_id,
129
131
  )))
130
132
  pex = ParamsExtras(**epk)
131
133
 
@@ -175,6 +177,7 @@ def make_dataclass( # noqa
175
177
  cache_hash=MISSING,
176
178
  generic_init=MISSING,
177
179
  override=MISSING,
180
+ repr_id=MISSING,
178
181
  ):
179
182
  if namespace is None:
180
183
  namespace = {}
@@ -236,6 +239,7 @@ def make_dataclass( # noqa
236
239
  cache_hash=cache_hash,
237
240
  generic_init=generic_init,
238
241
  override=override,
242
+ repr_id=repr_id,
239
243
  )
240
244
 
241
245
 
@@ -249,6 +253,7 @@ def extra_params( # noqa
249
253
  cache_hash=MISSING,
250
254
  generic_init=MISSING,
251
255
  override=MISSING,
256
+ repr_id=MISSING,
252
257
  ):
253
258
  def inner(cls):
254
259
  if PARAMS_ATTR in cls.__dict__:
@@ -266,6 +271,7 @@ def extra_params( # noqa
266
271
  cache_hash=cache_hash,
267
272
  generic_init=generic_init,
268
273
  override=override,
274
+ repr_id=repr_id,
269
275
  ))
270
276
 
271
277
  return cls
@@ -93,6 +93,7 @@ class ParamsExtras(lang.Final):
93
93
  cache_hash: bool = False
94
94
  generic_init: bool = False
95
95
  override: bool = False
96
+ repr_id: bool = False
96
97
 
97
98
 
98
99
  DEFAULT_PARAMS_EXTRAS = ParamsExtras()
@@ -149,16 +149,20 @@ class ClassInfo:
149
149
  def generic_mro_lookup(self) -> ta.Mapping[type, rfl.Type]:
150
150
  return col.make_map(((check.not_none(rfl.get_concrete_type(g)), g) for g in self.generic_mro), strict=True)
151
151
 
152
+ def generic_replaced_field_type(self, fn: str) -> rfl.Type:
153
+ f = self.fields[fn]
154
+ fo = self.field_owners[f.name]
155
+ go = self.generic_mro_lookup[fo]
156
+ tvr = rfl.get_type_var_replacements(go)
157
+ fty = rfl.type_(f.type)
158
+ rty = rfl.replace_type_vars(fty, tvr, update_aliases=True)
159
+ return rty
160
+
152
161
  @cached.property
153
162
  def generic_replaced_field_types(self) -> ta.Mapping[str, rfl.Type]:
154
163
  ret: dict[str, ta.Any] = {}
155
164
  for f in self.fields.values():
156
- fo = self.field_owners[f.name]
157
- go = self.generic_mro_lookup[fo]
158
- tvr = rfl.get_type_var_replacements(go)
159
- fty = rfl.type_(f.type)
160
- rty = rfl.replace_type_vars(fty, tvr, update_aliases=True)
161
- ret[f.name] = rty
165
+ ret[f.name] = self.generic_replaced_field_type(f.name)
162
166
  return ret
163
167
 
164
168
  @cached.property
@@ -12,11 +12,17 @@ from .utils import set_new_attribute
12
12
  def repr_fn(
13
13
  fields: ta.Sequence[dc.Field],
14
14
  globals: Namespace, # noqa
15
+ *,
16
+ repr_id: bool = False,
15
17
  ) -> ta.Callable:
16
18
  locals: dict[str, ta.Any] = {} # noqa
17
19
 
18
20
  fields = sorted(fields, key=lambda f: get_field_extras(f).repr_priority or 0)
19
21
 
22
+ prefix_src = '{self.__class__.__qualname__}'
23
+ if repr_id:
24
+ prefix_src += '@{hex(id(self))[2:]}'
25
+
20
26
  if any(get_field_extras(f).repr_fn is not None for f in fields):
21
27
  lst: list[str] = []
22
28
  for f in fields:
@@ -29,12 +35,12 @@ def repr_fn(
29
35
  src = [
30
36
  'l = []',
31
37
  *lst,
32
- 'return f"{self.__class__.__qualname__}({", ".join(l)})"',
38
+ f'return f"{prefix_src}({{", ".join(l)}})"',
33
39
  ]
34
40
 
35
41
  else:
36
42
  src = [
37
- 'return f"{self.__class__.__qualname__}(' +
43
+ f'return f"{prefix_src}(' +
38
44
  ', '.join([f'{f.name}={{self.{f.name}!r}}' for f in fields]) +
39
45
  ')"',
40
46
  ]
@@ -56,4 +62,5 @@ class ReprProcessor(Processor):
56
62
  return
57
63
 
58
64
  flds = [f for f in self._info.instance_fields if f.repr]
59
- set_new_attribute(self._cls, '__repr__', repr_fn(flds, self._info.globals)) # noqa
65
+ rfn = repr_fn(flds, self._info.globals, repr_id=self._info.params_extras.repr_id)
66
+ set_new_attribute(self._cls, '__repr__', rfn) # noqa
@@ -72,9 +72,14 @@ def get_dataclass_field_infos(
72
72
  else:
73
73
  um_name = field.name
74
74
 
75
+ fmd: FieldMetadata | None = field.metadata.get(FieldMetadata)
76
+
75
77
  f_ty: ta.Any
76
- if (cpx := dc_rf.cls_params_extras) is not None and cpx.generic_init:
77
- f_ty = dc_rf.generic_replaced_field_annotations[field.name]
78
+ if (
79
+ ((cpx := dc_rf.cls_params_extras) is not None and cpx.generic_init) or
80
+ (fmd is not None and fmd.options.generic_replace)
81
+ ):
82
+ f_ty = rfl.to_annotation(dc_rf.generic_replaced_field_type(field.name))
78
83
  else:
79
84
  f_ty = type_hints[field.name]
80
85
 
@@ -91,7 +96,7 @@ def get_dataclass_field_infos(
91
96
  )
92
97
 
93
98
  has_set_name = False
94
- if (fmd := field.metadata.get(FieldMetadata)) is not None:
99
+ if fmd is not None:
95
100
  fi_kw.update(
96
101
  metadata=fmd,
97
102
  )
@@ -22,6 +22,8 @@ class FieldOptions:
22
22
 
23
23
  embed: bool = False
24
24
 
25
+ generic_replace: bool = False
26
+
25
27
  no_marshal: bool = False
26
28
  no_unmarshal: bool = False
27
29
 
omlish/secrets/all.py CHANGED
@@ -14,3 +14,11 @@ from .secrets import ( # noqa
14
14
  secret_field,
15
15
  secret_repr,
16
16
  )
17
+
18
+
19
+ ##
20
+
21
+
22
+ from ..lang.imports import _register_conditional_import # noqa
23
+
24
+ _register_conditional_import('..marshal', '.marshal', __package__)
omlish/secrets/marshal.py CHANGED
@@ -16,6 +16,9 @@ from .secrets import SecretRef
16
16
  from .secrets import SecretRefOrStr
17
17
 
18
18
 
19
+ ##
20
+
21
+
19
22
  class StrOrSecretRefMarshalerUnmarshaler(msh.Marshaler, msh.Unmarshaler):
20
23
  def marshal(self, ctx: msh.MarshalContext, o: ta.Any) -> msh.Value:
21
24
  if isinstance(o, str):
omlish/secrets/pwgen.py CHANGED
@@ -16,6 +16,9 @@ import string
16
16
  import typing as ta
17
17
 
18
18
 
19
+ ##
20
+
21
+
19
22
  CHAR_CLASSES: ta.Mapping[str, str] = {
20
23
  'lower': string.ascii_lowercase,
21
24
  'upper': string.ascii_uppercase,
omlish/secrets/pwhash.py CHANGED
@@ -27,6 +27,9 @@ import hmac
27
27
  import secrets
28
28
 
29
29
 
30
+ ##
31
+
32
+
30
33
  SALT_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
31
34
  DEFAULT_PBKDF2_ITERATIONS = 600_000
32
35
 
omlish/secrets/ssl.py CHANGED
@@ -3,6 +3,9 @@
3
3
  import dataclasses as dc
4
4
 
5
5
 
6
+ ##
7
+
8
+
6
9
  @dc.dataclass(frozen=True)
7
10
  class SslCert:
8
11
  key_file: str
@@ -9,6 +9,9 @@ import tempfile
9
9
  import typing as ta
10
10
 
11
11
 
12
+ ##
13
+
14
+
12
15
  class SubprocessFileInput(ta.NamedTuple):
13
16
  file_path: str
14
17
  pass_fds: ta.Sequence[int]
omlish/secrets/tempssl.py CHANGED
@@ -12,6 +12,9 @@ from ..subprocesses.run import SubprocessRunOutput
12
12
  from .ssl import SslCert
13
13
 
14
14
 
15
+ ##
16
+
17
+
15
18
  class TempSslCert(ta.NamedTuple):
16
19
  cert: SslCert
17
20
  temp_dir: str
@@ -23,3 +23,11 @@ from .values import ( # noqa
23
23
 
24
24
  ScalarTypedValue,
25
25
  )
26
+
27
+
28
+ ##
29
+
30
+
31
+ from ..lang.imports import _register_conditional_import # noqa
32
+
33
+ _register_conditional_import('..marshal', '.marshal', __package__)
@@ -23,6 +23,13 @@ UniqueTypedValueU = ta.TypeVar('UniqueTypedValueU', bound='UniqueTypedValue')
23
23
 
24
24
 
25
25
  class TypedValuesAccessor(lang.Abstract, ta.Generic[TypedValueT]):
26
+ def __iter__(self):
27
+ raise TypeError(
28
+ 'TypedValuesAccessor does not implement __iter__ - it is reserved for implementation by subclasses.',
29
+ )
30
+
31
+ #
32
+
26
33
  @ta.final
27
34
  def __contains__(self, cls: type[TypedValueU]) -> bool:
28
35
  raise NotImplementedError
@@ -29,23 +29,29 @@ class TypedValues(
29
29
  ta.Generic[TypedValueT],
30
30
  ):
31
31
  def __init__(self, *tvs: TypedValueT, override: bool = False) -> None:
32
+ if hasattr(self, '_tup'):
33
+ # When __new__ returns the empty singleton __init__ will still be called.
34
+ if self is not self._EMPTY:
35
+ raise RuntimeError
36
+ return
37
+
32
38
  super().__init__()
33
39
 
34
40
  tmp: list = []
35
41
  udct: dict = {}
36
42
  for tv in tvs:
37
43
  if isinstance(tv, UniqueTypedValue):
38
- uoc = tv._unique_typed_value_cls # noqa
44
+ utvc = tv._unique_typed_value_cls # noqa
39
45
  if not override:
40
46
  try:
41
- exu = udct[uoc]
47
+ exu = udct[utvc]
42
48
  except KeyError:
43
49
  pass
44
50
  else:
45
- raise DuplicateUniqueTypedValueError(uoc, tv, check.single(exu))
46
- ulst = udct.setdefault(uoc, [])
51
+ raise DuplicateUniqueTypedValueError(utvc, tv, check.single(exu))
52
+ ulst = udct.setdefault(utvc, [])
47
53
  ulst.append(tv)
48
- tmp.append((tv, len(ulst)))
54
+ tmp.append((utvc, tv, ulst, len(ulst)))
49
55
  elif isinstance(tv, TypedValue):
50
56
  tmp.append(tv)
51
57
  else:
@@ -53,42 +59,105 @@ class TypedValues(
53
59
 
54
60
  lst: list = []
55
61
  dct: dict = {}
56
- for tv in tmp:
57
- if isinstance(tv, tuple):
58
- uo, idx = tv # type: ignore
59
- ulst = udct[uo._unique_typed_value_cls] # noqa
62
+ for obj in tmp:
63
+ if isinstance(obj, tuple):
64
+ utvc, tv, ulst, idx = obj
60
65
  if idx == len(ulst):
61
- lst.append(uo)
62
- dct[uo._unique_typed_value_cls] = uo # noqa
63
- dct[type(uo)] = uo
66
+ lst.append(tv)
67
+ dct[utvc] = tv
68
+ dct[type(tv)] = tv
64
69
  else:
70
+ tv = obj
65
71
  lst.append(tv)
66
72
  dct.setdefault(type(tv), []).append(tv)
67
73
 
68
- self._lst = lst
69
- self._dct = dct
74
+ self._tup: tuple[TypedValueT, ...] = tuple(lst)
75
+ self._dct: dict[type[TypedValueT], TypedValueT | tuple[TypedValueT, ...]] = {
76
+ k: tuple(v) if isinstance(v, list) else v
77
+ for k, v in dct.items()
78
+ }
79
+
80
+ #
81
+
82
+ _EMPTY: ta.ClassVar['TypedValues']
70
83
 
71
- self._any_dct: dict[type, ta.Sequence[ta.Any]] = {}
84
+ @classmethod
85
+ def empty(cls) -> 'TypedValues':
86
+ return cls._EMPTY
87
+
88
+ def __new__(cls, *tvs, **kwargs): # noqa
89
+ if not tvs:
90
+ try:
91
+ return cls._EMPTY
92
+ except AttributeError:
93
+ pass
94
+ return super().__new__(cls)
95
+
96
+ #
72
97
 
73
98
  def without(self, *tys: type) -> ta.Iterator[TypedValueT]:
74
- for o in self._lst:
99
+ for o in self._tup:
75
100
  if isinstance(o, tys):
76
101
  continue
77
102
  yield o
78
103
 
104
+ #
105
+
106
+ def update(self, *tvs, override: bool = False) -> 'TypedValues':
107
+ return TypedValues(*self._tup, *tvs, override=override)
108
+
109
+ def discard(self, *tys: type) -> 'TypedValues':
110
+ return TypedValues(*self.without(*tys))
111
+
112
+ #
113
+
79
114
  def __repr__(self) -> str:
80
- return f'{self.__class__.__name__}({", ".join(map(repr, self._lst))})'
115
+ return f'{self.__class__.__name__}({", ".join(map(repr, self._tup))})'
116
+
117
+ #
118
+
119
+ _set: frozenset[TypedValueT]
120
+
121
+ def to_set(self) -> frozenset[TypedValueT]:
122
+ try:
123
+ return self._set
124
+ except AttributeError:
125
+ pass
126
+ s = frozenset(self._tup)
127
+ self._set = s
128
+ return s
129
+
130
+ #
131
+
132
+ _hash: int
133
+
134
+ def __hash__(self) -> int:
135
+ try:
136
+ return self._hash
137
+ except AttributeError:
138
+ pass
139
+ h = hash(self._tup)
140
+ self._hash = h
141
+ return h
142
+
143
+ def __eq__(self, other):
144
+ if not isinstance(other, type(self)):
145
+ return NotImplemented
146
+ return (
147
+ other is self or
148
+ other._tup == self._tup
149
+ )
81
150
 
82
151
  #
83
152
 
84
153
  def __iter__(self) -> ta.Iterator[TypedValueT]:
85
- return iter(self._lst)
154
+ return iter(self._tup)
86
155
 
87
156
  def __len__(self) -> int:
88
- return len(self._lst)
157
+ return len(self._tup)
89
158
 
90
159
  def __bool__(self) -> bool:
91
- return bool(self._lst)
160
+ return bool(self._tup)
92
161
 
93
162
  #
94
163
 
@@ -97,7 +166,7 @@ class TypedValues(
97
166
 
98
167
  def _typed_value_getitem(self, key):
99
168
  if isinstance(key, int):
100
- return self._lst[key]
169
+ return self._tup[key]
101
170
  elif isinstance(key, type):
102
171
  return self._dct[check.issubclass(key, TypedValue)]
103
172
  else:
@@ -111,15 +180,25 @@ class TypedValues(
111
180
  if issubclass(key, UniqueTypedValue):
112
181
  return default
113
182
  elif default is not None:
114
- return list(default)
183
+ return tuple(default)
115
184
  else:
116
- return []
185
+ return ()
186
+
187
+ _any_dct: dict[type, tuple[TypedValueT, ...]]
117
188
 
118
189
  def _typed_value_get_any(self, cls):
119
190
  try:
120
- return self._any_dct[cls]
191
+ any_dct = self._any_dct
192
+ except AttributeError:
193
+ any_dct = {}
194
+ self._any_dct = any_dct
195
+ try:
196
+ return any_dct[cls]
121
197
  except KeyError:
122
198
  pass
123
- ret = [tv for tv in self if isinstance(tv, cls)]
124
- self._any_dct[cls] = ret
199
+ ret = tuple(tv for tv in self if isinstance(tv, cls))
200
+ any_dct[cls] = ret
125
201
  return ret
202
+
203
+
204
+ TypedValues._EMPTY = TypedValues() # noqa
@@ -0,0 +1,139 @@
1
+ from omlish import check
2
+ from omlish import dataclasses as dc
3
+ from omlish import lang
4
+ from omlish import marshal as msh
5
+ from omlish import reflect as rfl
6
+ from omlish.funcs import match as mfs
7
+
8
+ from .collection import TypedValues
9
+ from .values import ScalarTypedValue
10
+ from .values import TypedValue
11
+
12
+
13
+ ##
14
+
15
+
16
+ def _build_typed_value_poly(rty: rfl.Type) -> msh.Polymorphism:
17
+ ty: type[TypedValue] = check.issubclass(check.isinstance(rty, type), TypedValue)
18
+ check.state(lang.is_abstract_class(ty))
19
+ return msh.polymorphism_from_subclasses(
20
+ ty,
21
+ naming=msh.Naming.SNAKE,
22
+ strip_suffix='auto',
23
+ )
24
+
25
+
26
+ class TypedValueMarshalerFactory(msh.MarshalerFactoryMatchClass):
27
+ @mfs.simple(lambda _, ctx, rty: (
28
+ isinstance(rty, type) and
29
+ issubclass(rty, ScalarTypedValue) and
30
+ not lang.is_abstract_class(rty)
31
+ ))
32
+ def _build_scalar(self, ctx: msh.MarshalContext, rty: rfl.Type) -> msh.Marshaler:
33
+ dc_rfl = dc.reflect(check.isinstance(rty, type))
34
+ v_rty = check.single(dc_rfl.generic_replaced_field_annotations.values())
35
+ v_m = ctx.make(v_rty)
36
+ return msh.WrappedMarshaler(lambda _, o: o.v, v_m)
37
+
38
+ @mfs.simple(lambda _, ctx, rty: (
39
+ isinstance(rty, type) and
40
+ issubclass(rty, TypedValue) and
41
+ lang.is_abstract_class(rty)
42
+ ))
43
+ def _build_abstract(self, ctx: msh.MarshalContext, rty: rfl.Type) -> msh.Marshaler:
44
+ return msh.make_polymorphism_marshaler(
45
+ _build_typed_value_poly(rty).impls,
46
+ msh.WrapperTypeTagging(),
47
+ ctx,
48
+ )
49
+
50
+
51
+ class TypedValueUnmarshalerFactory(msh.UnmarshalerFactoryMatchClass):
52
+ @mfs.simple(lambda _, ctx, rty: (
53
+ isinstance(rty, type) and
54
+ issubclass(rty, ScalarTypedValue) and
55
+ not lang.is_abstract_class(rty)
56
+ ))
57
+ def _build_scalar(self, ctx: msh.UnmarshalContext, rty: rfl.Type) -> msh.Unmarshaler:
58
+ rty = check.isinstance(rty, type)
59
+ dc_rfl = dc.reflect(rty)
60
+ v_rty = check.single(dc_rfl.generic_replaced_field_annotations.values())
61
+ v_u = ctx.make(v_rty)
62
+ return msh.WrappedUnmarshaler(lambda _, v: rty(v), v_u)
63
+
64
+ @mfs.simple(lambda _, ctx, rty: (
65
+ isinstance(rty, type) and
66
+ issubclass(rty, TypedValue) and
67
+ lang.is_abstract_class(rty)
68
+ ))
69
+ def _build_abstract(self, ctx: msh.UnmarshalContext, rty: rfl.Type) -> msh.Unmarshaler:
70
+ return msh.make_polymorphism_unmarshaler(
71
+ _build_typed_value_poly(rty).impls,
72
+ msh.WrapperTypeTagging(),
73
+ ctx,
74
+ )
75
+
76
+
77
+ ##
78
+
79
+
80
+ def _build_typed_values_impls(rty: rfl.Type) -> msh.Impls:
81
+ gty = check.isinstance(rty, rfl.Generic)
82
+ check.is_(gty.cls, TypedValues)
83
+
84
+ opt_cls_set: set[type[TypedValue]] = set()
85
+
86
+ todo = [check.single(gty.args)]
87
+ seen = set()
88
+ while todo:
89
+ cur = todo.pop()
90
+ if cur in seen:
91
+ continue
92
+ seen.add(cur)
93
+
94
+ if isinstance(cur, rfl.Union):
95
+ todo.extend(cur.args)
96
+ else:
97
+ opt_cls_set.add(check.issubclass(check.isinstance(cur, type), TypedValue))
98
+
99
+ opt_impls: list[msh.Impl] = []
100
+ for opt_cls in opt_cls_set:
101
+ opt_impls.extend(_build_typed_value_poly(opt_cls).impls)
102
+
103
+ return msh.Impls(opt_impls)
104
+
105
+
106
+ class TypedValuesMarshalerFactory(msh.MarshalerFactoryMatchClass):
107
+ @mfs.simple(lambda _, ctx, rty: isinstance(rty, rfl.Generic) and rty.cls is TypedValues)
108
+ def _build(self, ctx: msh.MarshalContext, rty: rfl.Type) -> msh.Marshaler:
109
+ opt_m = msh.make_polymorphism_marshaler(
110
+ msh.Impls(_build_typed_values_impls(rty)),
111
+ msh.WrapperTypeTagging(),
112
+ ctx,
113
+ )
114
+ return msh.IterableMarshaler(opt_m)
115
+
116
+
117
+ class TypedValuesUnmarshalerFactory(msh.UnmarshalerFactoryMatchClass):
118
+ @mfs.simple(lambda _, ctx, rty: isinstance(rty, rfl.Generic) and rty.cls is TypedValues)
119
+ def _build(self, ctx: msh.UnmarshalContext, rty: rfl.Type) -> msh.Unmarshaler:
120
+ opt_u = msh.make_polymorphism_unmarshaler(
121
+ msh.Impls(_build_typed_values_impls(rty)),
122
+ msh.WrapperTypeTagging(),
123
+ ctx,
124
+ )
125
+ return msh.IterableUnmarshaler(lambda it: TypedValues(*it), opt_u) # noqa
126
+
127
+
128
+ ##
129
+
130
+
131
+ @lang.static_init
132
+ def _install_standard_marshalling() -> None:
133
+ msh.install_standard_factories(
134
+ TypedValueMarshalerFactory(),
135
+ TypedValueUnmarshalerFactory(),
136
+
137
+ TypedValuesMarshalerFactory(),
138
+ TypedValuesUnmarshalerFactory(),
139
+ )
@@ -42,3 +42,9 @@ class ScalarTypedValue(TypedValue, lang.Abstract, ta.Generic[T]):
42
42
 
43
43
  def __repr__(self) -> str:
44
44
  return f'{self.__class__.__name__}({self.v!r})'
45
+
46
+ def __init_subclass__(cls, **kwargs: ta.Any) -> None:
47
+ super().__init_subclass__(**kwargs)
48
+
49
+ if UniqueTypedValue in (mro := cls.__mro__) and mro.index(ScalarTypedValue) > mro.index(UniqueTypedValue):
50
+ raise TypeError(f'Class {cls} must have UniqueTypedValue before ScalarTypedValue in mro')
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: omlish
3
- Version: 0.0.0.dev273
3
+ Version: 0.0.0.dev275
4
4
  Summary: omlish
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -1,5 +1,5 @@
1
- omlish/.manifests.json,sha256=x26AIwDzScUvnX-p4xlq6Zc5QYrAo0Vmgf1qHc1KL_M,8253
2
- omlish/__about__.py,sha256=E6wHAnFO3xZWaRLHShW8D8wfZeMn1NE8rAz-ksXt6qg,3380
1
+ omlish/.manifests.json,sha256=pjGUyLHaoWpPqRP3jz2u1fC1qoRc2lvrEcpU_Ax2tdg,8253
2
+ omlish/__about__.py,sha256=lF4UMo4JKgTQYbwgQIGekUW4rRztnuwQfTy1Wa-z9kQ,3380
3
3
  omlish/__init__.py,sha256=SsyiITTuK0v74XpKV8dqNaCmjOlan1JZKrHQv5rWKPA,253
4
4
  omlish/c3.py,sha256=rer-TPOFDU6fYq_AWio_AmA-ckZ8JDY5shIzQ_yXfzA,8414
5
5
  omlish/cached.py,sha256=MLap_p0rdGoDIMVhXVHm1tsbcWobJF0OanoodV03Ju8,542
@@ -149,7 +149,7 @@ omlish/collections/coerce.py,sha256=tAls15v_7p5bUN33R7Zbko87KW5toWHl9fRialCqyNY,
149
149
  omlish/collections/exceptions.py,sha256=shcS-NCnEUudF8qC_SmO2TQyjivKlS4TDjaz_faqQ0c,44
150
150
  omlish/collections/frozen.py,sha256=LMbAHYDENIQk1hvjCTvpnx66m1TalrHa4CSn8n_tsXQ,4142
151
151
  omlish/collections/hasheq.py,sha256=swOBPEnU_C0SU3VqWJX9mr0BfZLD0A-4Ke9Vahj3fE4,3669
152
- omlish/collections/identity.py,sha256=32c1w-90OjwP9FlD-66yp4h_Y7cLfTmEUgp-MQdL8T8,2840
152
+ omlish/collections/identity.py,sha256=cIcvGORpKAWpNxEleAiPxJJsMA9RmZ7LUSKacexgCxE,3276
153
153
  omlish/collections/mappings.py,sha256=u0UrB550nBM_RNXQV0YnBTbRZEWrplZe9ZxcCN3H65M,2789
154
154
  omlish/collections/ordered.py,sha256=7zTbrAt12rf6i33XHkQERKar258fJacaw_WbtGEBgWo,2338
155
155
  omlish/collections/ranked.py,sha256=rg6DL36oOUiG5JQEAkGnT8b6f9mSndQlIovtt8GQj_w,2229
@@ -206,7 +206,7 @@ omlish/dataclasses/static.py,sha256=6pZG2iTR9NN8pKm-5ukDABnaVlTKFOzMwkg-rbxURoo,
206
206
  omlish/dataclasses/utils.py,sha256=BTXYyH0enSEP5kWxMnPTJ8_UPd7h4wF2RVPITNC8H4M,3872
207
207
  omlish/dataclasses/impl/LICENSE,sha256=Oy-B_iHRgcSZxZolbI4ZaEVdZonSaaqFNzv7avQdo78,13936
208
208
  omlish/dataclasses/impl/__init__.py,sha256=zqGBC5gSbjJxaqG_zS1LL1PX-zAfhIua8UqOE4IwO2k,789
209
- omlish/dataclasses/impl/api.py,sha256=Sl3DhCLn8KCvsXAOahr7VP_EH9XqBu9TBt3MQ9WqLbo,6849
209
+ omlish/dataclasses/impl/api.py,sha256=BkwGQYBdl9D8sq9pNmraqOfr5F0fpYF_CbD_s0ESEU8,7007
210
210
  omlish/dataclasses/impl/as_.py,sha256=CD-t7hkC1EP2F_jvZKIA_cVoDuwZ-Ln_xC4fJumPYX0,2598
211
211
  omlish/dataclasses/impl/copy.py,sha256=Tn8_n6Vohs-w4otbGdubBEvhd3TsSTaM3EfNGdS2LYo,591
212
212
  omlish/dataclasses/impl/descriptors.py,sha256=jSYNkKdy2rKddGpQqRwNuhw-ggpcvp_SWHpLwIWPOzc,2474
@@ -221,11 +221,11 @@ omlish/dataclasses/impl/metaclass.py,sha256=ebxJr3j8d_wz-fc7mvhWtJ6wJgnxVV6rVOQd
221
221
  omlish/dataclasses/impl/metadata.py,sha256=4veWwTr-aA0KP-Y1cPEeOcXHup9EKJTYNJ0ozIxtzD4,1401
222
222
  omlish/dataclasses/impl/order.py,sha256=zWvWDkSTym8cc7vO1cLHqcBhhjOlucHOCUVJcdh4jt0,1369
223
223
  omlish/dataclasses/impl/overrides.py,sha256=g9aCzaDDKyek8-yXRvtAcu1B1nCphWDYr4InHDlgbKk,1732
224
- omlish/dataclasses/impl/params.py,sha256=lmZkxZlZWPEPXmC-__P_3ZZeyL7IoQxli15mM3kUUsU,2983
224
+ omlish/dataclasses/impl/params.py,sha256=HMhvtsPup6WQOPLEVXTHgVvDWHk-kX-E2GAZxWXa6R0,3009
225
225
  omlish/dataclasses/impl/processing.py,sha256=DFxyFjL_h3awRyF_5eyTnB8QkuApx7Zc4QFnVoltlao,459
226
- omlish/dataclasses/impl/reflect.py,sha256=1PTxx3ycsWhC3oAV71mW-ZquDRwa2-t9uIaKFO8ab8U,5468
226
+ omlish/dataclasses/impl/reflect.py,sha256=ndX22d9bd9m_GAajPFQdnrw98AGw75lH9_tb-kdHwAs,5597
227
227
  omlish/dataclasses/impl/replace.py,sha256=wS9GHX4fIwaPv1JBJzIewdBfXyK3X3V7_t55Da87dYo,1217
228
- omlish/dataclasses/impl/repr.py,sha256=D6Rnz0tWf8Qy9abIFVV0x1UQFF9ERJd4VsyHmQ9Y2g0,1693
228
+ omlish/dataclasses/impl/repr.py,sha256=hk6HwKTLA0tb698CfiO8RYAqtpHQbGCpymm_Eo-B-2Y,1876
229
229
  omlish/dataclasses/impl/simple.py,sha256=Q272TYXifB5iKtydByxyzraeQHX6aXDY0VKO1-AKBF4,1771
230
230
  omlish/dataclasses/impl/slots.py,sha256=qXRLbtFWUs_2UV1fFUdv53_6fBLKJ_8McjNiP9YQlGM,5264
231
231
  omlish/dataclasses/impl/utils.py,sha256=aER2iL3UAtgS1BdLuEvTr9Tr2wC28wk1kiOeO-jIymw,6138
@@ -514,10 +514,10 @@ omlish/marshal/composite/newtypes.py,sha256=5-te247TiPYf84oFhf59tqIOOByXj8i9KaHT
514
514
  omlish/marshal/composite/optionals.py,sha256=MnecrmrJYjQvYJipIHNCDq78oH09dOjnw5pvaMKqoeU,1537
515
515
  omlish/marshal/composite/wrapped.py,sha256=jOsn3h1vLIqcoSTB-0KObnsdbV8jSVWJYbf7Kg9AUwg,750
516
516
  omlish/marshal/objects/__init__.py,sha256=F4wej8L_tedC8ETYxAnmKfdPR9TjsqIus9Z3nZofYuc,182
517
- omlish/marshal/objects/dataclasses.py,sha256=JKFrQiWn0YSYhcfz9-6rnk6NDoRhXqHdMER560z0h14,8515
517
+ omlish/marshal/objects/dataclasses.py,sha256=zs0yE0gi3tKHLiZGPf8FEMhPOc505vnHMjpp92MOX5k,8658
518
518
  omlish/marshal/objects/helpers.py,sha256=85GZp4h3Yo0GYGmnZpKgNxkWnSk8h2R21nfDLU2DtM0,1110
519
519
  omlish/marshal/objects/marshal.py,sha256=JarKGecMgaFYSUHUj-ZUYVP9HK6u2rjpBb3DWX9Uhh0,2648
520
- omlish/marshal/objects/metadata.py,sha256=QVD7DRhXbLda_Edgpc3OD1xT9fthmeaaj6l_nTE1PMM,3307
520
+ omlish/marshal/objects/metadata.py,sha256=2_rESnslP5fwtEW1xy9ECJg64uA4cQBuYcGkRfPElts,3342
521
521
  omlish/marshal/objects/namedtuples.py,sha256=8de8L7rwmvr_LLBHHfOl2wHObxc_1yZ8fC_J25yZi7Q,2866
522
522
  omlish/marshal/objects/unmarshal.py,sha256=IXIl_iokvVCSWYhkRORrWP_sE1DVklnrUErGWg_3MDc,3632
523
523
  omlish/marshal/polymorphism/__init__.py,sha256=e2UTrSL0qp7w_1vkdxDWd7sXlWhep2KPV49-BB64ma8,130
@@ -573,16 +573,16 @@ omlish/reflect/ops.py,sha256=RJ6jzrM4ieFsXzWyNXWV43O_WgzEaUvlHSc5N2ezW2A,2044
573
573
  omlish/reflect/subst.py,sha256=g3q7NmNWsmc67mcchmCE3WFPCMDSBq-FXn4ah-DWL_U,3622
574
574
  omlish/reflect/types.py,sha256=lYxK_hlC4kVDMKeDYJp0mymSth21quwuFAMAEFBznyE,9151
575
575
  omlish/secrets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
576
- omlish/secrets/all.py,sha256=zRp3bYkcVG4Aez4hBHKBxc07s6u74IrGQVUB8cfrGxY,281
576
+ omlish/secrets/all.py,sha256=SGB1KrlNrxlNpazEHYy95NTzteLi8ndoEgMhU7luBl8,420
577
577
  omlish/secrets/crypto.py,sha256=9D21lnvPhStwu8arD4ssT0ih0bDG-nlqIRdVgYL40xA,3708
578
- omlish/secrets/marshal.py,sha256=HWhim9pqk0ki9gVlDvnX0UVxnx_cGgWroDMKoprQBfo,1984
578
+ omlish/secrets/marshal.py,sha256=Jat6jTr0Fv3YBwqmq_DO2xahwn9qIeILrIybJ0vk34U,1989
579
579
  omlish/secrets/openssl.py,sha256=UT_dXJ4zA1s9e-UHoW_NLGHQO7iouUNPnJNkkpuw3JI,6213
580
- omlish/secrets/pwgen.py,sha256=v-5ztnOTHTAWXLGR-3H6HkMj2nPIZBMbo5xWR3q0rDY,1707
581
- omlish/secrets/pwhash.py,sha256=Goktn-swmC6PXqfRBnDrH_Lr42vjckT712UyErPjzkw,4102
580
+ omlish/secrets/pwgen.py,sha256=5k7QMSysUfv9F65TDMdDlrhTIKy6QbMG3KT2HNVmnVg,1712
581
+ omlish/secrets/pwhash.py,sha256=Jctv3QzcMvVPXJsWA3w3LDUlzmyUDGEWG9sLiJz1xaw,4107
582
582
  omlish/secrets/secrets.py,sha256=QNgOmRcIRK2fx49bIbBBM2rYbe6IhhLgk8fKvq8guoI,7963
583
- omlish/secrets/ssl.py,sha256=TvO1BJeCCBPsOLjO-QH7Q0DC-NS8onfmRxbl4ntOnd8,147
584
- omlish/secrets/subprocesses.py,sha256=ffjfbgPbEE_Pwb_87vG4yYR2CGZy3I31mHNCo_0JtHw,1212
585
- omlish/secrets/tempssl.py,sha256=tlwRrbHHvgKJtNAC31I5sDKryya4fagqN6kGt-tV4Qg,1874
583
+ omlish/secrets/ssl.py,sha256=_72xTNP6a1Xw0Pweuow9WK5yveqJ7hmjhala9iMnrAk,152
584
+ omlish/secrets/subprocesses.py,sha256=ZdShw4jrGDdyQW8mRMgl106-9qpCEq2J6w_x7ruz1wk,1217
585
+ omlish/secrets/tempssl.py,sha256=X_cAQbeaz-YcH8SzQ0luYTktIGJv4KMpfTD3t9l9Gqk,1879
586
586
  omlish/sockets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
587
587
  omlish/sockets/addresses.py,sha256=vbVeQBkzI513H4vRv-JS89QtRbr9U8v5zqkm3oODl_s,1869
588
588
  omlish/sockets/bind.py,sha256=J1SfFFFnVf3H5nqESDX2NGEY8DmjyIMUXZciZM33zQY,8003
@@ -776,15 +776,16 @@ omlish/text/parts.py,sha256=Q9NvoyEGQKIWgiPD4D_Qc66cWAuyEKE033dT9m7c3Wk,6662
776
776
  omlish/text/random.py,sha256=8feS5JE_tSjYlMl-lp0j93kCfzBae9AM2cXlRLebXMA,199
777
777
  omlish/text/go/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
778
778
  omlish/text/go/quoting.py,sha256=N9EYdnFdEX_A8fOviH-1w4jwV3XOQ7VU2WsoUNubYVY,9137
779
- omlish/typedvalues/__init__.py,sha256=9ROZq46KN2scNUckjMaSiUiXxP3a_-8_lnOh_eBF5RM,357
780
- omlish/typedvalues/accessor.py,sha256=gZ48yDFRYS_0TgbRBY6Pxa50ncWCqwaGes_T_RWLTvo,2738
781
- omlish/typedvalues/collection.py,sha256=1f0MLtlmynCm8pabzRtarmipcqFWw_7Z9EEuWJ68Ed8,3513
779
+ omlish/typedvalues/__init__.py,sha256=YalNleXS2vQX_3dOIMwfb4n_uBkENTT4QXHnsHatGGM,496
780
+ omlish/typedvalues/accessor.py,sha256=0k21N-CkjGaY6zCwugsRfOC_CDkqk7wNz4oxO1_6EEA,2919
781
+ omlish/typedvalues/collection.py,sha256=jsXSggmMMvGATcJgQkUXt5Guwq8aquw73_OIC-e6U0I,5300
782
782
  omlish/typedvalues/generic.py,sha256=byWG_gMXhNelckUwdmOoJE9FKkL71Q4BSi4ZLyy0XZ0,788
783
783
  omlish/typedvalues/holder.py,sha256=4SwRezsmuDDEO5gENGx8kTm30pblF5UktoEAu02i-Gk,1554
784
- omlish/typedvalues/values.py,sha256=V5hgmOmrVhRd0WdgMLku9MdxvRY2m0NzbQenu8WYl6I,902
785
- omlish-0.0.0.dev273.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
786
- omlish-0.0.0.dev273.dist-info/METADATA,sha256=8RDe_CEzwDnV44ud51Ere2JFi0bQudPpKeB0hXhw1to,4198
787
- omlish-0.0.0.dev273.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
788
- omlish-0.0.0.dev273.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
789
- omlish-0.0.0.dev273.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
790
- omlish-0.0.0.dev273.dist-info/RECORD,,
784
+ omlish/typedvalues/marshal.py,sha256=BuFQMoaLSDbEm32nj_hkBSClPvC0euNFU7_EhsrfBck,4487
785
+ omlish/typedvalues/values.py,sha256=Acyf6xSdNHxrkRXLXrFqJouk35YOveso1VqTbyPwQW4,1223
786
+ omlish-0.0.0.dev275.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
787
+ omlish-0.0.0.dev275.dist-info/METADATA,sha256=UZAxSmm4fOzFFAc7qszP_AvnFcJB1Sp3UwcpxUQ9V6w,4198
788
+ omlish-0.0.0.dev275.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
789
+ omlish-0.0.0.dev275.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
790
+ omlish-0.0.0.dev275.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
791
+ omlish-0.0.0.dev275.dist-info/RECORD,,