omlish 0.0.0.dev283__py3-none-any.whl → 0.0.0.dev285__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.
Files changed (121) hide show
  1. omlish/__about__.py +4 -4
  2. omlish/dataclasses/__init__.py +58 -60
  3. omlish/dataclasses/api/__init__.py +25 -0
  4. omlish/dataclasses/api/classes/__init__.py +0 -0
  5. omlish/dataclasses/api/classes/conversion.py +30 -0
  6. omlish/dataclasses/api/classes/decorator.py +145 -0
  7. omlish/dataclasses/api/classes/make.py +109 -0
  8. omlish/dataclasses/api/classes/metadata.py +133 -0
  9. omlish/dataclasses/api/classes/params.py +78 -0
  10. omlish/dataclasses/api/fields/__init__.py +0 -0
  11. omlish/dataclasses/api/fields/building.py +120 -0
  12. omlish/dataclasses/api/fields/constructor.py +56 -0
  13. omlish/dataclasses/api/fields/conversion.py +191 -0
  14. omlish/dataclasses/api/fields/metadata.py +94 -0
  15. omlish/dataclasses/concerns/__init__.py +17 -0
  16. omlish/dataclasses/concerns/abc.py +15 -0
  17. omlish/dataclasses/concerns/copy.py +63 -0
  18. omlish/dataclasses/concerns/doc.py +53 -0
  19. omlish/dataclasses/concerns/eq.py +60 -0
  20. omlish/dataclasses/concerns/fields.py +119 -0
  21. omlish/dataclasses/concerns/frozen.py +133 -0
  22. omlish/dataclasses/concerns/hash.py +165 -0
  23. omlish/dataclasses/concerns/init.py +453 -0
  24. omlish/dataclasses/concerns/matchargs.py +27 -0
  25. omlish/dataclasses/concerns/mro.py +16 -0
  26. omlish/dataclasses/concerns/order.py +87 -0
  27. omlish/dataclasses/concerns/override.py +98 -0
  28. omlish/dataclasses/concerns/params.py +14 -0
  29. omlish/dataclasses/concerns/replace.py +48 -0
  30. omlish/dataclasses/concerns/repr.py +95 -0
  31. omlish/dataclasses/{impl → concerns}/slots.py +25 -1
  32. omlish/dataclasses/debug.py +2 -0
  33. omlish/dataclasses/errors.py +115 -0
  34. omlish/dataclasses/generation/__init__.py +0 -0
  35. omlish/dataclasses/generation/base.py +38 -0
  36. omlish/dataclasses/generation/compilation.py +258 -0
  37. omlish/dataclasses/generation/execution.py +195 -0
  38. omlish/dataclasses/generation/globals.py +83 -0
  39. omlish/dataclasses/generation/idents.py +6 -0
  40. omlish/dataclasses/generation/mangling.py +18 -0
  41. omlish/dataclasses/generation/manifests.py +20 -0
  42. omlish/dataclasses/generation/ops.py +97 -0
  43. omlish/dataclasses/generation/plans.py +35 -0
  44. omlish/dataclasses/generation/processor.py +174 -0
  45. omlish/dataclasses/generation/registry.py +42 -0
  46. omlish/dataclasses/generation/utils.py +83 -0
  47. omlish/dataclasses/{impl/reflect.py → inspect.py} +53 -90
  48. omlish/dataclasses/{impl/internals.py → internals.py} +26 -32
  49. omlish/dataclasses/metaclass/__init__.py +0 -0
  50. omlish/dataclasses/metaclass/bases.py +69 -0
  51. omlish/dataclasses/metaclass/confer.py +65 -0
  52. omlish/dataclasses/metaclass/meta.py +115 -0
  53. omlish/dataclasses/metaclass/specs.py +38 -0
  54. omlish/dataclasses/processing/__init__.py +0 -0
  55. omlish/dataclasses/processing/base.py +83 -0
  56. omlish/dataclasses/processing/driving.py +45 -0
  57. omlish/dataclasses/processing/priority.py +13 -0
  58. omlish/dataclasses/processing/registry.py +81 -0
  59. omlish/dataclasses/reflection.py +81 -0
  60. omlish/dataclasses/specs.py +224 -0
  61. omlish/dataclasses/tools/__init__.py +0 -0
  62. omlish/dataclasses/{impl → tools}/as_.py +23 -8
  63. omlish/dataclasses/tools/iter.py +27 -0
  64. omlish/dataclasses/tools/modifiers.py +52 -0
  65. omlish/dataclasses/tools/replace.py +17 -0
  66. omlish/dataclasses/tools/repr.py +12 -0
  67. omlish/dataclasses/{static.py → tools/static.py} +25 -4
  68. omlish/dataclasses/utils.py +54 -109
  69. omlish/diag/__init__.py +4 -4
  70. omlish/inject/bindings.py +1 -1
  71. omlish/inject/eagers.py +1 -1
  72. omlish/inject/impl/bindings.py +1 -1
  73. omlish/inject/impl/origins.py +1 -1
  74. omlish/inject/keys.py +1 -1
  75. omlish/inject/listeners.py +1 -1
  76. omlish/inject/multis.py +4 -4
  77. omlish/inject/origins.py +2 -2
  78. omlish/inject/overrides.py +1 -1
  79. omlish/inject/privates.py +2 -2
  80. omlish/inject/providers.py +4 -4
  81. omlish/inject/scopes.py +3 -3
  82. omlish/lang/__init__.py +6 -2
  83. omlish/lang/cached/function.py +13 -2
  84. omlish/lang/cached/property.py +3 -1
  85. omlish/lang/imports.py +68 -10
  86. omlish/lang/objects.py +0 -46
  87. omlish/lite/reprs.py +84 -0
  88. omlish/marshal/objects/dataclasses.py +5 -9
  89. omlish/marshal/objects/helpers.py +3 -3
  90. omlish/secrets/marshal.py +1 -1
  91. omlish/secrets/secrets.py +1 -1
  92. omlish/sql/queries/base.py +4 -4
  93. omlish/text/mangle.py +66 -7
  94. omlish/typedvalues/marshal.py +2 -2
  95. omlish/typedvalues/values.py +1 -1
  96. {omlish-0.0.0.dev283.dist-info → omlish-0.0.0.dev285.dist-info}/METADATA +3 -3
  97. {omlish-0.0.0.dev283.dist-info → omlish-0.0.0.dev285.dist-info}/RECORD +101 -60
  98. omlish/dataclasses/impl/LICENSE +0 -279
  99. omlish/dataclasses/impl/__init__.py +0 -33
  100. omlish/dataclasses/impl/api.py +0 -278
  101. omlish/dataclasses/impl/copy.py +0 -30
  102. omlish/dataclasses/impl/errors.py +0 -53
  103. omlish/dataclasses/impl/fields.py +0 -245
  104. omlish/dataclasses/impl/frozen.py +0 -93
  105. omlish/dataclasses/impl/hashing.py +0 -86
  106. omlish/dataclasses/impl/init.py +0 -199
  107. omlish/dataclasses/impl/main.py +0 -93
  108. omlish/dataclasses/impl/metaclass.py +0 -235
  109. omlish/dataclasses/impl/metadata.py +0 -75
  110. omlish/dataclasses/impl/order.py +0 -47
  111. omlish/dataclasses/impl/overrides.py +0 -53
  112. omlish/dataclasses/impl/params.py +0 -128
  113. omlish/dataclasses/impl/processing.py +0 -24
  114. omlish/dataclasses/impl/replace.py +0 -40
  115. omlish/dataclasses/impl/repr.py +0 -66
  116. omlish/dataclasses/impl/simple.py +0 -50
  117. omlish/dataclasses/impl/utils.py +0 -167
  118. {omlish-0.0.0.dev283.dist-info → omlish-0.0.0.dev285.dist-info}/WHEEL +0 -0
  119. {omlish-0.0.0.dev283.dist-info → omlish-0.0.0.dev285.dist-info}/entry_points.txt +0 -0
  120. {omlish-0.0.0.dev283.dist-info → omlish-0.0.0.dev285.dist-info}/licenses/LICENSE +0 -0
  121. {omlish-0.0.0.dev283.dist-info → omlish-0.0.0.dev285.dist-info}/top_level.txt +0 -0
omlish/lang/imports.py CHANGED
@@ -3,6 +3,7 @@ TODO:
3
3
  - proxy_init 'as' alias support - attrs of (src, dst)
4
4
  """
5
5
  import contextlib
6
+ import functools
6
7
  import importlib.util
7
8
  import sys
8
9
  import types
@@ -254,6 +255,64 @@ def _trigger_conditional_imports(package: str) -> None:
254
255
  ##
255
256
 
256
257
 
258
+ class LazyGlobals:
259
+ def __init__(
260
+ self,
261
+ *,
262
+ globals: ta.MutableMapping[str, ta.Any] | None = None, # noqa
263
+ update_globals: bool = False,
264
+ ) -> None:
265
+ super().__init__()
266
+
267
+ self._globals = globals
268
+ self._update_globals = update_globals
269
+
270
+ self._attr_fns: dict[str, ta.Callable[[], ta.Any]] = {}
271
+
272
+ @classmethod
273
+ def install(cls, globals: ta.MutableMapping[str, ta.Any]) -> 'LazyGlobals': # noqa
274
+ try:
275
+ xga = globals['__getattr__']
276
+ except KeyError:
277
+ pass
278
+ else:
279
+ if not isinstance(xga, cls):
280
+ raise RuntimeError(f'Module already has __getattr__ hook: {xga}') # noqa
281
+ return xga
282
+
283
+ lm = cls(
284
+ globals=globals,
285
+ update_globals=True,
286
+ )
287
+
288
+ globals['__getattr__'] = lm
289
+
290
+ return lm
291
+
292
+ def set_fn(self, attr: str, fn: ta.Callable[[], ta.Any]) -> 'LazyGlobals':
293
+ self._attr_fns[attr] = fn
294
+ return self
295
+
296
+ def get(self, attr: str) -> ta.Any:
297
+ try:
298
+ fn = self._attr_fns[attr]
299
+ except KeyError:
300
+ raise AttributeError(attr) from None
301
+
302
+ val = fn()
303
+
304
+ if self._update_globals and self._globals is not None:
305
+ self._globals[attr] = val
306
+
307
+ return val
308
+
309
+ def __call__(self, attr: str) -> ta.Any:
310
+ return self.get(attr)
311
+
312
+
313
+ ##
314
+
315
+
257
316
  class NamePackage(ta.NamedTuple):
258
317
  name: str
259
318
  package: str
@@ -266,16 +325,13 @@ class _ProxyInit:
266
325
 
267
326
  def __init__(
268
327
  self,
328
+ lazy_globals: LazyGlobals,
269
329
  name_package: NamePackage,
270
- *,
271
- globals: ta.MutableMapping[str, ta.Any] | None = None, # noqa
272
- update_globals: bool = False,
273
330
  ) -> None:
274
331
  super().__init__()
275
332
 
333
+ self._lazy_globals = lazy_globals
276
334
  self._name_package = name_package
277
- self._globals = globals
278
- self._update_globals = update_globals
279
335
 
280
336
  self._imps_by_attr: dict[str, _ProxyInit._Import] = {}
281
337
  self._mods_by_pkgs: dict[str, ta.Any] = {}
@@ -287,13 +343,17 @@ class _ProxyInit:
287
343
  def add(self, package: str, attrs: ta.Iterable[str | tuple[str, str]]) -> None:
288
344
  if isinstance(attrs, str):
289
345
  raise TypeError(attrs)
346
+
290
347
  for attr in attrs:
291
348
  if isinstance(attr, tuple):
292
349
  imp_attr, attr = attr
293
350
  else:
294
351
  imp_attr = attr
352
+
295
353
  self._imps_by_attr[attr] = self._Import(package, imp_attr)
296
354
 
355
+ self._lazy_globals.set_fn(attr, functools.partial(self.get, attr))
356
+
297
357
  def get(self, attr: str) -> ta.Any:
298
358
  try:
299
359
  imp = self._imps_by_attr[attr]
@@ -307,9 +367,6 @@ class _ProxyInit:
307
367
 
308
368
  val = getattr(mod, imp.attr)
309
369
 
310
- if self._update_globals and self._globals is not None:
311
- self._globals[attr] = val
312
-
313
370
  return val
314
371
 
315
372
 
@@ -329,13 +386,14 @@ def proxy_init(
329
386
  pi: _ProxyInit
330
387
  try:
331
388
  pi = globals['__proxy_init__']
389
+
332
390
  except KeyError:
333
391
  pi = _ProxyInit(
392
+ LazyGlobals.install(globals),
334
393
  init_name_package,
335
- globals=globals,
336
394
  )
337
395
  globals['__proxy_init__'] = pi
338
- globals['__getattr__'] = pi.get
396
+
339
397
  else:
340
398
  if pi.name_package != init_name_package:
341
399
  raise Exception(f'Wrong init name: {pi.name_package=} != {init_name_package=}')
omlish/lang/objects.py CHANGED
@@ -1,8 +1,3 @@
1
- """
2
- TODO:
3
- - reprlib / recur guard (merge w/ defs.py)
4
- """
5
- import dataclasses as dc
6
1
  import types
7
2
  import typing as ta
8
3
  import weakref
@@ -16,47 +11,6 @@ T = ta.TypeVar('T')
16
11
  ##
17
12
 
18
13
 
19
- @dc.dataclass(frozen=True)
20
- class AttrRepr:
21
- attrs: ta.Sequence[str]
22
-
23
- _: dc.KW_ONLY
24
-
25
- with_module: bool = False
26
- use_qualname: bool = False
27
- with_id: bool = False
28
- value_filter: ta.Callable[[ta.Any], bool] | None = None
29
-
30
- @classmethod
31
- def of(cls, *attrs: str, **kwargs: ta.Any) -> 'AttrRepr':
32
- return cls(attrs, **kwargs)
33
-
34
- def __call__(self, obj: ta.Any) -> str:
35
- vs = ', '.join(
36
- f'{attr}={v!r}'
37
- for attr in self.attrs
38
- for v in [getattr(obj, attr)]
39
- if self.value_filter is None or self.value_filter(v)
40
- )
41
- return (
42
- f'{obj.__class__.__module__ + "." if self.with_module else ""}'
43
- f'{obj.__class__.__qualname__ if self.use_qualname else obj.__class__.__name__}'
44
- f'{("@" + hex(id(obj))[2:]) if self.with_id else ""}'
45
- f'({vs})'
46
- )
47
-
48
- def __get__(self, instance, owner):
49
- if instance is None:
50
- return self
51
- def __repr__(other): # noqa
52
- return self(other)
53
- return __repr__.__get__(instance, owner)
54
-
55
-
56
- def attr_repr(obj: ta.Any, *attrs: str, **kwargs: ta.Any) -> str:
57
- return AttrRepr(attrs, **kwargs)(obj)
58
-
59
-
60
14
  def arg_repr(*args: ta.Any, **kwargs: ta.Any) -> str:
61
15
  return ', '.join(*(
62
16
  list(map(repr, args)) +
omlish/lite/reprs.py ADDED
@@ -0,0 +1,84 @@
1
+ # ruff: noqa: UP007
2
+ import dataclasses as dc
3
+ import typing as ta
4
+
5
+
6
+ ##
7
+
8
+
9
+ @dc.dataclass(frozen=True)
10
+ class AttrRepr:
11
+ attrs: ta.Sequence[str]
12
+
13
+ # _: dc.KW_ONLY
14
+
15
+ with_module: bool = False
16
+ use_qualname: bool = False
17
+ with_id: bool = False
18
+ value_filter: ta.Optional[ta.Callable[[ta.Any], bool]] = None
19
+ recursive: bool = False
20
+
21
+ @classmethod
22
+ def of(cls, *attrs: str, **kwargs: ta.Any) -> 'AttrRepr':
23
+ return cls(attrs, **kwargs)
24
+
25
+ #
26
+
27
+ def _build_(self, obj: ta.Any) -> str:
28
+ vs = ', '.join(
29
+ f'{attr}={v!r}'
30
+ for attr in self.attrs
31
+ for v in [getattr(obj, attr)]
32
+ if self.value_filter is None or self.value_filter(v)
33
+ )
34
+
35
+ return (
36
+ f'{obj.__class__.__module__ + "." if self.with_module else ""}'
37
+ f'{obj.__class__.__qualname__ if self.use_qualname else obj.__class__.__name__}'
38
+ f'{("@" + hex(id(obj))[2:]) if self.with_id else ""}'
39
+ f'({vs})'
40
+ )
41
+
42
+ _build: ta.ClassVar[ta.Callable[[ta.Any], str]]
43
+
44
+ def __call__(self, obj: ta.Any) -> str:
45
+ try:
46
+ build: ta.Any = self._build
47
+
48
+ except AttributeError:
49
+ build = self._build_
50
+ if self.recursive:
51
+ build = self._reprlib().recursive_repr()(build)
52
+ object.__setattr__(self, '_build', build)
53
+
54
+ return build(obj)
55
+
56
+ #
57
+
58
+ def __get__(self, instance, owner):
59
+ if instance is None:
60
+ return self
61
+
62
+ def __repr__(other): # noqa
63
+ return self(other)
64
+
65
+ return __repr__.__get__(instance, owner)
66
+
67
+ #
68
+
69
+ _reprlib_: ta.ClassVar[ta.Any]
70
+
71
+ @classmethod
72
+ def _reprlib(cls) -> ta.Any:
73
+ try:
74
+ return cls._reprlib_
75
+ except AttributeError:
76
+ pass
77
+
78
+ reprlib = __import__('reprlib')
79
+ cls._reprlib_ = reprlib
80
+ return reprlib
81
+
82
+
83
+ def attr_repr(obj: ta.Any, *attrs: str, **kwargs: ta.Any) -> str:
84
+ return AttrRepr(attrs, **kwargs)(obj)
@@ -34,11 +34,7 @@ from .unmarshal import ObjectUnmarshaler
34
34
 
35
35
 
36
36
  def get_dataclass_metadata(ty: type) -> ObjectMetadata:
37
- return check.opt_single(
38
- e
39
- for e in dc.get_merged_metadata(ty).get(dc.UserMetadata, [])
40
- if isinstance(e, ObjectMetadata)
41
- ) or ObjectMetadata()
37
+ return check.single(dc.reflect(ty).spec.metadata_by_type.get(ObjectMetadata) or [ObjectMetadata()])
42
38
 
43
39
 
44
40
  def get_dataclass_field_infos(
@@ -50,7 +46,7 @@ def get_dataclass_field_infos(
50
46
 
51
47
  dc_md = get_dataclass_metadata(ty)
52
48
  dc_naming = dc_md.field_naming or opts.get(Naming)
53
- dc_rf = dc.reflect(ty)
49
+ dc_rfl = dc.reflect(ty)
54
50
 
55
51
  fi_defaults = {
56
52
  k: v
@@ -66,7 +62,7 @@ def get_dataclass_field_infos(
66
62
  type_hints = ta.get_type_hints(ty)
67
63
 
68
64
  ret: list[FieldInfo] = []
69
- for field in dc_rf.instance_fields:
65
+ for field in dc_rfl.instance_fields:
70
66
  if (f_naming := field.metadata.get(Naming, dc_naming)) is not None:
71
67
  um_name = translate_name(field.name, f_naming)
72
68
  else:
@@ -76,10 +72,10 @@ def get_dataclass_field_infos(
76
72
 
77
73
  f_ty: ta.Any
78
74
  if (
79
- ((cpx := dc_rf.cls_params_extras) is not None and cpx.generic_init) or
75
+ dc_rfl.spec.generic_init or
80
76
  (fmd is not None and fmd.options.generic_replace)
81
77
  ):
82
- f_ty = rfl.to_annotation(dc_rf.generic_replaced_field_type(field.name))
78
+ f_ty = rfl.to_annotation(dc_rfl.fields_inspection.generic_replaced_field_type(field.name))
83
79
  else:
84
80
  f_ty = type_hints[field.name]
85
81
 
@@ -14,7 +14,7 @@ T = ta.TypeVar('T')
14
14
  def update_field_metadata(**kwargs: ta.Any) -> dc.field_modifier:
15
15
  @dc.field_modifier
16
16
  def inner(f: dc.Field) -> dc.Field:
17
- return dc.update_field_metadata(f, {
17
+ return dc.set_field_metadata(f, {
18
18
  FieldMetadata: f.metadata.get(FieldMetadata, FieldMetadata()).update(**kwargs),
19
19
  })
20
20
  return inner
@@ -25,7 +25,7 @@ def update_fields_metadata(
25
25
  **kwargs: ta.Any,
26
26
  ) -> ta.Callable[[type[T]], type[T]]:
27
27
  def inner(a: str, f: dc.Field) -> dc.Field:
28
- return dc.update_field_metadata(f, {
28
+ return dc.set_field_metadata(f, {
29
29
  FieldMetadata: f.metadata.get(FieldMetadata, FieldMetadata()).update(**kwargs),
30
30
  })
31
31
 
@@ -37,7 +37,7 @@ def update_object_metadata(
37
37
  **kwargs: ta.Any,
38
38
  ):
39
39
  def inner(cls):
40
- return dc.update_class_metadata(cls, ObjectMetadata(**kwargs))
40
+ return dc.append_class_metadata(cls, ObjectMetadata(**kwargs))
41
41
 
42
42
  if cls is not None:
43
43
  inner(cls)
omlish/secrets/marshal.py CHANGED
@@ -44,7 +44,7 @@ class StrOrSecretRefMarshalerUnmarshaler(msh.Marshaler, msh.Unmarshaler):
44
44
  def marshal_secret_field(f: dc.Field) -> dc.Field:
45
45
  """Mostly obsolete with auto-registration below."""
46
46
 
47
- return dc.update_field_metadata(f, {
47
+ return dc.set_field_metadata(f, {
48
48
  msh.FieldMetadata: dc.replace(
49
49
  f.metadata.get(msh.FieldMetadata, msh.FieldMetadata()),
50
50
  marshaler=StrOrSecretRefMarshalerUnmarshaler(),
omlish/secrets/secrets.py CHANGED
@@ -79,7 +79,7 @@ def secret_repr(o: SecretRefOrStr | None) -> str | None:
79
79
 
80
80
  @dc.field_modifier
81
81
  def secret_field(f: dc.Field) -> dc.Field:
82
- return dc.update_field_extras(
82
+ return dc.update_extra_field_params(
83
83
  f,
84
84
  repr_fn=secret_repr,
85
85
  unless_non_default=True,
@@ -29,7 +29,7 @@ class Node(
29
29
  lang.Abstract,
30
30
  eq=False,
31
31
  confer=frozenset([
32
- *dc.get_metaclass_params(dc.Frozen).confer,
32
+ *dc.get_metaclass_spec(dc.Frozen).confer,
33
33
  'eq',
34
34
  ]),
35
35
  ):
@@ -61,10 +61,10 @@ class Node(
61
61
  except KeyError:
62
62
  pass
63
63
 
64
- dc_info = dc.reflect(cls)
64
+ dc_rfl = dc.reflect(cls)
65
65
  fields = Node._Fields(
66
- cmp_fields=tuple(f.name for f in dc_info.instance_fields if f.compare),
67
- hash_fields=tuple(f.name for f in dc_info.instance_fields if (f.compare if f.hash is None else f.hash)),
66
+ cmp_fields=tuple(f.name for f in dc_rfl.instance_fields if f.compare),
67
+ hash_fields=tuple(f.name for f in dc_rfl.instance_fields if (f.compare if f.hash is None else f.hash)),
68
68
  )
69
69
 
70
70
  setattr(cls, '__node_fields__', fields)
omlish/text/mangle.py CHANGED
@@ -1,6 +1,7 @@
1
1
  # ruff: noqa: UP006 UP007
2
2
  # @omlish-lite
3
3
  import dataclasses as dc
4
+ import re
4
5
  import typing as ta
5
6
 
6
7
  from ..lite.cached import cached_nullary
@@ -26,16 +27,74 @@ class StringMangler:
26
27
  check.not_in(self.escape, self.escaped)
27
28
  check.arg(len(set(self.escaped)) == len(self.escaped))
28
29
 
30
+ #
31
+
32
+ @cached_nullary
33
+ def replaced(self) -> ta.Tuple[str, ...]:
34
+ return (self.escape, *self.escaped)
35
+
36
+ @cached_nullary
37
+ def replaced_set(self) -> ta.FrozenSet[str]:
38
+ return frozenset(self.replaced())
39
+
40
+ @cached_nullary
41
+ def replaced_indexes(self) -> ta.Mapping[str, int]:
42
+ return {s: i for i, s in enumerate(self.replaced())}
43
+
44
+ @cached_nullary
45
+ def replaced_pat(self) -> re.Pattern:
46
+ return re.compile('|'.join(re.escape(k) for k in self.replaced()))
47
+
48
+ #
49
+
50
+ @cached_nullary
51
+ def replacement_pad(self) -> int:
52
+ return len('%x' % (len(self.replaced()),)) # noqa
53
+
29
54
  @cached_nullary
30
55
  def replacements(self) -> ta.Sequence[ta.Tuple[str, str]]:
31
- return [(l, self.escape + str(i)) for i, l in enumerate([self.escape, *self.escaped])]
56
+ fmt = f'%0{self.replacement_pad()}x'
57
+ return [
58
+ (l, self.escape + fmt % (i,))
59
+ for i, l in enumerate(self.replaced())
60
+ ]
61
+
62
+ @cached_nullary
63
+ def replacements_dict(self) -> ta.Mapping[str, str]:
64
+ return dict(self.replacements())
65
+
66
+ @cached_nullary
67
+ def inverse_replacements_dict(self) -> ta.Mapping[str, str]:
68
+ return {v: k for k, v in self.replacements()}
69
+
70
+ @cached_nullary
71
+ def replacements_pat(self) -> re.Pattern:
72
+ return re.compile(''.join([re.escape(self.escape), '.' * self.replacement_pad()]))
73
+
74
+ #
75
+
76
+ # def mangle(self, s: str) -> str:
77
+ # ecs = sorted(
78
+ # frozenset(s) & self.replaced_set(),
79
+ # key=self.replaced_indexes().__getitem__,
80
+ # )
81
+ # rd = self.replacements_dict()
82
+ # for l in ecs:
83
+ # r = rd[l]
84
+ # s = s.replace(l, r)
85
+ # return s
32
86
 
33
87
  def mangle(self, s: str) -> str:
34
- for l, r in self.replacements():
35
- s = s.replace(l, r)
36
- return s
88
+ rd = self.replacements_dict()
89
+ return self.replaced_pat().sub(lambda m: rd[m.group(0)], s)
90
+
91
+ #
92
+
93
+ # def unmangle(self, s: str) -> str:
94
+ # for l, r in reversed(self.replacements()):
95
+ # s = s.replace(r, l)
96
+ # return s
37
97
 
38
98
  def unmangle(self, s: str) -> str:
39
- for l, r in reversed(self.replacements()):
40
- s = s.replace(r, l)
41
- return s
99
+ ird = self.inverse_replacements_dict()
100
+ return self.replacements_pat().sub(lambda m: ird[m.group(0)], s)
@@ -32,7 +32,7 @@ class TypedValueMarshalerFactory(msh.MarshalerFactoryMatchClass):
32
32
  ))
33
33
  def _build_scalar(self, ctx: msh.MarshalContext, rty: rfl.Type) -> msh.Marshaler:
34
34
  dc_rfl = dc.reflect(check.isinstance(rty, type))
35
- v_rty = check.single(dc_rfl.generic_replaced_field_annotations.values())
35
+ v_rty = check.single(dc_rfl.fields_inspection.generic_replaced_field_annotations.values())
36
36
  v_m = ctx.make(v_rty)
37
37
  return msh.WrappedMarshaler(lambda _, o: o.v, v_m)
38
38
 
@@ -58,7 +58,7 @@ class TypedValueUnmarshalerFactory(msh.UnmarshalerFactoryMatchClass):
58
58
  def _build_scalar(self, ctx: msh.UnmarshalContext, rty: rfl.Type) -> msh.Unmarshaler:
59
59
  rty = check.isinstance(rty, type)
60
60
  dc_rfl = dc.reflect(rty)
61
- v_rty = check.single(dc_rfl.generic_replaced_field_annotations.values())
61
+ v_rty = check.single(dc_rfl.fields_inspection.generic_replaced_field_annotations.values())
62
62
  v_u = ctx.make(v_rty)
63
63
  return msh.WrappedUnmarshaler(lambda _, v: rty(v), v_u)
64
64
 
@@ -36,7 +36,7 @@ class UniqueTypedValue(TypedValue, lang.Abstract):
36
36
 
37
37
 
38
38
  @dc.dataclass(frozen=True)
39
- @dc.extra_params(generic_init=True)
39
+ @dc.extra_class_params(generic_init=True)
40
40
  class ScalarTypedValue(TypedValue, lang.Abstract, ta.Generic[T]):
41
41
  v: T
42
42
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: omlish
3
- Version: 0.0.0.dev283
3
+ Version: 0.0.0.dev285
4
4
  Summary: omlish
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -15,7 +15,7 @@ License-File: LICENSE
15
15
  Provides-Extra: all
16
16
  Requires-Dist: anyio~=4.9; extra == "all"
17
17
  Requires-Dist: sniffio~=1.3; extra == "all"
18
- Requires-Dist: greenlet~=3.1; extra == "all"
18
+ Requires-Dist: greenlet~=3.2; extra == "all"
19
19
  Requires-Dist: trio~=0.29; extra == "all"
20
20
  Requires-Dist: trio-asyncio~=0.15; extra == "all"
21
21
  Requires-Dist: lz4~=4.4; extra == "all"
@@ -53,7 +53,7 @@ Requires-Dist: wrapt~=1.17; extra == "all"
53
53
  Provides-Extra: async
54
54
  Requires-Dist: anyio~=4.9; extra == "async"
55
55
  Requires-Dist: sniffio~=1.3; extra == "async"
56
- Requires-Dist: greenlet~=3.1; extra == "async"
56
+ Requires-Dist: greenlet~=3.2; extra == "async"
57
57
  Requires-Dist: trio~=0.29; extra == "async"
58
58
  Requires-Dist: trio-asyncio~=0.15; extra == "async"
59
59
  Provides-Extra: compress