omlish 0.0.0.dev133__py3-none-any.whl → 0.0.0.dev177__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 (210) hide show
  1. omlish/.manifests.json +265 -7
  2. omlish/__about__.py +5 -3
  3. omlish/antlr/_runtime/__init__.py +0 -22
  4. omlish/antlr/_runtime/_all.py +24 -0
  5. omlish/antlr/_runtime/atn/ParserATNSimulator.py +1 -1
  6. omlish/antlr/_runtime/dfa/DFASerializer.py +1 -1
  7. omlish/antlr/_runtime/error/DiagnosticErrorListener.py +2 -1
  8. omlish/antlr/_runtime/xpath/XPath.py +7 -1
  9. omlish/antlr/_runtime/xpath/XPathLexer.py +1 -1
  10. omlish/antlr/delimit.py +106 -0
  11. omlish/antlr/dot.py +31 -0
  12. omlish/antlr/errors.py +11 -0
  13. omlish/antlr/input.py +96 -0
  14. omlish/antlr/parsing.py +19 -0
  15. omlish/antlr/runtime.py +102 -0
  16. omlish/antlr/utils.py +38 -0
  17. omlish/argparse/all.py +45 -0
  18. omlish/{argparse.py → argparse/cli.py} +112 -107
  19. omlish/asyncs/__init__.py +0 -35
  20. omlish/asyncs/all.py +35 -0
  21. omlish/asyncs/asyncio/all.py +7 -0
  22. omlish/asyncs/asyncio/channels.py +40 -0
  23. omlish/asyncs/asyncio/streams.py +45 -0
  24. omlish/asyncs/asyncio/subprocesses.py +238 -0
  25. omlish/asyncs/asyncio/timeouts.py +16 -0
  26. omlish/asyncs/bluelet/LICENSE +6 -0
  27. omlish/asyncs/bluelet/all.py +67 -0
  28. omlish/asyncs/bluelet/api.py +23 -0
  29. omlish/asyncs/bluelet/core.py +178 -0
  30. omlish/asyncs/bluelet/events.py +78 -0
  31. omlish/asyncs/bluelet/files.py +80 -0
  32. omlish/asyncs/bluelet/runner.py +416 -0
  33. omlish/asyncs/bluelet/sockets.py +214 -0
  34. omlish/bootstrap/sys.py +3 -3
  35. omlish/cached.py +2 -2
  36. omlish/check.py +49 -460
  37. omlish/codecs/__init__.py +72 -0
  38. omlish/codecs/base.py +106 -0
  39. omlish/codecs/bytes.py +119 -0
  40. omlish/codecs/chain.py +23 -0
  41. omlish/codecs/funcs.py +39 -0
  42. omlish/codecs/registry.py +139 -0
  43. omlish/codecs/standard.py +4 -0
  44. omlish/codecs/text.py +217 -0
  45. omlish/collections/cache/impl.py +50 -57
  46. omlish/collections/coerce.py +1 -0
  47. omlish/collections/mappings.py +1 -1
  48. omlish/configs/flattening.py +1 -1
  49. omlish/defs.py +1 -1
  50. omlish/diag/_pycharm/runhack.py +8 -2
  51. omlish/diag/procfs.py +8 -8
  52. omlish/docker/__init__.py +0 -36
  53. omlish/docker/all.py +31 -0
  54. omlish/docker/consts.py +4 -0
  55. omlish/{lite/docker.py → docker/detect.py} +18 -0
  56. omlish/docker/{helpers.py → timebomb.py} +0 -21
  57. omlish/formats/cbor.py +31 -0
  58. omlish/formats/cloudpickle.py +31 -0
  59. omlish/formats/codecs.py +93 -0
  60. omlish/formats/json/codecs.py +29 -0
  61. omlish/formats/json/delimted.py +4 -0
  62. omlish/formats/json/stream/errors.py +2 -0
  63. omlish/formats/json/stream/lex.py +12 -6
  64. omlish/formats/json/stream/parse.py +38 -22
  65. omlish/formats/json5.py +31 -0
  66. omlish/formats/pickle.py +31 -0
  67. omlish/formats/repr.py +25 -0
  68. omlish/formats/toml.py +17 -0
  69. omlish/formats/yaml.py +25 -0
  70. omlish/funcs/__init__.py +0 -0
  71. omlish/{genmachine.py → funcs/genmachine.py} +5 -4
  72. omlish/{matchfns.py → funcs/match.py} +1 -1
  73. omlish/funcs/pairs.py +215 -0
  74. omlish/http/__init__.py +0 -48
  75. omlish/http/all.py +48 -0
  76. omlish/http/coro/__init__.py +0 -0
  77. omlish/{lite/fdio/corohttp.py → http/coro/fdio.py} +21 -19
  78. omlish/{lite/http/coroserver.py → http/coro/server.py} +20 -21
  79. omlish/{lite/http → http}/handlers.py +3 -2
  80. omlish/{lite/http → http}/parsing.py +1 -0
  81. omlish/http/sessions.py +1 -1
  82. omlish/{lite/http → http}/versions.py +1 -0
  83. omlish/inject/managed.py +2 -2
  84. omlish/io/__init__.py +0 -3
  85. omlish/{lite/io.py → io/buffers.py} +8 -9
  86. omlish/io/compress/__init__.py +9 -0
  87. omlish/io/compress/abc.py +104 -0
  88. omlish/io/compress/adapters.py +148 -0
  89. omlish/io/compress/base.py +24 -0
  90. omlish/io/compress/brotli.py +47 -0
  91. omlish/io/compress/bz2.py +61 -0
  92. omlish/io/compress/codecs.py +78 -0
  93. omlish/io/compress/gzip.py +350 -0
  94. omlish/io/compress/lz4.py +91 -0
  95. omlish/io/compress/lzma.py +81 -0
  96. omlish/io/compress/snappy.py +34 -0
  97. omlish/io/compress/zlib.py +74 -0
  98. omlish/io/compress/zstd.py +44 -0
  99. omlish/io/fdio/__init__.py +1 -0
  100. omlish/{lite → io}/fdio/handlers.py +5 -5
  101. omlish/{lite → io}/fdio/kqueue.py +8 -8
  102. omlish/{lite → io}/fdio/manager.py +7 -7
  103. omlish/{lite → io}/fdio/pollers.py +13 -13
  104. omlish/io/generators/__init__.py +56 -0
  105. omlish/io/generators/consts.py +1 -0
  106. omlish/io/generators/direct.py +13 -0
  107. omlish/io/generators/readers.py +189 -0
  108. omlish/io/generators/stepped.py +191 -0
  109. omlish/io/pyio.py +5 -2
  110. omlish/iterators/__init__.py +24 -0
  111. omlish/iterators/iterators.py +132 -0
  112. omlish/iterators/recipes.py +18 -0
  113. omlish/iterators/tools.py +96 -0
  114. omlish/iterators/unique.py +67 -0
  115. omlish/lang/__init__.py +13 -1
  116. omlish/lang/functions.py +11 -2
  117. omlish/lang/generators.py +243 -0
  118. omlish/lang/iterables.py +46 -49
  119. omlish/lang/maybes.py +4 -4
  120. omlish/lite/cached.py +39 -6
  121. omlish/lite/check.py +438 -75
  122. omlish/lite/contextmanagers.py +17 -4
  123. omlish/lite/dataclasses.py +42 -0
  124. omlish/lite/inject.py +28 -45
  125. omlish/lite/logs.py +0 -270
  126. omlish/lite/marshal.py +309 -144
  127. omlish/lite/pycharm.py +47 -0
  128. omlish/lite/reflect.py +33 -0
  129. omlish/lite/resources.py +8 -0
  130. omlish/lite/runtime.py +4 -4
  131. omlish/lite/shlex.py +12 -0
  132. omlish/lite/socketserver.py +2 -2
  133. omlish/lite/strings.py +31 -0
  134. omlish/logs/__init__.py +0 -32
  135. omlish/logs/{_abc.py → abc.py} +0 -1
  136. omlish/logs/all.py +37 -0
  137. omlish/logs/{formatters.py → color.py} +1 -2
  138. omlish/logs/configs.py +7 -38
  139. omlish/logs/filters.py +10 -0
  140. omlish/logs/handlers.py +4 -1
  141. omlish/logs/json.py +56 -0
  142. omlish/logs/proxy.py +99 -0
  143. omlish/logs/standard.py +128 -0
  144. omlish/logs/utils.py +2 -2
  145. omlish/manifests/__init__.py +2 -0
  146. omlish/manifests/load.py +209 -0
  147. omlish/manifests/types.py +17 -0
  148. omlish/marshal/base.py +1 -1
  149. omlish/marshal/factories.py +1 -1
  150. omlish/marshal/forbidden.py +1 -1
  151. omlish/marshal/iterables.py +1 -1
  152. omlish/marshal/literals.py +50 -0
  153. omlish/marshal/mappings.py +1 -1
  154. omlish/marshal/maybes.py +1 -1
  155. omlish/marshal/standard.py +5 -1
  156. omlish/marshal/unions.py +1 -1
  157. omlish/os/__init__.py +0 -0
  158. omlish/os/atomics.py +205 -0
  159. omlish/os/deathsig.py +23 -0
  160. omlish/{os.py → os/files.py} +0 -9
  161. omlish/{lite → os}/journald.py +2 -1
  162. omlish/os/linux.py +484 -0
  163. omlish/os/paths.py +36 -0
  164. omlish/{lite → os}/pidfile.py +1 -0
  165. omlish/os/sizes.py +9 -0
  166. omlish/reflect/__init__.py +3 -0
  167. omlish/reflect/subst.py +2 -1
  168. omlish/reflect/types.py +126 -44
  169. omlish/secrets/pwhash.py +1 -1
  170. omlish/secrets/subprocesses.py +3 -1
  171. omlish/specs/jsonrpc/marshal.py +1 -1
  172. omlish/specs/openapi/marshal.py +1 -1
  173. omlish/sql/alchemy/asyncs.py +1 -1
  174. omlish/sql/queries/__init__.py +9 -1
  175. omlish/sql/queries/building.py +3 -0
  176. omlish/sql/queries/exprs.py +10 -27
  177. omlish/sql/queries/idents.py +48 -10
  178. omlish/sql/queries/names.py +80 -13
  179. omlish/sql/queries/params.py +64 -0
  180. omlish/sql/queries/rendering.py +1 -1
  181. omlish/subprocesses.py +340 -0
  182. omlish/term.py +29 -14
  183. omlish/testing/pytest/marks.py +2 -2
  184. omlish/testing/pytest/plugins/asyncs.py +6 -1
  185. omlish/testing/pytest/plugins/logging.py +1 -1
  186. omlish/testing/pytest/plugins/switches.py +1 -1
  187. {omlish-0.0.0.dev133.dist-info → omlish-0.0.0.dev177.dist-info}/METADATA +7 -5
  188. {omlish-0.0.0.dev133.dist-info → omlish-0.0.0.dev177.dist-info}/RECORD +200 -117
  189. omlish/fnpairs.py +0 -496
  190. omlish/formats/json/cli/__main__.py +0 -11
  191. omlish/formats/json/cli/cli.py +0 -298
  192. omlish/formats/json/cli/formats.py +0 -71
  193. omlish/formats/json/cli/io.py +0 -74
  194. omlish/formats/json/cli/parsing.py +0 -82
  195. omlish/formats/json/cli/processing.py +0 -48
  196. omlish/formats/json/cli/rendering.py +0 -92
  197. omlish/iterators.py +0 -300
  198. omlish/lite/subprocesses.py +0 -130
  199. /omlish/{formats/json/cli → argparse}/__init__.py +0 -0
  200. /omlish/{lite/fdio → asyncs/asyncio}/__init__.py +0 -0
  201. /omlish/asyncs/{asyncio.py → asyncio/asyncio.py} +0 -0
  202. /omlish/{lite/http → asyncs/bluelet}/__init__.py +0 -0
  203. /omlish/collections/{_abc.py → abc.py} +0 -0
  204. /omlish/{fnpipes.py → funcs/pipes.py} +0 -0
  205. /omlish/io/{_abc.py → abc.py} +0 -0
  206. /omlish/sql/{_abc.py → abc.py} +0 -0
  207. {omlish-0.0.0.dev133.dist-info → omlish-0.0.0.dev177.dist-info}/LICENSE +0 -0
  208. {omlish-0.0.0.dev133.dist-info → omlish-0.0.0.dev177.dist-info}/WHEEL +0 -0
  209. {omlish-0.0.0.dev133.dist-info → omlish-0.0.0.dev177.dist-info}/entry_points.txt +0 -0
  210. {omlish-0.0.0.dev133.dist-info → omlish-0.0.0.dev177.dist-info}/top_level.txt +0 -0
omlish/lite/marshal.py CHANGED
@@ -1,7 +1,7 @@
1
1
  """
2
2
  TODO:
3
3
  - pickle stdlib objs? have to pin to 3.8 pickle protocol, will be cross-version
4
- - nonstrict toggle
4
+ - literals
5
5
  """
6
6
  # ruff: noqa: UP006 UP007
7
7
  import abc
@@ -13,17 +13,22 @@ import decimal
13
13
  import enum
14
14
  import fractions
15
15
  import functools
16
+ import inspect
16
17
  import threading
17
18
  import typing as ta
18
19
  import uuid
19
20
  import weakref # noqa
20
21
 
21
- from .check import check_isinstance
22
- from .check import check_not_none
22
+ from .check import check
23
23
  from .reflect import deep_subclasses
24
+ from .reflect import get_literal_type_args
25
+ from .reflect import get_new_type_supertype
24
26
  from .reflect import get_optional_alias_arg
25
27
  from .reflect import is_generic_alias
28
+ from .reflect import is_literal_type
29
+ from .reflect import is_new_type
26
30
  from .reflect import is_union_alias
31
+ from .strings import snake_case
27
32
 
28
33
 
29
34
  T = ta.TypeVar('T')
@@ -32,21 +37,27 @@ T = ta.TypeVar('T')
32
37
  ##
33
38
 
34
39
 
40
+ @dc.dataclass(frozen=True)
41
+ class ObjMarshalOptions:
42
+ raw_bytes: bool = False
43
+ non_strict_fields: bool = False
44
+
45
+
35
46
  class ObjMarshaler(abc.ABC):
36
47
  @abc.abstractmethod
37
- def marshal(self, o: ta.Any) -> ta.Any:
48
+ def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
38
49
  raise NotImplementedError
39
50
 
40
51
  @abc.abstractmethod
41
- def unmarshal(self, o: ta.Any) -> ta.Any:
52
+ def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
42
53
  raise NotImplementedError
43
54
 
44
55
 
45
56
  class NopObjMarshaler(ObjMarshaler):
46
- def marshal(self, o: ta.Any) -> ta.Any:
57
+ def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
47
58
  return o
48
59
 
49
- def unmarshal(self, o: ta.Any) -> ta.Any:
60
+ def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
50
61
  return o
51
62
 
52
63
 
@@ -54,29 +65,29 @@ class NopObjMarshaler(ObjMarshaler):
54
65
  class ProxyObjMarshaler(ObjMarshaler):
55
66
  m: ta.Optional[ObjMarshaler] = None
56
67
 
57
- def marshal(self, o: ta.Any) -> ta.Any:
58
- return check_not_none(self.m).marshal(o)
68
+ def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
69
+ return check.not_none(self.m).marshal(o, ctx)
59
70
 
60
- def unmarshal(self, o: ta.Any) -> ta.Any:
61
- return check_not_none(self.m).unmarshal(o)
71
+ def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
72
+ return check.not_none(self.m).unmarshal(o, ctx)
62
73
 
63
74
 
64
75
  @dc.dataclass(frozen=True)
65
76
  class CastObjMarshaler(ObjMarshaler):
66
77
  ty: type
67
78
 
68
- def marshal(self, o: ta.Any) -> ta.Any:
79
+ def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
69
80
  return o
70
81
 
71
- def unmarshal(self, o: ta.Any) -> ta.Any:
82
+ def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
72
83
  return self.ty(o)
73
84
 
74
85
 
75
86
  class DynamicObjMarshaler(ObjMarshaler):
76
- def marshal(self, o: ta.Any) -> ta.Any:
77
- return marshal_obj(o)
87
+ def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
88
+ return ctx.manager.marshal_obj(o, opts=ctx.options)
78
89
 
79
- def unmarshal(self, o: ta.Any) -> ta.Any:
90
+ def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
80
91
  return o
81
92
 
82
93
 
@@ -84,21 +95,36 @@ class DynamicObjMarshaler(ObjMarshaler):
84
95
  class Base64ObjMarshaler(ObjMarshaler):
85
96
  ty: type
86
97
 
87
- def marshal(self, o: ta.Any) -> ta.Any:
98
+ def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
88
99
  return base64.b64encode(o).decode('ascii')
89
100
 
90
- def unmarshal(self, o: ta.Any) -> ta.Any:
101
+ def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
91
102
  return self.ty(base64.b64decode(o))
92
103
 
93
104
 
105
+ @dc.dataclass(frozen=True)
106
+ class BytesSwitchedObjMarshaler(ObjMarshaler):
107
+ m: ObjMarshaler
108
+
109
+ def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
110
+ if ctx.options.raw_bytes:
111
+ return o
112
+ return self.m.marshal(o, ctx)
113
+
114
+ def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
115
+ if ctx.options.raw_bytes:
116
+ return o
117
+ return self.m.unmarshal(o, ctx)
118
+
119
+
94
120
  @dc.dataclass(frozen=True)
95
121
  class EnumObjMarshaler(ObjMarshaler):
96
122
  ty: type
97
123
 
98
- def marshal(self, o: ta.Any) -> ta.Any:
124
+ def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
99
125
  return o.name
100
126
 
101
- def unmarshal(self, o: ta.Any) -> ta.Any:
127
+ def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
102
128
  return self.ty.__members__[o] # type: ignore
103
129
 
104
130
 
@@ -106,15 +132,27 @@ class EnumObjMarshaler(ObjMarshaler):
106
132
  class OptionalObjMarshaler(ObjMarshaler):
107
133
  item: ObjMarshaler
108
134
 
109
- def marshal(self, o: ta.Any) -> ta.Any:
135
+ def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
110
136
  if o is None:
111
137
  return None
112
- return self.item.marshal(o)
138
+ return self.item.marshal(o, ctx)
113
139
 
114
- def unmarshal(self, o: ta.Any) -> ta.Any:
140
+ def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
115
141
  if o is None:
116
142
  return None
117
- return self.item.unmarshal(o)
143
+ return self.item.unmarshal(o, ctx)
144
+
145
+
146
+ @dc.dataclass(frozen=True)
147
+ class LiteralObjMarshaler(ObjMarshaler):
148
+ item: ObjMarshaler
149
+ vs: frozenset
150
+
151
+ def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
152
+ return self.item.marshal(check.in_(o, self.vs), ctx)
153
+
154
+ def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
155
+ return check.in_(self.item.unmarshal(o, ctx), self.vs)
118
156
 
119
157
 
120
158
  @dc.dataclass(frozen=True)
@@ -123,11 +161,11 @@ class MappingObjMarshaler(ObjMarshaler):
123
161
  km: ObjMarshaler
124
162
  vm: ObjMarshaler
125
163
 
126
- def marshal(self, o: ta.Any) -> ta.Any:
127
- return {self.km.marshal(k): self.vm.marshal(v) for k, v in o.items()}
164
+ def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
165
+ return {self.km.marshal(k, ctx): self.vm.marshal(v, ctx) for k, v in o.items()}
128
166
 
129
- def unmarshal(self, o: ta.Any) -> ta.Any:
130
- return self.ty((self.km.unmarshal(k), self.vm.unmarshal(v)) for k, v in o.items())
167
+ def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
168
+ return self.ty((self.km.unmarshal(k, ctx), self.vm.unmarshal(v, ctx)) for k, v in o.items())
131
169
 
132
170
 
133
171
  @dc.dataclass(frozen=True)
@@ -135,24 +173,43 @@ class IterableObjMarshaler(ObjMarshaler):
135
173
  ty: type
136
174
  item: ObjMarshaler
137
175
 
138
- def marshal(self, o: ta.Any) -> ta.Any:
139
- return [self.item.marshal(e) for e in o]
176
+ def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
177
+ return [self.item.marshal(e, ctx) for e in o]
140
178
 
141
- def unmarshal(self, o: ta.Any) -> ta.Any:
142
- return self.ty(self.item.unmarshal(e) for e in o)
179
+ def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
180
+ return self.ty(self.item.unmarshal(e, ctx) for e in o)
143
181
 
144
182
 
145
183
  @dc.dataclass(frozen=True)
146
- class DataclassObjMarshaler(ObjMarshaler):
184
+ class FieldsObjMarshaler(ObjMarshaler):
147
185
  ty: type
148
186
  fs: ta.Mapping[str, ObjMarshaler]
149
- nonstrict: bool = False
187
+ non_strict: bool = False
150
188
 
151
- def marshal(self, o: ta.Any) -> ta.Any:
152
- return {k: m.marshal(getattr(o, k)) for k, m in self.fs.items()}
189
+ def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
190
+ return {
191
+ k: m.marshal(getattr(o, k), ctx)
192
+ for k, m in self.fs.items()
193
+ }
153
194
 
154
- def unmarshal(self, o: ta.Any) -> ta.Any:
155
- return self.ty(**{k: self.fs[k].unmarshal(v) for k, v in o.items() if not self.nonstrict or k in self.fs})
195
+ def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
196
+ return self.ty(**{
197
+ k: self.fs[k].unmarshal(v, ctx)
198
+ for k, v in o.items()
199
+ if not (self.non_strict or ctx.options.non_strict_fields) or k in self.fs
200
+ })
201
+
202
+
203
+ @dc.dataclass(frozen=True)
204
+ class SingleFieldObjMarshaler(ObjMarshaler):
205
+ ty: type
206
+ fld: str
207
+
208
+ def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
209
+ return getattr(o, self.fld)
210
+
211
+ def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
212
+ return self.ty(**{self.fld: o})
156
213
 
157
214
 
158
215
  @dc.dataclass(frozen=True)
@@ -165,50 +222,57 @@ class PolymorphicObjMarshaler(ObjMarshaler):
165
222
  impls_by_ty: ta.Mapping[type, Impl]
166
223
  impls_by_tag: ta.Mapping[str, Impl]
167
224
 
168
- def marshal(self, o: ta.Any) -> ta.Any:
225
+ @classmethod
226
+ def of(cls, impls: ta.Iterable[Impl]) -> 'PolymorphicObjMarshaler':
227
+ return cls(
228
+ {i.ty: i for i in impls},
229
+ {i.tag: i for i in impls},
230
+ )
231
+
232
+ def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
169
233
  impl = self.impls_by_ty[type(o)]
170
- return {impl.tag: impl.m.marshal(o)}
234
+ return {impl.tag: impl.m.marshal(o, ctx)}
171
235
 
172
- def unmarshal(self, o: ta.Any) -> ta.Any:
236
+ def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
173
237
  [(t, v)] = o.items()
174
238
  impl = self.impls_by_tag[t]
175
- return impl.m.unmarshal(v)
239
+ return impl.m.unmarshal(v, ctx)
176
240
 
177
241
 
178
242
  @dc.dataclass(frozen=True)
179
243
  class DatetimeObjMarshaler(ObjMarshaler):
180
244
  ty: type
181
245
 
182
- def marshal(self, o: ta.Any) -> ta.Any:
246
+ def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
183
247
  return o.isoformat()
184
248
 
185
- def unmarshal(self, o: ta.Any) -> ta.Any:
249
+ def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
186
250
  return self.ty.fromisoformat(o) # type: ignore
187
251
 
188
252
 
189
253
  class DecimalObjMarshaler(ObjMarshaler):
190
- def marshal(self, o: ta.Any) -> ta.Any:
191
- return str(check_isinstance(o, decimal.Decimal))
254
+ def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
255
+ return str(check.isinstance(o, decimal.Decimal))
192
256
 
193
- def unmarshal(self, v: ta.Any) -> ta.Any:
194
- return decimal.Decimal(check_isinstance(v, str))
257
+ def unmarshal(self, v: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
258
+ return decimal.Decimal(check.isinstance(v, str))
195
259
 
196
260
 
197
261
  class FractionObjMarshaler(ObjMarshaler):
198
- def marshal(self, o: ta.Any) -> ta.Any:
199
- fr = check_isinstance(o, fractions.Fraction)
262
+ def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
263
+ fr = check.isinstance(o, fractions.Fraction)
200
264
  return [fr.numerator, fr.denominator]
201
265
 
202
- def unmarshal(self, v: ta.Any) -> ta.Any:
203
- num, denom = check_isinstance(v, list)
266
+ def unmarshal(self, v: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
267
+ num, denom = check.isinstance(v, list)
204
268
  return fractions.Fraction(num, denom)
205
269
 
206
270
 
207
271
  class UuidObjMarshaler(ObjMarshaler):
208
- def marshal(self, o: ta.Any) -> ta.Any:
272
+ def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
209
273
  return str(o)
210
274
 
211
- def unmarshal(self, o: ta.Any) -> ta.Any:
275
+ def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
212
276
  return uuid.UUID(o)
213
277
 
214
278
 
@@ -218,11 +282,11 @@ class UuidObjMarshaler(ObjMarshaler):
218
282
  _DEFAULT_OBJ_MARSHALERS: ta.Dict[ta.Any, ObjMarshaler] = {
219
283
  **{t: NopObjMarshaler() for t in (type(None),)},
220
284
  **{t: CastObjMarshaler(t) for t in (int, float, str, bool)},
221
- **{t: Base64ObjMarshaler(t) for t in (bytes, bytearray)},
285
+ **{t: BytesSwitchedObjMarshaler(Base64ObjMarshaler(t)) for t in (bytes, bytearray)},
222
286
  **{t: IterableObjMarshaler(t, DynamicObjMarshaler()) for t in (list, tuple, set, frozenset)},
223
287
  **{t: MappingObjMarshaler(t, DynamicObjMarshaler(), DynamicObjMarshaler()) for t in (dict,)},
224
288
 
225
- ta.Any: DynamicObjMarshaler(),
289
+ **{t: DynamicObjMarshaler() for t in (ta.Any, object)},
226
290
 
227
291
  **{t: DatetimeObjMarshaler(t) for t in (datetime.date, datetime.time, datetime.datetime)},
228
292
  decimal.Decimal: DecimalObjMarshaler(),
@@ -244,121 +308,222 @@ _OBJ_MARSHALER_GENERIC_ITERABLE_TYPES: ta.Dict[ta.Any, type] = {
244
308
  }
245
309
 
246
310
 
247
- def _make_obj_marshaler(
248
- ty: ta.Any,
249
- rec: ta.Callable[[ta.Any], ObjMarshaler],
250
- *,
251
- nonstrict_dataclasses: bool = False,
252
- ) -> ObjMarshaler:
253
- if isinstance(ty, type):
254
- if abc.ABC in ty.__bases__:
255
- impls = [ # type: ignore
256
- PolymorphicObjMarshaler.Impl(
257
- ity,
258
- ity.__qualname__,
259
- rec(ity),
260
- )
261
- for ity in deep_subclasses(ty)
262
- if abc.ABC not in ity.__bases__
263
- ]
264
- return PolymorphicObjMarshaler(
265
- {i.ty: i for i in impls},
266
- {i.tag: i for i in impls},
267
- )
268
-
269
- if issubclass(ty, enum.Enum):
270
- return EnumObjMarshaler(ty)
271
-
272
- if dc.is_dataclass(ty):
273
- return DataclassObjMarshaler(
274
- ty,
275
- {f.name: rec(f.type) for f in dc.fields(ty)},
276
- nonstrict=nonstrict_dataclasses,
277
- )
311
+ ##
278
312
 
279
- if is_generic_alias(ty):
280
- try:
281
- mt = _OBJ_MARSHALER_GENERIC_MAPPING_TYPES[ta.get_origin(ty)]
282
- except KeyError:
283
- pass
284
- else:
285
- k, v = ta.get_args(ty)
286
- return MappingObjMarshaler(mt, rec(k), rec(v))
287
313
 
288
- try:
289
- st = _OBJ_MARSHALER_GENERIC_ITERABLE_TYPES[ta.get_origin(ty)]
290
- except KeyError:
291
- pass
292
- else:
293
- [e] = ta.get_args(ty)
294
- return IterableObjMarshaler(st, rec(e))
314
+ _REGISTERED_OBJ_MARSHALERS_BY_TYPE: ta.MutableMapping[type, ObjMarshaler] = weakref.WeakKeyDictionary()
295
315
 
296
- if is_union_alias(ty):
297
- return OptionalObjMarshaler(rec(get_optional_alias_arg(ty)))
298
316
 
299
- raise TypeError(ty)
317
+ def register_type_obj_marshaler(ty: type, om: ObjMarshaler) -> None:
318
+ _REGISTERED_OBJ_MARSHALERS_BY_TYPE[ty] = om
300
319
 
301
320
 
302
321
  ##
303
322
 
304
323
 
305
- _OBJ_MARSHALERS_LOCK = threading.RLock()
324
+ class ObjMarshalerManager:
325
+ def __init__(
326
+ self,
327
+ *,
328
+ default_options: ObjMarshalOptions = ObjMarshalOptions(),
329
+
330
+ default_obj_marshalers: ta.Dict[ta.Any, ObjMarshaler] = _DEFAULT_OBJ_MARSHALERS, # noqa
331
+ generic_mapping_types: ta.Dict[ta.Any, type] = _OBJ_MARSHALER_GENERIC_MAPPING_TYPES, # noqa
332
+ generic_iterable_types: ta.Dict[ta.Any, type] = _OBJ_MARSHALER_GENERIC_ITERABLE_TYPES, # noqa
333
+
334
+ registered_obj_marshalers: ta.Mapping[type, ObjMarshaler] = _REGISTERED_OBJ_MARSHALERS_BY_TYPE,
335
+ ) -> None:
336
+ super().__init__()
337
+
338
+ self._default_options = default_options
339
+
340
+ self._obj_marshalers = dict(default_obj_marshalers)
341
+ self._generic_mapping_types = generic_mapping_types
342
+ self._generic_iterable_types = generic_iterable_types
343
+ self._registered_obj_marshalers = registered_obj_marshalers
344
+
345
+ self._lock = threading.RLock()
346
+ self._marshalers: ta.Dict[ta.Any, ObjMarshaler] = dict(_DEFAULT_OBJ_MARSHALERS)
347
+ self._proxies: ta.Dict[ta.Any, ProxyObjMarshaler] = {}
348
+
349
+ #
350
+
351
+ def make_obj_marshaler(
352
+ self,
353
+ ty: ta.Any,
354
+ rec: ta.Callable[[ta.Any], ObjMarshaler],
355
+ *,
356
+ non_strict_fields: bool = False,
357
+ ) -> ObjMarshaler:
358
+ if isinstance(ty, type):
359
+ if (reg := self._registered_obj_marshalers.get(ty)) is not None:
360
+ return reg
361
+
362
+ if abc.ABC in ty.__bases__:
363
+ impls = [ity for ity in deep_subclasses(ty) if abc.ABC not in ity.__bases__] # type: ignore
364
+ if all(ity.__qualname__.endswith(ty.__name__) for ity in impls):
365
+ ins = {ity: snake_case(ity.__qualname__[:-len(ty.__name__)]) for ity in impls}
366
+ else:
367
+ ins = {ity: ity.__qualname__ for ity in impls}
368
+ return PolymorphicObjMarshaler.of([
369
+ PolymorphicObjMarshaler.Impl(
370
+ ity,
371
+ itn,
372
+ rec(ity),
373
+ )
374
+ for ity, itn in ins.items()
375
+ ])
376
+
377
+ if issubclass(ty, enum.Enum):
378
+ return EnumObjMarshaler(ty)
379
+
380
+ if dc.is_dataclass(ty):
381
+ return FieldsObjMarshaler(
382
+ ty,
383
+ {f.name: rec(f.type) for f in dc.fields(ty)},
384
+ non_strict=non_strict_fields,
385
+ )
306
386
 
307
- _OBJ_MARSHALERS: ta.Dict[ta.Any, ObjMarshaler] = dict(_DEFAULT_OBJ_MARSHALERS)
387
+ if issubclass(ty, tuple) and hasattr(ty, '_fields'):
388
+ return FieldsObjMarshaler(
389
+ ty,
390
+ {p.name: rec(p.annotation) for p in inspect.signature(ty).parameters.values()},
391
+ non_strict=non_strict_fields,
392
+ )
308
393
 
309
- _OBJ_MARSHALER_PROXIES: ta.Dict[ta.Any, ProxyObjMarshaler] = {}
394
+ if is_new_type(ty):
395
+ return rec(get_new_type_supertype(ty))
310
396
 
397
+ if is_literal_type(ty):
398
+ lvs = frozenset(get_literal_type_args(ty))
399
+ lty = check.single(set(map(type, lvs)))
400
+ return LiteralObjMarshaler(rec(lty), lvs)
311
401
 
312
- def register_opj_marshaler(ty: ta.Any, m: ObjMarshaler) -> None:
313
- with _OBJ_MARSHALERS_LOCK:
314
- if ty in _OBJ_MARSHALERS:
315
- raise KeyError(ty)
316
- _OBJ_MARSHALERS[ty] = m
402
+ if is_generic_alias(ty):
403
+ try:
404
+ mt = self._generic_mapping_types[ta.get_origin(ty)]
405
+ except KeyError:
406
+ pass
407
+ else:
408
+ k, v = ta.get_args(ty)
409
+ return MappingObjMarshaler(mt, rec(k), rec(v))
317
410
 
411
+ try:
412
+ st = self._generic_iterable_types[ta.get_origin(ty)]
413
+ except KeyError:
414
+ pass
415
+ else:
416
+ [e] = ta.get_args(ty)
417
+ return IterableObjMarshaler(st, rec(e))
418
+
419
+ if is_union_alias(ty):
420
+ return OptionalObjMarshaler(rec(get_optional_alias_arg(ty)))
421
+
422
+ raise TypeError(ty)
423
+
424
+ #
425
+
426
+ def set_obj_marshaler(
427
+ self,
428
+ ty: ta.Any,
429
+ m: ObjMarshaler,
430
+ *,
431
+ override: bool = False,
432
+ ) -> None:
433
+ with self._lock:
434
+ if not override and ty in self._obj_marshalers:
435
+ raise KeyError(ty)
436
+ self._obj_marshalers[ty] = m
437
+
438
+ def get_obj_marshaler(
439
+ self,
440
+ ty: ta.Any,
441
+ *,
442
+ no_cache: bool = False,
443
+ **kwargs: ta.Any,
444
+ ) -> ObjMarshaler:
445
+ with self._lock:
446
+ if not no_cache:
447
+ try:
448
+ return self._obj_marshalers[ty]
449
+ except KeyError:
450
+ pass
318
451
 
319
- def get_obj_marshaler(
320
- ty: ta.Any,
321
- *,
322
- no_cache: bool = False,
323
- **kwargs: ta.Any,
324
- ) -> ObjMarshaler:
325
- with _OBJ_MARSHALERS_LOCK:
326
- if not no_cache:
327
452
  try:
328
- return _OBJ_MARSHALERS[ty]
453
+ return self._proxies[ty]
329
454
  except KeyError:
330
455
  pass
331
456
 
332
- try:
333
- return _OBJ_MARSHALER_PROXIES[ty]
334
- except KeyError:
335
- pass
457
+ rec = functools.partial(
458
+ self.get_obj_marshaler,
459
+ no_cache=no_cache,
460
+ **kwargs,
461
+ )
462
+
463
+ p = ProxyObjMarshaler()
464
+ self._proxies[ty] = p
465
+ try:
466
+ m = self.make_obj_marshaler(ty, rec, **kwargs)
467
+ finally:
468
+ del self._proxies[ty]
469
+ p.m = m
470
+
471
+ if not no_cache:
472
+ self._obj_marshalers[ty] = m
473
+ return m
474
+
475
+ #
336
476
 
337
- rec = functools.partial(
338
- get_obj_marshaler,
339
- no_cache=no_cache,
340
- **kwargs,
477
+ def _make_context(self, opts: ta.Optional[ObjMarshalOptions]) -> 'ObjMarshalContext':
478
+ return ObjMarshalContext(
479
+ options=opts or self._default_options,
480
+ manager=self,
341
481
  )
342
482
 
343
- p = ProxyObjMarshaler()
344
- _OBJ_MARSHALER_PROXIES[ty] = p
345
- try:
346
- m = _make_obj_marshaler(ty, rec, **kwargs)
347
- finally:
348
- del _OBJ_MARSHALER_PROXIES[ty]
349
- p.m = m
483
+ def marshal_obj(
484
+ self,
485
+ o: ta.Any,
486
+ ty: ta.Any = None,
487
+ opts: ta.Optional[ObjMarshalOptions] = None,
488
+ ) -> ta.Any:
489
+ m = self.get_obj_marshaler(ty if ty is not None else type(o))
490
+ return m.marshal(o, self._make_context(opts))
491
+
492
+ def unmarshal_obj(
493
+ self,
494
+ o: ta.Any,
495
+ ty: ta.Union[ta.Type[T], ta.Any],
496
+ opts: ta.Optional[ObjMarshalOptions] = None,
497
+ ) -> T:
498
+ m = self.get_obj_marshaler(ty)
499
+ return m.unmarshal(o, self._make_context(opts))
500
+
501
+ def roundtrip_obj(
502
+ self,
503
+ o: ta.Any,
504
+ ty: ta.Any = None,
505
+ opts: ta.Optional[ObjMarshalOptions] = None,
506
+ ) -> ta.Any:
507
+ if ty is None:
508
+ ty = type(o)
509
+ m: ta.Any = self.marshal_obj(o, ty, opts)
510
+ u: ta.Any = self.unmarshal_obj(m, ty, opts)
511
+ return u
350
512
 
351
- if not no_cache:
352
- _OBJ_MARSHALERS[ty] = m
353
- return m
513
+
514
+ @dc.dataclass(frozen=True)
515
+ class ObjMarshalContext:
516
+ options: ObjMarshalOptions
517
+ manager: ObjMarshalerManager
354
518
 
355
519
 
356
520
  ##
357
521
 
358
522
 
359
- def marshal_obj(o: ta.Any, ty: ta.Any = None) -> ta.Any:
360
- return get_obj_marshaler(ty if ty is not None else type(o)).marshal(o)
523
+ OBJ_MARSHALER_MANAGER = ObjMarshalerManager()
361
524
 
525
+ set_obj_marshaler = OBJ_MARSHALER_MANAGER.set_obj_marshaler
526
+ get_obj_marshaler = OBJ_MARSHALER_MANAGER.get_obj_marshaler
362
527
 
363
- def unmarshal_obj(o: ta.Any, ty: ta.Union[ta.Type[T], ta.Any]) -> T:
364
- return get_obj_marshaler(ty).unmarshal(o)
528
+ marshal_obj = OBJ_MARSHALER_MANAGER.marshal_obj
529
+ unmarshal_obj = OBJ_MARSHALER_MANAGER.unmarshal_obj
omlish/lite/pycharm.py ADDED
@@ -0,0 +1,47 @@
1
+ # ruff: noqa: UP006 UP007
2
+ import dataclasses as dc
3
+ import typing as ta
4
+
5
+
6
+ DEFAULT_PYCHARM_VERSION = '242.23726.102'
7
+
8
+
9
+ @dc.dataclass(frozen=True)
10
+ class PycharmRemoteDebug:
11
+ port: int
12
+ host: ta.Optional[str] = 'localhost'
13
+ install_version: ta.Optional[str] = DEFAULT_PYCHARM_VERSION
14
+
15
+
16
+ def pycharm_debug_connect(prd: PycharmRemoteDebug) -> None:
17
+ if prd.install_version is not None:
18
+ import subprocess
19
+ import sys
20
+ subprocess.check_call([
21
+ sys.executable,
22
+ '-mpip',
23
+ 'install',
24
+ f'pydevd-pycharm~={prd.install_version}',
25
+ ])
26
+
27
+ pydevd_pycharm = __import__('pydevd_pycharm') # noqa
28
+ pydevd_pycharm.settrace(
29
+ prd.host,
30
+ port=prd.port,
31
+ stdoutToServer=True,
32
+ stderrToServer=True,
33
+ )
34
+
35
+
36
+ def pycharm_debug_preamble(prd: PycharmRemoteDebug) -> str:
37
+ import inspect
38
+ import textwrap
39
+ return textwrap.dedent(f"""
40
+ {inspect.getsource(pycharm_debug_connect)}
41
+
42
+ pycharm_debug_connect(PycharmRemoteDebug(
43
+ {prd.port!r},
44
+ host={prd.host!r},
45
+ install_version={prd.install_version!r},
46
+ ))
47
+ """)