omlish 0.0.0.dev132__py3-none-any.whl → 0.0.0.dev177__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (210) hide show
  1. omlish/.manifests.json +265 -7
  2. omlish/__about__.py +7 -5
  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.dev132.dist-info → omlish-0.0.0.dev177.dist-info}/METADATA +13 -11
  188. {omlish-0.0.0.dev132.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.dev132.dist-info → omlish-0.0.0.dev177.dist-info}/LICENSE +0 -0
  208. {omlish-0.0.0.dev132.dist-info → omlish-0.0.0.dev177.dist-info}/WHEEL +0 -0
  209. {omlish-0.0.0.dev132.dist-info → omlish-0.0.0.dev177.dist-info}/entry_points.txt +0 -0
  210. {omlish-0.0.0.dev132.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
+ """)