omlish 0.0.0.dev5__py3-none-any.whl → 0.0.0.dev7__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 (163) hide show
  1. omlish/__about__.py +109 -5
  2. omlish/__init__.py +0 -8
  3. omlish/asyncs/__init__.py +9 -9
  4. omlish/asyncs/anyio.py +123 -19
  5. omlish/asyncs/asyncio.py +23 -0
  6. omlish/asyncs/asyncs.py +9 -6
  7. omlish/asyncs/bridge.py +316 -0
  8. omlish/asyncs/trio_asyncio.py +7 -3
  9. omlish/bootstrap.py +737 -0
  10. omlish/check.py +1 -1
  11. omlish/collections/__init__.py +5 -0
  12. omlish/collections/exceptions.py +2 -0
  13. omlish/collections/identity.py +7 -0
  14. omlish/collections/utils.py +38 -9
  15. omlish/configs/strings.py +96 -0
  16. omlish/dataclasses/__init__.py +16 -0
  17. omlish/dataclasses/impl/copy.py +30 -0
  18. omlish/dataclasses/impl/descriptors.py +95 -0
  19. omlish/dataclasses/impl/exceptions.py +6 -0
  20. omlish/dataclasses/impl/fields.py +24 -25
  21. omlish/dataclasses/impl/init.py +4 -2
  22. omlish/dataclasses/impl/main.py +2 -0
  23. omlish/dataclasses/impl/reflect.py +1 -1
  24. omlish/dataclasses/utils.py +67 -0
  25. omlish/{lang/datetimes.py → datetimes.py} +8 -4
  26. omlish/diag/__init__.py +4 -0
  27. omlish/diag/procfs.py +2 -2
  28. omlish/{testing → diag}/pydevd.py +35 -0
  29. omlish/diag/threads.py +131 -48
  30. omlish/dispatch/_dispatch2.py +65 -0
  31. omlish/dispatch/_dispatch3.py +104 -0
  32. omlish/docker.py +16 -1
  33. omlish/fnpairs.py +11 -4
  34. omlish/formats/__init__.py +0 -0
  35. omlish/{configs → formats}/dotenv.py +15 -24
  36. omlish/{json.py → formats/json.py} +2 -1
  37. omlish/formats/yaml.py +223 -0
  38. omlish/graphs/trees.py +1 -1
  39. omlish/http/asgi.py +2 -1
  40. omlish/http/collections.py +15 -0
  41. omlish/http/consts.py +22 -1
  42. omlish/http/sessions.py +10 -3
  43. omlish/inject/__init__.py +49 -17
  44. omlish/inject/binder.py +185 -5
  45. omlish/inject/bindings.py +3 -36
  46. omlish/inject/eagers.py +2 -8
  47. omlish/inject/elements.py +31 -10
  48. omlish/inject/exceptions.py +1 -1
  49. omlish/inject/impl/elements.py +37 -12
  50. omlish/inject/impl/injector.py +72 -25
  51. omlish/inject/impl/inspect.py +33 -5
  52. omlish/inject/impl/origins.py +77 -0
  53. omlish/inject/impl/{private.py → privates.py} +2 -2
  54. omlish/inject/impl/scopes.py +6 -2
  55. omlish/inject/injector.py +8 -4
  56. omlish/inject/inspect.py +18 -0
  57. omlish/inject/keys.py +8 -14
  58. omlish/inject/listeners.py +26 -0
  59. omlish/inject/managed.py +76 -10
  60. omlish/inject/multis.py +68 -18
  61. omlish/inject/origins.py +30 -0
  62. omlish/inject/overrides.py +5 -4
  63. omlish/inject/{private.py → privates.py} +6 -10
  64. omlish/inject/providers.py +12 -85
  65. omlish/inject/scopes.py +13 -6
  66. omlish/inject/types.py +3 -1
  67. omlish/inject/utils.py +18 -0
  68. omlish/iterators.py +69 -2
  69. omlish/lang/__init__.py +24 -9
  70. omlish/lang/cached.py +2 -2
  71. omlish/lang/classes/restrict.py +12 -1
  72. omlish/lang/classes/simple.py +18 -8
  73. omlish/lang/contextmanagers.py +13 -4
  74. omlish/lang/descriptors.py +132 -1
  75. omlish/lang/functions.py +8 -28
  76. omlish/lang/imports.py +67 -0
  77. omlish/lang/iterables.py +60 -1
  78. omlish/lang/maybes.py +3 -0
  79. omlish/lang/objects.py +38 -0
  80. omlish/lang/strings.py +25 -0
  81. omlish/lang/sys.py +9 -0
  82. omlish/lang/typing.py +42 -0
  83. omlish/lifecycles/__init__.py +34 -0
  84. omlish/lifecycles/abstract.py +43 -0
  85. omlish/lifecycles/base.py +51 -0
  86. omlish/lifecycles/contextmanagers.py +74 -0
  87. omlish/lifecycles/controller.py +116 -0
  88. omlish/lifecycles/manager.py +161 -0
  89. omlish/lifecycles/states.py +43 -0
  90. omlish/lifecycles/transitions.py +64 -0
  91. omlish/lite/__init__.py +1 -0
  92. omlish/lite/cached.py +18 -0
  93. omlish/lite/check.py +29 -0
  94. omlish/lite/contextmanagers.py +18 -0
  95. omlish/lite/json.py +30 -0
  96. omlish/lite/logs.py +52 -0
  97. omlish/lite/marshal.py +316 -0
  98. omlish/lite/reflect.py +49 -0
  99. omlish/lite/runtime.py +18 -0
  100. omlish/lite/secrets.py +19 -0
  101. omlish/lite/strings.py +25 -0
  102. omlish/lite/subprocesses.py +112 -0
  103. omlish/logs/configs.py +15 -2
  104. omlish/logs/formatters.py +7 -2
  105. omlish/marshal/__init__.py +32 -0
  106. omlish/marshal/any.py +5 -5
  107. omlish/marshal/base.py +27 -11
  108. omlish/marshal/base64.py +24 -9
  109. omlish/marshal/dataclasses.py +34 -28
  110. omlish/marshal/datetimes.py +74 -18
  111. omlish/marshal/enums.py +14 -8
  112. omlish/marshal/exceptions.py +11 -1
  113. omlish/marshal/factories.py +59 -74
  114. omlish/marshal/forbidden.py +35 -0
  115. omlish/marshal/global_.py +11 -4
  116. omlish/marshal/iterables.py +21 -24
  117. omlish/marshal/mappings.py +23 -26
  118. omlish/marshal/naming.py +4 -0
  119. omlish/marshal/numbers.py +51 -0
  120. omlish/marshal/objects.py +1 -0
  121. omlish/marshal/optionals.py +11 -12
  122. omlish/marshal/polymorphism.py +86 -21
  123. omlish/marshal/primitives.py +4 -5
  124. omlish/marshal/standard.py +13 -8
  125. omlish/marshal/uuids.py +4 -5
  126. omlish/matchfns.py +218 -0
  127. omlish/os.py +64 -0
  128. omlish/reflect/__init__.py +39 -0
  129. omlish/reflect/isinstance.py +38 -0
  130. omlish/reflect/ops.py +84 -0
  131. omlish/reflect/subst.py +110 -0
  132. omlish/reflect/types.py +275 -0
  133. omlish/secrets/__init__.py +23 -0
  134. omlish/secrets/crypto.py +132 -0
  135. omlish/secrets/marshal.py +70 -0
  136. omlish/secrets/openssl.py +207 -0
  137. omlish/secrets/passwords.py +120 -0
  138. omlish/secrets/secrets.py +299 -0
  139. omlish/secrets/subprocesses.py +42 -0
  140. omlish/sql/dbs.py +7 -6
  141. omlish/sql/duckdb.py +136 -0
  142. omlish/sql/exprs.py +12 -0
  143. omlish/sql/secrets.py +10 -0
  144. omlish/sql/sqlean.py +17 -0
  145. omlish/term.py +2 -2
  146. omlish/testing/pytest/__init__.py +3 -2
  147. omlish/testing/pytest/inject/harness.py +3 -3
  148. omlish/testing/pytest/marks.py +4 -7
  149. omlish/testing/pytest/plugins/__init__.py +1 -0
  150. omlish/testing/pytest/plugins/asyncs.py +136 -0
  151. omlish/testing/pytest/plugins/pydevd.py +1 -1
  152. omlish/testing/pytest/plugins/switches.py +54 -19
  153. omlish/text/glyphsplit.py +97 -0
  154. omlish-0.0.0.dev7.dist-info/METADATA +50 -0
  155. omlish-0.0.0.dev7.dist-info/RECORD +268 -0
  156. {omlish-0.0.0.dev5.dist-info → omlish-0.0.0.dev7.dist-info}/WHEEL +1 -1
  157. omlish/reflect.py +0 -355
  158. omlish-0.0.0.dev5.dist-info/METADATA +0 -34
  159. omlish-0.0.0.dev5.dist-info/RECORD +0 -212
  160. /omlish/{asyncs/futures.py → concurrent.py} +0 -0
  161. /omlish/{configs → formats}/props.py +0 -0
  162. {omlish-0.0.0.dev5.dist-info → omlish-0.0.0.dev7.dist-info}/LICENSE +0 -0
  163. {omlish-0.0.0.dev5.dist-info → omlish-0.0.0.dev7.dist-info}/top_level.txt +0 -0
@@ -4,13 +4,14 @@ import functools
4
4
  import typing as ta
5
5
 
6
6
  from .. import check
7
+ from .. import matchfns as mfs
7
8
  from .. import reflect as rfl
8
9
  from .base import MarshalContext
9
10
  from .base import Marshaler
10
- from .base import MarshalerFactory
11
+ from .base import MarshalerFactoryMatchClass
11
12
  from .base import UnmarshalContext
12
13
  from .base import Unmarshaler
13
- from .base import UnmarshalerFactory
14
+ from .base import UnmarshalerFactoryMatchClass
14
15
  from .values import Value
15
16
 
16
17
 
@@ -22,17 +23,15 @@ class IterableMarshaler(Marshaler):
22
23
  return list(map(functools.partial(self.e.marshal, ctx), o))
23
24
 
24
25
 
25
- class IterableMarshalerFactory(MarshalerFactory):
26
- def __call__(self, ctx: MarshalContext, rty: rfl.Type) -> Marshaler | None:
27
- if isinstance(rty, rfl.Generic) and issubclass(rty.cls, collections.abc.Iterable):
28
- if (e := ctx.make(check.single(rty.args))) is None:
29
- return None # type: ignore
30
- return IterableMarshaler(e)
31
- if isinstance(rty, type) and issubclass(rty, collections.abc.Iterable):
32
- if (e := ctx.make(ta.Any)) is None:
33
- return None # type: ignore
34
- return IterableMarshaler(e)
35
- return None
26
+ class IterableMarshalerFactory(MarshalerFactoryMatchClass):
27
+ @mfs.simple(lambda _, ctx, rty: isinstance(rty, rfl.Generic) and issubclass(rty.cls, collections.abc.Iterable))
28
+ def _build_generic(self, ctx: MarshalContext, rty: rfl.Type) -> Marshaler:
29
+ gty = check.isinstance(rty, rfl.Generic)
30
+ return IterableMarshaler(ctx.make(check.single(gty.args)))
31
+
32
+ @mfs.simple(lambda _, ctx, rty: isinstance(rty, type) and issubclass(rty, collections.abc.Iterable))
33
+ def _build_concrete(self, ctx: MarshalContext, rty: rfl.Type) -> Marshaler:
34
+ return IterableMarshaler(ctx.make(ta.Any))
36
35
 
37
36
 
38
37
  @dc.dataclass(frozen=True)
@@ -44,14 +43,12 @@ class IterableUnmarshaler(Unmarshaler):
44
43
  return self.ctor(map(functools.partial(self.e.unmarshal, ctx), check.isinstance(v, collections.abc.Iterable)))
45
44
 
46
45
 
47
- class IterableUnmarshalerFactory(UnmarshalerFactory):
48
- def __call__(self, ctx: UnmarshalContext, rty: rfl.Type) -> Unmarshaler | None:
49
- if isinstance(rty, rfl.Generic) and issubclass(rty.cls, collections.abc.Iterable):
50
- if (e := ctx.make(check.single(rty.args))) is None:
51
- return None # type: ignore
52
- return IterableUnmarshaler(rty.cls, e) # noqa
53
- if isinstance(rty, type) and issubclass(rty, collections.abc.Iterable):
54
- if (e := ctx.make(ta.Any)) is None:
55
- return None # type: ignore
56
- return IterableUnmarshaler(rty, e) # noqa
57
- return None
46
+ class IterableUnmarshalerFactory(UnmarshalerFactoryMatchClass):
47
+ @mfs.simple(lambda _, ctx, rty: isinstance(rty, rfl.Generic) and issubclass(rty.cls, collections.abc.Iterable))
48
+ def _build_generic(self, ctx: UnmarshalContext, rty: rfl.Type) -> Unmarshaler:
49
+ gty = check.isinstance(rty, rfl.Generic)
50
+ return IterableUnmarshaler(gty.cls, ctx.make(check.single(gty.args)))
51
+
52
+ @mfs.simple(lambda _, ctx, rty: isinstance(rty, type) and issubclass(rty, collections.abc.Iterable))
53
+ def _build_concrete(self, ctx: UnmarshalContext, rty: rfl.Type) -> Unmarshaler:
54
+ return IterableUnmarshaler(check.isinstance(rty, type), ctx.make(ta.Any))
@@ -3,13 +3,14 @@ import dataclasses as dc
3
3
  import typing as ta
4
4
 
5
5
  from .. import check
6
+ from .. import matchfns as mfs
6
7
  from .. import reflect as rfl
7
8
  from .base import MarshalContext
8
9
  from .base import Marshaler
9
- from .base import MarshalerFactory
10
+ from .base import MarshalerFactoryMatchClass
10
11
  from .base import UnmarshalContext
11
12
  from .base import Unmarshaler
12
- from .base import UnmarshalerFactory
13
+ from .base import UnmarshalerFactoryMatchClass
13
14
  from .values import Value
14
15
 
15
16
 
@@ -25,18 +26,16 @@ class MappingMarshaler(Marshaler):
25
26
  }
26
27
 
27
28
 
28
- class MappingMarshalerFactory(MarshalerFactory):
29
- def __call__(self, ctx: MarshalContext, rty: rfl.Type) -> Marshaler | None:
30
- if isinstance(rty, rfl.Generic) and issubclass(rty.cls, collections.abc.Mapping):
31
- kt, vt = rty.args
32
- if (ke := ctx.make(kt)) is None or (ve := ctx.make(vt)) is None:
33
- return None # type: ignore
34
- return MappingMarshaler(ke, ve)
35
- if isinstance(rty, type) and issubclass(rty, collections.abc.Mapping):
36
- if (e := ctx.make(ta.Any)) is None:
37
- return None # type: ignore
38
- return MappingMarshaler(e, e)
39
- return None
29
+ class MappingMarshalerFactory(MarshalerFactoryMatchClass):
30
+ @mfs.simple(lambda _, ctx, rty: isinstance(rty, rfl.Generic) and issubclass(rty.cls, collections.abc.Mapping))
31
+ def _build_generic(self, ctx: MarshalContext, rty: rfl.Type) -> Marshaler:
32
+ gty = check.isinstance(rty, rfl.Generic)
33
+ kt, vt = gty.args
34
+ return MappingMarshaler(ctx.make(kt), ctx.make(vt))
35
+
36
+ @mfs.simple(lambda _, ctx, rty: isinstance(rty, type) and issubclass(rty, collections.abc.Mapping))
37
+ def _build_concrete(self, ctx: MarshalContext, rty: rfl.Type) -> Marshaler:
38
+ return MappingMarshaler(a := ctx.make(ta.Any), a)
40
39
 
41
40
 
42
41
  @dc.dataclass(frozen=True)
@@ -52,15 +51,13 @@ class MappingUnmarshaler(Unmarshaler):
52
51
  return self.ctor(dct)
53
52
 
54
53
 
55
- class MappingUnmarshalerFactory(UnmarshalerFactory):
56
- def __call__(self, ctx: UnmarshalContext, rty: rfl.Type) -> Unmarshaler | None:
57
- if isinstance(rty, rfl.Generic) and issubclass(rty.cls, collections.abc.Mapping):
58
- kt, vt = rty.args
59
- if (ke := ctx.make(kt)) is None or (ve := ctx.make(vt)) is None:
60
- return None # type: ignore
61
- return MappingUnmarshaler(rty.cls, ke, ve)
62
- if isinstance(rty, type) and issubclass(rty, collections.abc.Mapping):
63
- if (e := ctx.make(ta.Any)) is None:
64
- return None # type: ignore
65
- return MappingUnmarshaler(rty, e, e)
66
- return None
54
+ class MappingUnmarshalerFactory(UnmarshalerFactoryMatchClass):
55
+ @mfs.simple(lambda _, ctx, rty: isinstance(rty, rfl.Generic) and issubclass(rty.cls, collections.abc.Mapping))
56
+ def _build_generic(self, ctx: UnmarshalContext, rty: rfl.Type) -> Unmarshaler:
57
+ gty = check.isinstance(rty, rfl.Generic)
58
+ kt, vt = gty.args
59
+ return MappingUnmarshaler(gty.cls, ctx.make(kt), ctx.make(vt))
60
+
61
+ @mfs.simple(lambda _, ctx, rty: isinstance(rty, type) and issubclass(rty, collections.abc.Mapping))
62
+ def _build_concrete(self, ctx: UnmarshalContext, rty: rfl.Type) -> Unmarshaler:
63
+ return MappingUnmarshaler(check.isinstance(rty, type), a := ctx.make(ta.Any), a)
omlish/marshal/naming.py CHANGED
@@ -7,6 +7,7 @@ from .base import Option
7
7
  class Naming(Option, enum.Enum):
8
8
  SNAKE = 'snake'
9
9
  CAMEL = 'camel'
10
+ LOW_CAMEL = 'low_camel'
10
11
 
11
12
 
12
13
  def translate_name(n: str, e: Naming) -> str:
@@ -14,4 +15,7 @@ def translate_name(n: str, e: Naming) -> str:
14
15
  return lang.snake_case(n)
15
16
  if e is Naming.CAMEL:
16
17
  return lang.camel_case(n)
18
+ if e is Naming.LOW_CAMEL:
19
+ r = lang.camel_case(n)
20
+ return (r[0].lower() + r[1:]) if r else r
17
21
  raise ValueError(e)
@@ -0,0 +1,51 @@
1
+ import decimal
2
+ import fractions
3
+ import typing as ta
4
+
5
+ from .. import check
6
+ from .base import MarshalContext
7
+ from .base import Marshaler
8
+ from .base import TypeMapMarshalerFactory
9
+ from .base import TypeMapUnmarshalerFactory
10
+ from .base import UnmarshalContext
11
+ from .base import Unmarshaler
12
+ from .values import Value
13
+
14
+
15
+ class ComplexMarshalerUnmarshaler(Marshaler, Unmarshaler):
16
+ def marshal(self, ctx: MarshalContext, o: complex) -> Value:
17
+ return [o.real, o.imag]
18
+
19
+ def unmarshal(self, ctx: UnmarshalContext, v: Value) -> ta.Any:
20
+ real, imag = check.isinstance(v, list)
21
+ return complex(real, imag) # type: ignore
22
+
23
+
24
+ class DecimalMarshalerUnmarshaler(Marshaler, Unmarshaler):
25
+ def marshal(self, ctx: MarshalContext, o: decimal.Decimal) -> Value:
26
+ return str(o)
27
+
28
+ def unmarshal(self, ctx: UnmarshalContext, v: Value) -> ta.Any:
29
+ return decimal.Decimal(check.isinstance(v, str))
30
+
31
+
32
+ class FractionMarshalerUnmarshaler(Marshaler, Unmarshaler):
33
+ def marshal(self, ctx: MarshalContext, o: fractions.Fraction) -> Value:
34
+ return [o.numerator, o.denominator]
35
+
36
+ def unmarshal(self, ctx: UnmarshalContext, v: Value) -> ta.Any:
37
+ num, denom = check.isinstance(v, list)
38
+ return fractions.Fraction(num, denom) # type: ignore
39
+
40
+
41
+ NUMBERS_MARSHALER_FACTORY = TypeMapMarshalerFactory({
42
+ complex: ComplexMarshalerUnmarshaler(),
43
+ decimal.Decimal: DecimalMarshalerUnmarshaler(),
44
+ fractions.Fraction: FractionMarshalerUnmarshaler(),
45
+ })
46
+
47
+ NUMBERS_UNMARSHALER_FACTORY = TypeMapUnmarshalerFactory({
48
+ complex: ComplexMarshalerUnmarshaler(),
49
+ decimal.Decimal: DecimalMarshalerUnmarshaler(),
50
+ fractions.Fraction: FractionMarshalerUnmarshaler(),
51
+ })
omlish/marshal/objects.py CHANGED
@@ -2,6 +2,7 @@
2
2
  TODO:
3
3
  - cfg naming
4
4
  - adapters for dataclasses / namedtuples / user objects (as confitured)
5
+ - mro-merge ObjectMetadata
5
6
  """
6
7
  import collections.abc
7
8
  import typing as ta
@@ -1,6 +1,7 @@
1
1
  import dataclasses as dc
2
2
  import typing as ta
3
3
 
4
+ from .. import check
4
5
  from .. import reflect as rfl
5
6
  from .base import MarshalContext
6
7
  from .base import Marshaler
@@ -22,12 +23,11 @@ class OptionalMarshaler(Marshaler):
22
23
 
23
24
 
24
25
  class OptionalMarshalerFactory(MarshalerFactory):
25
- def __call__(self, ctx: MarshalContext, rty: rfl.Type) -> Marshaler | None:
26
- if isinstance(rty, rfl.Union) and rty.is_optional:
27
- if (e := ctx.make(rty.without_none())) is None:
28
- return None # type: ignore
29
- return OptionalMarshaler(e)
30
- return None
26
+ def guard(self, ctx: MarshalContext, rty: rfl.Type) -> bool:
27
+ return isinstance(rty, rfl.Union) and rty.is_optional
28
+
29
+ def fn(self, ctx: MarshalContext, rty: rfl.Type) -> Marshaler:
30
+ return OptionalMarshaler(ctx.make(check.isinstance(rty, rfl.Union).without_none()))
31
31
 
32
32
 
33
33
  @dc.dataclass(frozen=True)
@@ -41,9 +41,8 @@ class OptionalUnmarshaler(Unmarshaler):
41
41
 
42
42
 
43
43
  class OptionalUnmarshalerFactory(UnmarshalerFactory):
44
- def __call__(self, ctx: UnmarshalContext, rty: rfl.Type) -> Unmarshaler | None:
45
- if isinstance(rty, rfl.Union) and rty.is_optional:
46
- if (e := ctx.make(rty.without_none())) is None:
47
- return None # type: ignore
48
- return OptionalUnmarshaler(e)
49
- return None
44
+ def guard(self, ctx: UnmarshalContext, rty: rfl.Type) -> bool:
45
+ return isinstance(rty, rfl.Union) and rty.is_optional
46
+
47
+ def fn(self, ctx: UnmarshalContext, rty: rfl.Type) -> Unmarshaler:
48
+ return OptionalUnmarshaler(ctx.make(check.isinstance(rty, rfl.Union).without_none()))
@@ -19,12 +19,29 @@ from .base import Unmarshaler
19
19
  from .base import UnmarshalerFactory
20
20
  from .naming import Naming
21
21
  from .naming import translate_name
22
+ from .registries import RegistryItem
22
23
  from .values import Value
23
24
 
24
25
 
25
26
  ##
26
27
 
27
28
 
29
+ class TypeTagging(RegistryItem, lang.Abstract, lang.Sealed):
30
+ pass
31
+
32
+
33
+ class WrapperTypeTagging(TypeTagging, lang.Final):
34
+ pass
35
+
36
+
37
+ @dc.dataclass(frozen=True)
38
+ class FieldTypeTagging(TypeTagging, lang.Final):
39
+ field: str
40
+
41
+
42
+ ##
43
+
44
+
28
45
  @dc.dataclass(frozen=True)
29
46
  class Impl:
30
47
  ty: type
@@ -33,7 +50,11 @@ class Impl:
33
50
 
34
51
 
35
52
  class Polymorphism:
36
- def __init__(self, ty: type, impls: ta.Iterable[Impl]) -> None:
53
+ def __init__(
54
+ self,
55
+ ty: type,
56
+ impls: ta.Iterable[Impl],
57
+ ) -> None:
37
58
  super().__init__()
38
59
  self._ty = ty
39
60
  self._impls = list(impls)
@@ -72,7 +93,11 @@ class Polymorphism:
72
93
  return self._by_tag
73
94
 
74
95
 
75
- def polymorphism_from_subclasses(ty: type, *, naming: Naming | None = None) -> Polymorphism:
96
+ def polymorphism_from_subclasses(
97
+ ty: type,
98
+ *,
99
+ naming: Naming | None = None,
100
+ ) -> Polymorphism:
76
101
  dct: dict[str, Impl] = {}
77
102
  seen: set[type] = set()
78
103
  todo: list[type] = [ty]
@@ -97,7 +122,7 @@ def polymorphism_from_subclasses(ty: type, *, naming: Naming | None = None) -> P
97
122
 
98
123
 
99
124
  @dc.dataclass(frozen=True)
100
- class PolymorphismMarshaler(Marshaler):
125
+ class WrapperPolymorphismMarshaler(Marshaler):
101
126
  m: ta.Mapping[type, tuple[str, Marshaler]]
102
127
 
103
128
  def marshal(self, ctx: MarshalContext, o: ta.Any | None) -> Value:
@@ -105,24 +130,43 @@ class PolymorphismMarshaler(Marshaler):
105
130
  return {tag: m.marshal(ctx, o)}
106
131
 
107
132
 
133
+ @dc.dataclass(frozen=True)
134
+ class FieldPolymorphismMarshaler(Marshaler):
135
+ m: ta.Mapping[type, tuple[str, Marshaler]]
136
+ tf: str
137
+
138
+ def marshal(self, ctx: MarshalContext, o: ta.Any | None) -> Value:
139
+ tag, m = self.m[type(o)]
140
+ return {self.tf: tag, **m.marshal(ctx, o)} # type: ignore
141
+
142
+
108
143
  @dc.dataclass(frozen=True)
109
144
  class PolymorphismMarshalerFactory(MarshalerFactory):
110
145
  p: Polymorphism
146
+ tt: TypeTagging = WrapperTypeTagging()
111
147
 
112
- def __call__(self, ctx: MarshalContext, rty: rfl.Type) -> Marshaler | None:
113
- if rty is self.p.ty:
114
- return PolymorphismMarshaler({
115
- i.ty: (i.tag, ctx.make(i.ty))
116
- for i in self.p.impls
117
- })
118
- return None
148
+ def guard(self, ctx: MarshalContext, rty: rfl.Type) -> bool:
149
+ return rty is self.p.ty
150
+
151
+ def fn(self, ctx: MarshalContext, rty: rfl.Type) -> Marshaler:
152
+ check.is_(rty, self.p.ty)
153
+ m = {
154
+ i.ty: (i.tag, ctx.make(i.ty))
155
+ for i in self.p.impls
156
+ }
157
+ if isinstance(self.tt, WrapperTypeTagging):
158
+ return WrapperPolymorphismMarshaler(m)
159
+ elif isinstance(self.tt, FieldTypeTagging):
160
+ return FieldPolymorphismMarshaler(m, self.tt.field)
161
+ else:
162
+ raise TypeError(self.tt)
119
163
 
120
164
 
121
165
  ##
122
166
 
123
167
 
124
168
  @dc.dataclass(frozen=True)
125
- class PolymorphismUnmarshaler(Unmarshaler):
169
+ class WrapperPolymorphismUnmarshaler(Unmarshaler):
126
170
  m: ta.Mapping[str, Unmarshaler]
127
171
 
128
172
  def unmarshal(self, ctx: UnmarshalContext, v: Value) -> ta.Any | None:
@@ -132,16 +176,37 @@ class PolymorphismUnmarshaler(Unmarshaler):
132
176
  return u.unmarshal(ctx, iv) # type: ignore
133
177
 
134
178
 
179
+ @dc.dataclass(frozen=True)
180
+ class FieldPolymorphismUnmarshaler(Unmarshaler):
181
+ m: ta.Mapping[str, Unmarshaler]
182
+ tf: str
183
+
184
+ def unmarshal(self, ctx: UnmarshalContext, v: Value) -> ta.Any | None:
185
+ ma = dict(check.isinstance(v, collections.abc.Mapping))
186
+ tag = ma.pop(self.tf) # type: ignore
187
+ u = self.m[tag] # type: ignore
188
+ return u.unmarshal(ctx, ma)
189
+
190
+
135
191
  @dc.dataclass(frozen=True)
136
192
  class PolymorphismUnmarshalerFactory(UnmarshalerFactory):
137
193
  p: Polymorphism
138
-
139
- def __call__(self, ctx: UnmarshalContext, rty: rfl.Type) -> Unmarshaler | None:
140
- if rty is self.p.ty:
141
- return PolymorphismUnmarshaler({
142
- t: u
143
- for i in self.p.impls
144
- for u in [ctx.make(i.ty)]
145
- for t in [i.tag, *i.alts]
146
- })
147
- return None
194
+ tt: TypeTagging = WrapperTypeTagging()
195
+
196
+ def guard(self, ctx: UnmarshalContext, rty: rfl.Type) -> bool:
197
+ return rty is self.p.ty
198
+
199
+ def fn(self, ctx: UnmarshalContext, rty: rfl.Type) -> Unmarshaler:
200
+ check.is_(rty, self.p.ty)
201
+ m = {
202
+ t: u
203
+ for i in self.p.impls
204
+ for u in [ctx.make(i.ty)]
205
+ for t in [i.tag, *i.alts]
206
+ }
207
+ if isinstance(self.tt, WrapperTypeTagging):
208
+ return WrapperPolymorphismUnmarshaler(m)
209
+ elif isinstance(self.tt, FieldTypeTagging):
210
+ return FieldPolymorphismUnmarshaler(m, self.tt.field)
211
+ else:
212
+ raise TypeError(self.tt)
@@ -2,11 +2,10 @@ import typing as ta
2
2
 
3
3
  from .base import MarshalContext
4
4
  from .base import Marshaler
5
- from .base import MarshalerFactory
5
+ from .base import TypeMapMarshalerFactory
6
+ from .base import TypeMapUnmarshalerFactory
6
7
  from .base import UnmarshalContext
7
8
  from .base import Unmarshaler
8
- from .base import UnmarshalerFactory
9
- from .factories import TypeMapFactory
10
9
  from .values import Value
11
10
 
12
11
 
@@ -34,10 +33,10 @@ class PrimitiveMarshalerUnmarshaler(Marshaler, Unmarshaler):
34
33
 
35
34
  PRIMITIVE_MARSHALER_UNMARSHALER = PrimitiveMarshalerUnmarshaler()
36
35
 
37
- PRIMITIVE_MARSHALER_FACTORY: MarshalerFactory = TypeMapFactory({ # noqa
36
+ PRIMITIVE_MARSHALER_FACTORY = TypeMapMarshalerFactory({ # noqa
38
37
  t: PRIMITIVE_MARSHALER_UNMARSHALER for t in PRIMITIVE_TYPES
39
38
  })
40
39
 
41
- PRIMITIVE_UNMARSHALER_FACTORY: UnmarshalerFactory = TypeMapFactory({ # noqa
40
+ PRIMITIVE_UNMARSHALER_FACTORY = TypeMapUnmarshalerFactory({ # noqa
42
41
  t: PRIMITIVE_MARSHALER_UNMARSHALER for t in PRIMITIVE_TYPES
43
42
  })
@@ -1,8 +1,11 @@
1
+ from .. import matchfns as mfs
1
2
  from .any import ANY_MARSHALER_FACTORY
2
3
  from .any import ANY_UNMARSHALER_FACTORY
3
4
  from .base import MarshalerFactory
4
5
  from .base import RecursiveMarshalerFactory
5
6
  from .base import RecursiveUnmarshalerFactory
7
+ from .base import TypeCacheMarshalerFactory
8
+ from .base import TypeCacheUnmarshalerFactory
6
9
  from .base import UnmarshalerFactory
7
10
  from .base64 import BASE64_MARSHALER_FACTORY
8
11
  from .base64 import BASE64_UNMARSHALER_FACTORY
@@ -12,12 +15,12 @@ from .datetimes import DATETIME_MARSHALER_FACTORY
12
15
  from .datetimes import DATETIME_UNMARSHALER_FACTORY
13
16
  from .enums import EnumMarshalerFactory
14
17
  from .enums import EnumUnmarshalerFactory
15
- from .factories import CompositeFactory
16
- from .factories import TypeCacheFactory
17
18
  from .iterables import IterableMarshalerFactory
18
19
  from .iterables import IterableUnmarshalerFactory
19
20
  from .mappings import MappingMarshalerFactory
20
21
  from .mappings import MappingUnmarshalerFactory
22
+ from .numbers import NUMBERS_MARSHALER_FACTORY
23
+ from .numbers import NUMBERS_UNMARSHALER_FACTORY
21
24
  from .optionals import OptionalMarshalerFactory
22
25
  from .optionals import OptionalUnmarshalerFactory
23
26
  from .primitives import PRIMITIVE_MARSHALER_FACTORY
@@ -34,6 +37,7 @@ STANDARD_MARSHALER_FACTORIES: list[MarshalerFactory] = [
34
37
  OptionalMarshalerFactory(),
35
38
  DataclassMarshalerFactory(),
36
39
  EnumMarshalerFactory(),
40
+ NUMBERS_MARSHALER_FACTORY,
37
41
  UUID_MARSHALER_FACTORY,
38
42
  BASE64_MARSHALER_FACTORY,
39
43
  DATETIME_MARSHALER_FACTORY,
@@ -44,10 +48,10 @@ STANDARD_MARSHALER_FACTORIES: list[MarshalerFactory] = [
44
48
 
45
49
 
46
50
  def new_standard_marshaler_factory() -> MarshalerFactory:
47
- return TypeCacheFactory( # noqa
51
+ return TypeCacheMarshalerFactory(
48
52
  RecursiveMarshalerFactory(
49
- CompositeFactory(
50
- *STANDARD_MARSHALER_FACTORIES,
53
+ mfs.MultiMatchFn(
54
+ list(STANDARD_MARSHALER_FACTORIES),
51
55
  ),
52
56
  ),
53
57
  )
@@ -61,6 +65,7 @@ STANDARD_UNMARSHALER_FACTORIES: list[UnmarshalerFactory] = [
61
65
  OptionalUnmarshalerFactory(),
62
66
  DataclassUnmarshalerFactory(),
63
67
  EnumUnmarshalerFactory(),
68
+ NUMBERS_UNMARSHALER_FACTORY,
64
69
  UUID_UNMARSHALER_FACTORY,
65
70
  BASE64_UNMARSHALER_FACTORY,
66
71
  DATETIME_UNMARSHALER_FACTORY,
@@ -71,10 +76,10 @@ STANDARD_UNMARSHALER_FACTORIES: list[UnmarshalerFactory] = [
71
76
 
72
77
 
73
78
  def new_standard_unmarshaler_factory() -> UnmarshalerFactory:
74
- return TypeCacheFactory( # noqa
79
+ return TypeCacheUnmarshalerFactory(
75
80
  RecursiveUnmarshalerFactory(
76
- CompositeFactory(
77
- *STANDARD_UNMARSHALER_FACTORIES,
81
+ mfs.MultiMatchFn(
82
+ list(STANDARD_UNMARSHALER_FACTORIES),
78
83
  ),
79
84
  ),
80
85
  )
omlish/marshal/uuids.py CHANGED
@@ -4,11 +4,10 @@ import uuid
4
4
  from .. import check
5
5
  from .base import MarshalContext
6
6
  from .base import Marshaler
7
- from .base import MarshalerFactory
7
+ from .base import TypeMapMarshalerFactory
8
+ from .base import TypeMapUnmarshalerFactory
8
9
  from .base import UnmarshalContext
9
10
  from .base import Unmarshaler
10
- from .base import UnmarshalerFactory
11
- from .factories import TypeMapFactory
12
11
  from .values import Value
13
12
 
14
13
 
@@ -25,5 +24,5 @@ class UuidMarshalerUnmarshaler(Marshaler, Unmarshaler):
25
24
 
26
25
  UUID_MARSHALER_UNMARSHALER = UuidMarshalerUnmarshaler()
27
26
 
28
- UUID_MARSHALER_FACTORY: MarshalerFactory = TypeMapFactory({uuid.UUID: UUID_MARSHALER_UNMARSHALER})
29
- UUID_UNMARSHALER_FACTORY: UnmarshalerFactory = TypeMapFactory({uuid.UUID: UUID_MARSHALER_UNMARSHALER})
27
+ UUID_MARSHALER_FACTORY = TypeMapMarshalerFactory({uuid.UUID: UUID_MARSHALER_UNMARSHALER})
28
+ UUID_UNMARSHALER_FACTORY = TypeMapUnmarshalerFactory({uuid.UUID: UUID_MARSHALER_UNMARSHALER})