omlish 0.0.0.dev1__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 (187) hide show
  1. omlish/__about__.py +7 -0
  2. omlish/__init__.py +0 -0
  3. omlish/argparse.py +223 -0
  4. omlish/asyncs/__init__.py +17 -0
  5. omlish/asyncs/anyio.py +23 -0
  6. omlish/asyncs/asyncio.py +19 -0
  7. omlish/asyncs/asyncs.py +76 -0
  8. omlish/asyncs/futures.py +179 -0
  9. omlish/asyncs/trio.py +11 -0
  10. omlish/c3.py +173 -0
  11. omlish/cached.py +9 -0
  12. omlish/check.py +231 -0
  13. omlish/collections/__init__.py +63 -0
  14. omlish/collections/_abc.py +156 -0
  15. omlish/collections/_io_abc.py +78 -0
  16. omlish/collections/cache/__init__.py +11 -0
  17. omlish/collections/cache/descriptor.py +188 -0
  18. omlish/collections/cache/impl.py +485 -0
  19. omlish/collections/cache/types.py +37 -0
  20. omlish/collections/coerce.py +337 -0
  21. omlish/collections/frozen.py +148 -0
  22. omlish/collections/identity.py +106 -0
  23. omlish/collections/indexed.py +75 -0
  24. omlish/collections/mappings.py +127 -0
  25. omlish/collections/ordered.py +81 -0
  26. omlish/collections/persistent.py +36 -0
  27. omlish/collections/skiplist.py +193 -0
  28. omlish/collections/sorted.py +126 -0
  29. omlish/collections/treap.py +228 -0
  30. omlish/collections/treapmap.py +144 -0
  31. omlish/collections/unmodifiable.py +174 -0
  32. omlish/collections/utils.py +110 -0
  33. omlish/configs/__init__.py +0 -0
  34. omlish/configs/flattening.py +147 -0
  35. omlish/configs/props.py +64 -0
  36. omlish/dataclasses/__init__.py +83 -0
  37. omlish/dataclasses/impl/__init__.py +6 -0
  38. omlish/dataclasses/impl/api.py +260 -0
  39. omlish/dataclasses/impl/as_.py +76 -0
  40. omlish/dataclasses/impl/exceptions.py +2 -0
  41. omlish/dataclasses/impl/fields.py +148 -0
  42. omlish/dataclasses/impl/frozen.py +55 -0
  43. omlish/dataclasses/impl/hashing.py +85 -0
  44. omlish/dataclasses/impl/init.py +173 -0
  45. omlish/dataclasses/impl/internals.py +118 -0
  46. omlish/dataclasses/impl/main.py +150 -0
  47. omlish/dataclasses/impl/metaclass.py +126 -0
  48. omlish/dataclasses/impl/metadata.py +74 -0
  49. omlish/dataclasses/impl/order.py +47 -0
  50. omlish/dataclasses/impl/params.py +150 -0
  51. omlish/dataclasses/impl/processing.py +16 -0
  52. omlish/dataclasses/impl/reflect.py +173 -0
  53. omlish/dataclasses/impl/replace.py +40 -0
  54. omlish/dataclasses/impl/repr.py +34 -0
  55. omlish/dataclasses/impl/simple.py +92 -0
  56. omlish/dataclasses/impl/slots.py +80 -0
  57. omlish/dataclasses/impl/utils.py +167 -0
  58. omlish/defs.py +193 -0
  59. omlish/dispatch/__init__.py +3 -0
  60. omlish/dispatch/dispatch.py +137 -0
  61. omlish/dispatch/functions.py +52 -0
  62. omlish/dispatch/methods.py +162 -0
  63. omlish/docker.py +149 -0
  64. omlish/dynamic.py +220 -0
  65. omlish/graphs/__init__.py +0 -0
  66. omlish/graphs/dot/__init__.py +19 -0
  67. omlish/graphs/dot/items.py +162 -0
  68. omlish/graphs/dot/rendering.py +147 -0
  69. omlish/graphs/dot/utils.py +30 -0
  70. omlish/graphs/trees.py +249 -0
  71. omlish/http/__init__.py +0 -0
  72. omlish/http/consts.py +20 -0
  73. omlish/http/wsgi.py +34 -0
  74. omlish/inject/__init__.py +85 -0
  75. omlish/inject/binder.py +12 -0
  76. omlish/inject/bindings.py +49 -0
  77. omlish/inject/eagers.py +21 -0
  78. omlish/inject/elements.py +43 -0
  79. omlish/inject/exceptions.py +49 -0
  80. omlish/inject/impl/__init__.py +0 -0
  81. omlish/inject/impl/bindings.py +19 -0
  82. omlish/inject/impl/elements.py +154 -0
  83. omlish/inject/impl/injector.py +182 -0
  84. omlish/inject/impl/inspect.py +98 -0
  85. omlish/inject/impl/private.py +109 -0
  86. omlish/inject/impl/providers.py +132 -0
  87. omlish/inject/impl/scopes.py +198 -0
  88. omlish/inject/injector.py +40 -0
  89. omlish/inject/inspect.py +14 -0
  90. omlish/inject/keys.py +43 -0
  91. omlish/inject/managed.py +24 -0
  92. omlish/inject/overrides.py +18 -0
  93. omlish/inject/private.py +29 -0
  94. omlish/inject/providers.py +111 -0
  95. omlish/inject/proxy.py +48 -0
  96. omlish/inject/scopes.py +84 -0
  97. omlish/inject/types.py +21 -0
  98. omlish/iterators.py +184 -0
  99. omlish/json.py +194 -0
  100. omlish/lang/__init__.py +112 -0
  101. omlish/lang/cached.py +267 -0
  102. omlish/lang/classes/__init__.py +24 -0
  103. omlish/lang/classes/abstract.py +74 -0
  104. omlish/lang/classes/restrict.py +137 -0
  105. omlish/lang/classes/simple.py +120 -0
  106. omlish/lang/classes/test/__init__.py +0 -0
  107. omlish/lang/classes/test/test_abstract.py +89 -0
  108. omlish/lang/classes/test/test_restrict.py +71 -0
  109. omlish/lang/classes/test/test_simple.py +58 -0
  110. omlish/lang/classes/test/test_virtual.py +72 -0
  111. omlish/lang/classes/virtual.py +130 -0
  112. omlish/lang/clsdct.py +67 -0
  113. omlish/lang/cmp.py +63 -0
  114. omlish/lang/contextmanagers.py +249 -0
  115. omlish/lang/datetimes.py +67 -0
  116. omlish/lang/descriptors.py +52 -0
  117. omlish/lang/functions.py +126 -0
  118. omlish/lang/imports.py +153 -0
  119. omlish/lang/iterables.py +54 -0
  120. omlish/lang/maybes.py +136 -0
  121. omlish/lang/objects.py +103 -0
  122. omlish/lang/resolving.py +50 -0
  123. omlish/lang/strings.py +128 -0
  124. omlish/lang/typing.py +92 -0
  125. omlish/libc.py +532 -0
  126. omlish/logs/__init__.py +9 -0
  127. omlish/logs/_abc.py +247 -0
  128. omlish/logs/configs.py +62 -0
  129. omlish/logs/filters.py +9 -0
  130. omlish/logs/formatters.py +67 -0
  131. omlish/logs/utils.py +20 -0
  132. omlish/marshal/__init__.py +52 -0
  133. omlish/marshal/any.py +25 -0
  134. omlish/marshal/base.py +201 -0
  135. omlish/marshal/base64.py +25 -0
  136. omlish/marshal/dataclasses.py +115 -0
  137. omlish/marshal/datetimes.py +90 -0
  138. omlish/marshal/enums.py +43 -0
  139. omlish/marshal/exceptions.py +7 -0
  140. omlish/marshal/factories.py +129 -0
  141. omlish/marshal/global_.py +33 -0
  142. omlish/marshal/iterables.py +57 -0
  143. omlish/marshal/mappings.py +66 -0
  144. omlish/marshal/naming.py +17 -0
  145. omlish/marshal/objects.py +106 -0
  146. omlish/marshal/optionals.py +49 -0
  147. omlish/marshal/polymorphism.py +147 -0
  148. omlish/marshal/primitives.py +43 -0
  149. omlish/marshal/registries.py +57 -0
  150. omlish/marshal/standard.py +80 -0
  151. omlish/marshal/utils.py +23 -0
  152. omlish/marshal/uuids.py +29 -0
  153. omlish/marshal/values.py +30 -0
  154. omlish/math.py +184 -0
  155. omlish/os.py +32 -0
  156. omlish/reflect.py +359 -0
  157. omlish/replserver/__init__.py +5 -0
  158. omlish/replserver/__main__.py +4 -0
  159. omlish/replserver/console.py +247 -0
  160. omlish/replserver/server.py +146 -0
  161. omlish/runmodule.py +28 -0
  162. omlish/stats.py +342 -0
  163. omlish/term.py +222 -0
  164. omlish/testing/__init__.py +7 -0
  165. omlish/testing/pydevd.py +225 -0
  166. omlish/testing/pytest/__init__.py +8 -0
  167. omlish/testing/pytest/helpers.py +35 -0
  168. omlish/testing/pytest/inject/__init__.py +1 -0
  169. omlish/testing/pytest/inject/harness.py +159 -0
  170. omlish/testing/pytest/plugins/__init__.py +20 -0
  171. omlish/testing/pytest/plugins/_registry.py +6 -0
  172. omlish/testing/pytest/plugins/logging.py +13 -0
  173. omlish/testing/pytest/plugins/pycharm.py +54 -0
  174. omlish/testing/pytest/plugins/repeat.py +19 -0
  175. omlish/testing/pytest/plugins/skips.py +32 -0
  176. omlish/testing/pytest/plugins/spacing.py +19 -0
  177. omlish/testing/pytest/plugins/switches.py +70 -0
  178. omlish/testing/testing.py +102 -0
  179. omlish/text/__init__.py +0 -0
  180. omlish/text/delimit.py +171 -0
  181. omlish/text/indent.py +50 -0
  182. omlish/text/parts.py +265 -0
  183. omlish-0.0.0.dev1.dist-info/LICENSE +21 -0
  184. omlish-0.0.0.dev1.dist-info/METADATA +17 -0
  185. omlish-0.0.0.dev1.dist-info/RECORD +187 -0
  186. omlish-0.0.0.dev1.dist-info/WHEEL +5 -0
  187. omlish-0.0.0.dev1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,49 @@
1
+ import dataclasses as dc
2
+ import typing as ta
3
+
4
+ from .. import reflect as rfl
5
+ from .base import MarshalContext
6
+ from .base import Marshaler
7
+ from .base import MarshalerFactory
8
+ from .base import UnmarshalContext
9
+ from .base import Unmarshaler
10
+ from .base import UnmarshalerFactory
11
+ from .values import Value
12
+
13
+
14
+ @dc.dataclass(frozen=True)
15
+ class OptionalMarshaler(Marshaler):
16
+ e: Marshaler
17
+
18
+ def marshal(self, ctx: MarshalContext, o: ta.Optional[ta.Any]) -> Value:
19
+ if o is None:
20
+ return None
21
+ return self.e.marshal(ctx, o)
22
+
23
+
24
+ class OptionalMarshalerFactory(MarshalerFactory):
25
+ def __call__(self, ctx: MarshalContext, rty: rfl.Type) -> ta.Optional[Marshaler]:
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
31
+
32
+
33
+ @dc.dataclass(frozen=True)
34
+ class OptionalUnmarshaler(Unmarshaler):
35
+ e: Unmarshaler
36
+
37
+ def unmarshal(self, ctx: UnmarshalContext, v: Value) -> ta.Optional[ta.Any]:
38
+ if v is None:
39
+ return None
40
+ return self.e.unmarshal(ctx, v)
41
+
42
+
43
+ class OptionalUnmarshalerFactory(UnmarshalerFactory):
44
+ def __call__(self, ctx: UnmarshalContext, rty: rfl.Type) -> ta.Optional[Unmarshaler]:
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
@@ -0,0 +1,147 @@
1
+ """
2
+ TODO:
3
+ - auto-gen from __subclasses__ if abstract
4
+ - cfg: unless prefixed with _ or abstract
5
+ - auto-name
6
+ """
7
+ import collections.abc
8
+ import dataclasses as dc
9
+ import typing as ta
10
+
11
+ from .. import check
12
+ from .. import lang
13
+ from .. import reflect as rfl
14
+ from .base import MarshalContext
15
+ from .base import Marshaler
16
+ from .base import MarshalerFactory
17
+ from .base import UnmarshalContext
18
+ from .base import Unmarshaler
19
+ from .base import UnmarshalerFactory
20
+ from .naming import Naming
21
+ from .naming import translate_name
22
+ from .values import Value
23
+
24
+
25
+ ##
26
+
27
+
28
+ @dc.dataclass(frozen=True)
29
+ class Impl:
30
+ ty: type
31
+ tag: str
32
+ alts: ta.AbstractSet[str] = frozenset()
33
+
34
+
35
+ class Polymorphism:
36
+ def __init__(self, ty: type, impls: ta.Iterable[Impl]) -> None:
37
+ super().__init__()
38
+ self._ty = ty
39
+ self._impls = list(impls)
40
+
41
+ by_ty: dict[type, Impl] = {}
42
+ by_tag: dict[str, Impl] = {}
43
+ for i in self._impls:
44
+ if not issubclass(i.ty, ty) or i.ty in by_ty:
45
+ raise TypeError(i.ty, ty)
46
+ if i.tag in by_tag:
47
+ raise NameError(i.tag)
48
+ for a in i.alts:
49
+ if a in by_tag:
50
+ raise NameError(a)
51
+ by_ty[i.ty] = i
52
+ by_tag[i.tag] = i
53
+ for a in i.alts:
54
+ by_tag[a] = i
55
+ self._by_ty = by_ty
56
+ self._by_tag = by_tag
57
+
58
+ @property
59
+ def ty(self) -> type:
60
+ return self._ty
61
+
62
+ @property
63
+ def impls(self) -> ta.Sequence[Impl]:
64
+ return self._impls
65
+
66
+ @property
67
+ def by_ty(self) -> ta.Mapping[type, Impl]:
68
+ return self._by_ty
69
+
70
+ @property
71
+ def by_tag(self) -> ta.Mapping[str, Impl]:
72
+ return self._by_tag
73
+
74
+
75
+ def polymorphism_from_subclasses(ty: type, *, naming: Naming | None = None) -> Polymorphism:
76
+ dct: dict[str, Impl] = {}
77
+ seen: set[type] = set()
78
+ todo: list[type] = [ty]
79
+ while todo:
80
+ cur = todo.pop()
81
+ seen.add(cur)
82
+ if not lang.is_abstract_class(cur):
83
+ nam = cur.__name__
84
+ if naming is not None:
85
+ nam = translate_name(nam, naming)
86
+ if nam in dct:
87
+ raise KeyError(f'Duplicate name: {nam}')
88
+ dct[nam] = Impl(
89
+ cur,
90
+ nam,
91
+ )
92
+ todo.extend(nxt for nxt in cur.__subclasses__() if nxt not in seen)
93
+ return Polymorphism(ty, dct.values())
94
+
95
+
96
+ ##
97
+
98
+
99
+ @dc.dataclass(frozen=True)
100
+ class PolymorphismMarshaler(Marshaler):
101
+ m: ta.Mapping[type, tuple[str, Marshaler]]
102
+
103
+ def marshal(self, ctx: MarshalContext, o: ta.Optional[ta.Any]) -> Value:
104
+ tag, m = self.m[type(o)]
105
+ return {tag: m.marshal(ctx, o)}
106
+
107
+
108
+ @dc.dataclass(frozen=True)
109
+ class PolymorphismMarshalerFactory(MarshalerFactory):
110
+ p: Polymorphism
111
+
112
+ def __call__(self, ctx: MarshalContext, rty: rfl.Type) -> ta.Optional[Marshaler]:
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
119
+
120
+
121
+ ##
122
+
123
+
124
+ @dc.dataclass(frozen=True)
125
+ class PolymorphismUnmarshaler(Unmarshaler):
126
+ m: ta.Mapping[str, Unmarshaler]
127
+
128
+ def unmarshal(self, ctx: UnmarshalContext, v: Value) -> ta.Optional[ta.Any]:
129
+ ma = check.isinstance(v, collections.abc.Mapping)
130
+ [(tag, iv)] = ma.items()
131
+ u = self.m[tag] # type: ignore
132
+ return u.unmarshal(ctx, iv) # type: ignore
133
+
134
+
135
+ @dc.dataclass(frozen=True)
136
+ class PolymorphismUnmarshalerFactory(UnmarshalerFactory):
137
+ p: Polymorphism
138
+
139
+ def __call__(self, ctx: UnmarshalContext, rty: rfl.Type) -> ta.Optional[Unmarshaler]:
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
@@ -0,0 +1,43 @@
1
+ import typing as ta
2
+
3
+ from .base import MarshalContext
4
+ from .base import Marshaler
5
+ from .base import MarshalerFactory
6
+ from .base import UnmarshalContext
7
+ from .base import Unmarshaler
8
+ from .base import UnmarshalerFactory
9
+ from .factories import TypeMapFactory
10
+ from .values import Value
11
+
12
+
13
+ PRIMITIVE_TYPES: tuple[type, ...] = (
14
+ bool,
15
+ int,
16
+ float,
17
+ str,
18
+ bytes,
19
+ type(None),
20
+ )
21
+
22
+
23
+ class PrimitiveMarshalerUnmarshaler(Marshaler, Unmarshaler):
24
+ def marshal(self, ctx: MarshalContext, o: ta.Any) -> Value:
25
+ if isinstance(o, PRIMITIVE_TYPES):
26
+ return o # type: ignore
27
+ raise TypeError(o)
28
+
29
+ def unmarshal(self, ctx: UnmarshalContext, v: Value) -> ta.Any:
30
+ if isinstance(v, PRIMITIVE_TYPES):
31
+ return v
32
+ raise TypeError(v)
33
+
34
+
35
+ PRIMITIVE_MARSHALER_UNMARSHALER = PrimitiveMarshalerUnmarshaler()
36
+
37
+ PRIMITIVE_MARSHALER_FACTORY: MarshalerFactory = TypeMapFactory({ # noqa
38
+ t: PRIMITIVE_MARSHALER_UNMARSHALER for t in PRIMITIVE_TYPES
39
+ })
40
+
41
+ PRIMITIVE_UNMARSHALER_FACTORY: UnmarshalerFactory = TypeMapFactory({ # noqa
42
+ t: PRIMITIVE_MARSHALER_UNMARSHALER for t in PRIMITIVE_TYPES
43
+ })
@@ -0,0 +1,57 @@
1
+ import abc
2
+ import dataclasses as dc
3
+ import threading
4
+ import typing as ta
5
+
6
+ from .. import check
7
+ from .. import reflect as rfl
8
+
9
+
10
+ class RegistryItem(abc.ABC):
11
+ pass
12
+
13
+
14
+ RegistryItemT = ta.TypeVar('RegistryItemT', bound=RegistryItem)
15
+
16
+
17
+ @dc.dataclass(frozen=True)
18
+ class _TypeRegistry:
19
+ rty: rfl.Type
20
+ items: list[RegistryItem] = dc.field(default_factory=list)
21
+ item_lists_by_ty: dict[type[RegistryItem], list[RegistryItem]] = dc.field(default_factory=dict)
22
+
23
+ def add(self, *items: RegistryItem) -> None:
24
+ for i in items:
25
+ self.items.append(i)
26
+ self.item_lists_by_ty.setdefault(type(i), []).append(i)
27
+
28
+
29
+ class Registry:
30
+ def __init__(self) -> None:
31
+ super().__init__()
32
+ self._mtx = threading.Lock()
33
+ self._dct: dict[rfl.Type, _TypeRegistry] = {}
34
+ self._ps: ta.Sequence['Registry'] = []
35
+
36
+ def register(self, rty: rfl.Type, *items: RegistryItem) -> 'Registry':
37
+ check.isinstance(rty, rfl.TYPES)
38
+ with self._mtx:
39
+ if (sr := self._dct.get(rty)) is None:
40
+ sr = self._dct[rty] = _TypeRegistry(rty)
41
+ sr.add(*items)
42
+ return self
43
+
44
+ def get(self, rty: rfl.Type) -> ta.Sequence[RegistryItem]:
45
+ check.isinstance(rty, rfl.TYPES)
46
+ try:
47
+ return self._dct[rty].items
48
+ except KeyError:
49
+ return ()
50
+
51
+ def get_of(self, rty: rfl.Type, item_ty: type[RegistryItemT]) -> ta.Sequence[RegistryItemT]:
52
+ check.isinstance(rty, rfl.TYPES)
53
+ try:
54
+ sr = self._dct[rty]
55
+ except KeyError:
56
+ return ()
57
+ return sr.item_lists_by_ty.get(item_ty, ()) # type: ignore
@@ -0,0 +1,80 @@
1
+ from .any import ANY_MARSHALER_FACTORY
2
+ from .any import ANY_UNMARSHALER_FACTORY
3
+ from .base import MarshalerFactory
4
+ from .base import RecursiveMarshalerFactory
5
+ from .base import RecursiveUnmarshalerFactory
6
+ from .base import UnmarshalerFactory
7
+ from .base64 import BASE64_MARSHALER_FACTORY
8
+ from .base64 import BASE64_UNMARSHALER_FACTORY
9
+ from .dataclasses import DataclassMarshalerFactory
10
+ from .dataclasses import DataclassUnmarshalerFactory
11
+ from .datetimes import DATETIME_MARSHALER_FACTORY
12
+ from .datetimes import DATETIME_UNMARSHALER_FACTORY
13
+ from .enums import EnumMarshalerFactory
14
+ from .enums import EnumUnmarshalerFactory
15
+ from .factories import CompositeFactory
16
+ from .factories import TypeCacheFactory
17
+ from .iterables import IterableMarshalerFactory
18
+ from .iterables import IterableUnmarshalerFactory
19
+ from .mappings import MappingMarshalerFactory
20
+ from .mappings import MappingUnmarshalerFactory
21
+ from .optionals import OptionalMarshalerFactory
22
+ from .optionals import OptionalUnmarshalerFactory
23
+ from .primitives import PRIMITIVE_MARSHALER_FACTORY
24
+ from .primitives import PRIMITIVE_UNMARSHALER_FACTORY
25
+ from .uuids import UUID_MARSHALER_FACTORY
26
+ from .uuids import UUID_UNMARSHALER_FACTORY
27
+
28
+
29
+ ##
30
+
31
+
32
+ STANDARD_MARSHALER_FACTORIES: list[MarshalerFactory] = [
33
+ PRIMITIVE_MARSHALER_FACTORY,
34
+ OptionalMarshalerFactory(),
35
+ DataclassMarshalerFactory(),
36
+ EnumMarshalerFactory(),
37
+ UUID_MARSHALER_FACTORY,
38
+ BASE64_MARSHALER_FACTORY,
39
+ DATETIME_MARSHALER_FACTORY,
40
+ MappingMarshalerFactory(),
41
+ IterableMarshalerFactory(),
42
+ ANY_MARSHALER_FACTORY,
43
+ ]
44
+
45
+
46
+ def new_standard_marshaler_factory() -> MarshalerFactory:
47
+ return TypeCacheFactory( # noqa
48
+ RecursiveMarshalerFactory(
49
+ CompositeFactory(
50
+ *STANDARD_MARSHALER_FACTORIES
51
+ )
52
+ )
53
+ )
54
+
55
+
56
+ ##
57
+
58
+
59
+ STANDARD_UNMARSHALER_FACTORIES: list[UnmarshalerFactory] = [
60
+ PRIMITIVE_UNMARSHALER_FACTORY,
61
+ OptionalUnmarshalerFactory(),
62
+ DataclassUnmarshalerFactory(),
63
+ EnumUnmarshalerFactory(),
64
+ UUID_UNMARSHALER_FACTORY,
65
+ BASE64_UNMARSHALER_FACTORY,
66
+ DATETIME_UNMARSHALER_FACTORY,
67
+ MappingUnmarshalerFactory(),
68
+ IterableUnmarshalerFactory(),
69
+ ANY_UNMARSHALER_FACTORY,
70
+ ]
71
+
72
+
73
+ def new_standard_unmarshaler_factory() -> UnmarshalerFactory:
74
+ return TypeCacheFactory( # noqa
75
+ RecursiveUnmarshalerFactory(
76
+ CompositeFactory(
77
+ *STANDARD_UNMARSHALER_FACTORIES
78
+ )
79
+ )
80
+ )
@@ -0,0 +1,23 @@
1
+ import typing as ta
2
+
3
+
4
+ T = ta.TypeVar('T')
5
+
6
+
7
+ class _Proxy(ta.Generic[T]):
8
+ __obj: ta.Optional[T] = None
9
+
10
+ @property
11
+ def _obj(self) -> T:
12
+ if self.__obj is None:
13
+ raise TypeError('recursive proxy not set')
14
+ return self.__obj
15
+
16
+ def _set_obj(self, obj: T) -> None:
17
+ if self.__obj is not None:
18
+ raise TypeError('recursive proxy already set')
19
+ self.__obj = obj
20
+
21
+ @classmethod
22
+ def _new(cls):
23
+ return (p := cls()), p._set_obj
@@ -0,0 +1,29 @@
1
+ import re
2
+ import uuid
3
+
4
+ from .. import check
5
+ from .base import MarshalContext
6
+ from .base import Marshaler
7
+ from .base import MarshalerFactory
8
+ from .base import UnmarshalContext
9
+ from .base import Unmarshaler
10
+ from .base import UnmarshalerFactory
11
+ from .factories import TypeMapFactory
12
+ from .values import Value
13
+
14
+
15
+ PATTERN = re.compile(r'([0-9A-Fa-f]{8}-([0-9A-Fa-f]{4}-){3}[0-9A-Fa-f]{12})|([0-9A-Fa-f]{32})')
16
+
17
+
18
+ class UuidMarshalerUnmarshaler(Marshaler, Unmarshaler):
19
+ def marshal(self, ctx: MarshalContext, o: uuid.UUID) -> Value:
20
+ return str(o)
21
+
22
+ def unmarshal(self, ctx: UnmarshalContext, v: Value) -> uuid.UUID:
23
+ return uuid.UUID(check.isinstance(v, str).replace('-', ''))
24
+
25
+
26
+ UUID_MARSHALER_UNMARSHALER = UuidMarshalerUnmarshaler()
27
+
28
+ UUID_MARSHALER_FACTORY: MarshalerFactory = TypeMapFactory({uuid.UUID: UUID_MARSHALER_UNMARSHALER})
29
+ UUID_UNMARSHALER_FACTORY: UnmarshalerFactory = TypeMapFactory({uuid.UUID: UUID_MARSHALER_UNMARSHALER})
@@ -0,0 +1,30 @@
1
+ """
2
+ Null
3
+ Bool
4
+ Int
5
+ Float
6
+ Number
7
+ String
8
+ Bytes
9
+ Array
10
+ Object
11
+ Any
12
+ """
13
+ import typing as ta
14
+
15
+
16
+ Value = ta.Union[
17
+ None,
18
+
19
+ bool,
20
+ int,
21
+ float,
22
+ # Number,
23
+ str,
24
+ bytes,
25
+
26
+ list, # list[Value],
27
+ dict, # dict[str, Value],
28
+
29
+ # ta.Any,
30
+ ]
omlish/math.py ADDED
@@ -0,0 +1,184 @@
1
+ import functools
2
+ import struct
3
+ import typing as ta
4
+
5
+
6
+ ##
7
+
8
+
9
+ def isclose(a: float, b: float, *, rel_tol: float = 1e-09, abs_tol: float = 0.0) -> float:
10
+ return abs(a - b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)
11
+
12
+
13
+ def get_bit(bit: int, value: int) -> int:
14
+ return (value >> bit) & 1
15
+
16
+
17
+ def get_bits(bits_from: int, num_bits: int, value: int) -> int:
18
+ return (value & ((1 << (bits_from + num_bits)) - 1)) >> bits_from
19
+
20
+
21
+ def set_bit(bit: int, bit_value: int, value: int) -> int:
22
+ if bit_value:
23
+ return value | (1 << bit)
24
+ else:
25
+ return value & ~(1 << bit)
26
+
27
+
28
+ def set_bits(bits_from: int, num_bits: int, bits_value: int, value: int) -> int:
29
+ return value & ~(((1 << num_bits) - 1) << bits_from) | (bits_value << bits_from)
30
+
31
+
32
+ def float_to_bytes(f: float) -> bytes:
33
+ return struct.pack('>f', f)
34
+
35
+
36
+ def bytes_to_float(b: bytes) -> float:
37
+ return struct.unpack('>f', b)[0]
38
+
39
+
40
+ ##
41
+
42
+
43
+ def _gen_scalar_proxy_method(name):
44
+ def inner(self, *args, **kwargs):
45
+ return self.__class__(orig(self, *args, **kwargs))
46
+
47
+ orig = getattr(int, name)
48
+ return functools.wraps(orig)(inner)
49
+
50
+
51
+ def _gen_tuple_proxy_method(name):
52
+ def inner(self, *args, **kwargs):
53
+ return tuple(map(self.__class__, orig(self, *args, **kwargs)))
54
+
55
+ orig = getattr(int, name)
56
+ return functools.wraps(orig)(inner)
57
+
58
+
59
+ class FixedWidthInt(int):
60
+
61
+ BITS: ta.ClassVar[int]
62
+ SIGNED: ta.ClassVar[bool]
63
+
64
+ MIN: ta.ClassVar[int]
65
+ MAX: ta.ClassVar[int]
66
+
67
+ MASK: ta.ClassVar[int]
68
+
69
+ def __init_subclass__(cls, **kwargs):
70
+ super().__init_subclass__()
71
+
72
+ if not isinstance(cls.BITS, int):
73
+ raise TypeError(cls.BITS)
74
+
75
+ if cls.SIGNED:
76
+ cls.MIN = -(1 << (cls.BITS - 1))
77
+ cls.MAX = (1 << (cls.BITS - 1)) - 1
78
+ else:
79
+ cls.MIN = 0
80
+ cls.MAX = (1 << cls.BITS) - 1
81
+
82
+ cls.MASK = (1 << cls.BITS) - 1
83
+
84
+ @classmethod
85
+ def clamp(cls, value):
86
+ return ((value - cls.MIN) & cls.MASK) + cls.MIN
87
+
88
+ def __new__(cls, value, *args, **kwargs):
89
+ return super().__new__(cls, cls.clamp(value))
90
+
91
+ SCALAR_PROXY_METHODS = {
92
+ '__abs__',
93
+ '__add__',
94
+ '__and__',
95
+ '__floordiv__',
96
+ '__invert__',
97
+ '__lshift__',
98
+ '__mod__',
99
+ '__mul__',
100
+ '__neg__',
101
+ '__or__',
102
+ '__pos__',
103
+ '__pow__',
104
+ '__radd__',
105
+ '__rand__',
106
+ '__rfloordiv__',
107
+ '__rlshift__',
108
+ '__rmod__',
109
+ '__rmul__',
110
+ '__ror__',
111
+ '__rpow__',
112
+ '__rrshift__',
113
+ '__rshift__',
114
+ '__rsub__',
115
+ '__rtruediv__',
116
+ '__rxor__',
117
+ '__sub__',
118
+ '__truediv__',
119
+ '__xor__',
120
+ }
121
+
122
+ TUPLE_PROXY_METHODS = {
123
+ '__divmod__',
124
+ '__rdivmod__',
125
+ }
126
+
127
+ for _proxy_name in SCALAR_PROXY_METHODS:
128
+ locals()[_proxy_name] = _gen_scalar_proxy_method(_proxy_name)
129
+ for _proxy_name in TUPLE_PROXY_METHODS:
130
+ locals()[_proxy_name] = _gen_tuple_proxy_method(_proxy_name)
131
+ del _proxy_name
132
+
133
+ def __repr__(self):
134
+ return f'{self.__class__.__name__}({int(self)})'
135
+
136
+
137
+ class Int8(FixedWidthInt):
138
+ BITS = 8
139
+ SIGNED = True
140
+
141
+
142
+ class Int16(FixedWidthInt):
143
+ BITS = 16
144
+ SIGNED = True
145
+
146
+
147
+ class Int32(FixedWidthInt):
148
+ BITS = 32
149
+ SIGNED = True
150
+
151
+
152
+ class Int64(FixedWidthInt):
153
+ BITS = 64
154
+ SIGNED = True
155
+
156
+
157
+ class Int128(FixedWidthInt):
158
+ BITS = 128
159
+ SIGNED = True
160
+
161
+
162
+ class Uint8(FixedWidthInt):
163
+ BITS = 8
164
+ SIGNED = False
165
+
166
+
167
+ class Uint16(FixedWidthInt):
168
+ BITS = 16
169
+ SIGNED = False
170
+
171
+
172
+ class Uint32(FixedWidthInt):
173
+ BITS = 32
174
+ SIGNED = False
175
+
176
+
177
+ class Uint64(FixedWidthInt):
178
+ BITS = 64
179
+ SIGNED = False
180
+
181
+
182
+ class Uint128(FixedWidthInt):
183
+ BITS = 128
184
+ SIGNED = False
omlish/os.py ADDED
@@ -0,0 +1,32 @@
1
+ import contextlib
2
+ import shutil
3
+ import tempfile
4
+ import typing as ta
5
+
6
+
7
+ @contextlib.contextmanager
8
+ def tmp_dir(
9
+ root_dir: ta.Optional[str] = None,
10
+ cleanup: bool = True,
11
+ **kwargs: ta.Any
12
+ ) -> ta.Iterator[str]:
13
+ path = tempfile.mkdtemp(dir=root_dir, **kwargs)
14
+ try:
15
+ yield path
16
+ finally:
17
+ if cleanup:
18
+ shutil.rmtree(path, ignore_errors=True)
19
+
20
+
21
+ @contextlib.contextmanager
22
+ def tmp_file(
23
+ root_dir: ta.Optional[str] = None,
24
+ cleanup: bool = True,
25
+ **kwargs: ta.Any
26
+ ) -> ta.Iterator[tempfile._TemporaryFileWrapper]: # noqa
27
+ with tempfile.NamedTemporaryFile(dir=root_dir, delete=False, **kwargs) as f:
28
+ try:
29
+ yield f
30
+ finally:
31
+ if cleanup:
32
+ shutil.rmtree(f.name, ignore_errors=True)