ominfra 0.0.0.dev141__py3-none-any.whl → 0.0.0.dev143__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. ominfra/manage/__init__.py +10 -0
  2. ominfra/manage/__main__.py +4 -0
  3. ominfra/manage/bootstrap.py +11 -0
  4. ominfra/manage/bootstrap_.py +18 -0
  5. ominfra/manage/commands/base.py +133 -1
  6. ominfra/manage/commands/execution.py +23 -0
  7. ominfra/manage/commands/inject.py +122 -0
  8. ominfra/manage/commands/marshal.py +26 -0
  9. ominfra/manage/commands/subprocess.py +18 -17
  10. ominfra/manage/config.py +10 -0
  11. ominfra/manage/inject.py +55 -0
  12. ominfra/manage/main.py +54 -132
  13. ominfra/manage/marshal.py +12 -0
  14. ominfra/manage/remote/__init__.py +0 -0
  15. ominfra/manage/remote/channel.py +52 -0
  16. ominfra/manage/remote/config.py +12 -0
  17. ominfra/manage/remote/execution.py +193 -0
  18. ominfra/manage/remote/inject.py +29 -0
  19. ominfra/manage/{payload.py → remote/payload.py} +7 -1
  20. ominfra/manage/{spawning.py → remote/spawning.py} +31 -35
  21. ominfra/pyremote.py +53 -14
  22. ominfra/scripts/journald2aws.py +216 -131
  23. ominfra/scripts/manage.py +2180 -452
  24. ominfra/scripts/supervisor.py +203 -130
  25. ominfra/supervisor/inject.py +2 -1
  26. {ominfra-0.0.0.dev141.dist-info → ominfra-0.0.0.dev143.dist-info}/METADATA +3 -3
  27. {ominfra-0.0.0.dev141.dist-info → ominfra-0.0.0.dev143.dist-info}/RECORD +31 -17
  28. {ominfra-0.0.0.dev141.dist-info → ominfra-0.0.0.dev143.dist-info}/LICENSE +0 -0
  29. {ominfra-0.0.0.dev141.dist-info → ominfra-0.0.0.dev143.dist-info}/WHEEL +0 -0
  30. {ominfra-0.0.0.dev141.dist-info → ominfra-0.0.0.dev143.dist-info}/entry_points.txt +0 -0
  31. {ominfra-0.0.0.dev141.dist-info → ominfra-0.0.0.dev143.dist-info}/top_level.txt +0 -0
ominfra/pyremote.py CHANGED
@@ -2,6 +2,9 @@
2
2
  # @omlish-lite
3
3
  """
4
4
  Basically this: https://mitogen.networkgenomics.com/howitworks.html
5
+
6
+ TODO:
7
+ - log: ta.Optional[logging.Logger] = None + log.debug's
5
8
  """
6
9
  import base64
7
10
  import dataclasses as dc
@@ -23,6 +26,9 @@ import zlib
23
26
  class PyremoteBootstrapOptions:
24
27
  debug: bool = False
25
28
 
29
+ DEFAULT_MAIN_NAME_OVERRIDE: ta.ClassVar[str] = '__pyremote__'
30
+ main_name_override: ta.Optional[str] = DEFAULT_MAIN_NAME_OVERRIDE
31
+
26
32
 
27
33
  ##
28
34
 
@@ -177,12 +183,14 @@ def _pyremote_bootstrap_main(context_name: str) -> None:
177
183
  os.close(f)
178
184
 
179
185
  # Save vars
180
- os.environ[_PYREMOTE_BOOTSTRAP_CHILD_PID_VAR] = str(cp)
181
- os.environ[_PYREMOTE_BOOTSTRAP_ARGV0_VAR] = sys.executable
182
- os.environ[_PYREMOTE_BOOTSTRAP_CONTEXT_NAME_VAR] = context_name
186
+ env = os.environ
187
+ exe = sys.executable
188
+ env[_PYREMOTE_BOOTSTRAP_CHILD_PID_VAR] = str(cp)
189
+ env[_PYREMOTE_BOOTSTRAP_ARGV0_VAR] = exe
190
+ env[_PYREMOTE_BOOTSTRAP_CONTEXT_NAME_VAR] = context_name
183
191
 
184
192
  # Start repl reading stdin from r0
185
- os.execl(sys.executable, sys.executable + (_PYREMOTE_BOOTSTRAP_PROC_TITLE_FMT % (context_name,)))
193
+ os.execl(exe, exe + (_PYREMOTE_BOOTSTRAP_PROC_TITLE_FMT % (context_name,)))
186
194
 
187
195
  else:
188
196
  # Child process
@@ -246,12 +254,12 @@ def pyremote_build_bootstrap_cmd(context_name: str) -> str:
246
254
  if cl.strip()
247
255
  )
248
256
 
249
- bs_z = zlib.compress(bs_src.encode('utf-8'))
250
- bs_z64 = base64.encodebytes(bs_z).replace(b'\n', b'')
257
+ bs_z = zlib.compress(bs_src.encode('utf-8'), 9)
258
+ bs_z85 = base64.b85encode(bs_z).replace(b'\n', b'')
251
259
 
252
260
  stmts = [
253
261
  f'import {", ".join(_PYREMOTE_BOOTSTRAP_IMPORTS)}',
254
- f'exec(zlib.decompress(base64.decodebytes({bs_z64!r})))',
262
+ f'exec(zlib.decompress(base64.b85decode({bs_z85!r})))',
255
263
  f'_pyremote_bootstrap_main({context_name!r})',
256
264
  ]
257
265
 
@@ -337,6 +345,10 @@ def pyremote_bootstrap_finalize() -> PyremotePayloadRuntime:
337
345
  os.dup2(nfd := os.open('/dev/null', os.O_WRONLY), 1)
338
346
  os.close(nfd)
339
347
 
348
+ if (mn := options.main_name_override) is not None:
349
+ # Inspections like typing.get_type_hints need an entry in sys.modules.
350
+ sys.modules[mn] = sys.modules['__main__']
351
+
340
352
  # Write fourth ack
341
353
  output.write(_PYREMOTE_BOOTSTRAP_ACK3)
342
354
 
@@ -355,14 +367,41 @@ def pyremote_bootstrap_finalize() -> PyremotePayloadRuntime:
355
367
 
356
368
 
357
369
  class PyremoteBootstrapDriver:
358
- def __init__(self, main_src: str, options: PyremoteBootstrapOptions = PyremoteBootstrapOptions()) -> None:
370
+ def __init__(
371
+ self,
372
+ main_src: ta.Union[str, ta.Sequence[str]],
373
+ options: PyremoteBootstrapOptions = PyremoteBootstrapOptions(),
374
+ ) -> None:
359
375
  super().__init__()
360
376
 
361
377
  self._main_src = main_src
362
- self._main_z = zlib.compress(main_src.encode('utf-8'))
363
-
364
378
  self._options = options
379
+
380
+ self._prepared_main_src = self._prepare_main_src(main_src, options)
381
+ self._main_z = zlib.compress(self._prepared_main_src.encode('utf-8'))
382
+
365
383
  self._options_json = json.dumps(dc.asdict(options), indent=None, separators=(',', ':')).encode('utf-8') # noqa
384
+ #
385
+
386
+ @classmethod
387
+ def _prepare_main_src(
388
+ cls,
389
+ main_src: ta.Union[str, ta.Sequence[str]],
390
+ options: PyremoteBootstrapOptions,
391
+ ) -> str:
392
+ parts: ta.List[str]
393
+ if isinstance(main_src, str):
394
+ parts = [main_src]
395
+ else:
396
+ parts = list(main_src)
397
+
398
+ if (mn := options.main_name_override) is not None:
399
+ parts.insert(0, f'__name__ = {mn!r}')
400
+
401
+ if len(parts) == 1:
402
+ return parts[0]
403
+ else:
404
+ return '\n\n'.join(parts)
366
405
 
367
406
  #
368
407
 
@@ -440,7 +479,7 @@ class PyremoteBootstrapDriver:
440
479
 
441
480
  #
442
481
 
443
- def run(self, stdin: ta.IO, stdout: ta.IO) -> Result:
482
+ def run(self, input: ta.IO, output: ta.IO) -> Result: # noqa
444
483
  gen = self.gen()
445
484
 
446
485
  gi: ta.Optional[bytes] = None
@@ -454,11 +493,11 @@ class PyremoteBootstrapDriver:
454
493
  return e.value
455
494
 
456
495
  if isinstance(go, self.Read):
457
- if len(gi := stdout.read(go.sz)) != go.sz:
496
+ if len(gi := input.read(go.sz)) != go.sz:
458
497
  raise EOFError
459
498
  elif isinstance(go, self.Write):
460
499
  gi = None
461
- stdin.write(go.d)
462
- stdin.flush()
500
+ output.write(go.d)
501
+ output.flush()
463
502
  else:
464
503
  raise TypeError(go)
@@ -72,6 +72,9 @@ ConfigMapping = ta.Mapping[str, ta.Any]
72
72
  # ../../../threadworkers.py
73
73
  ThreadWorkerT = ta.TypeVar('ThreadWorkerT', bound='ThreadWorker')
74
74
 
75
+ # ../../../../omlish/lite/subprocesses.py
76
+ SubprocessChannelOption = ta.Literal['pipe', 'stdout', 'devnull']
77
+
75
78
 
76
79
  ########################################
77
80
  # ../../../../../omdev/toml/parser.py
@@ -2163,21 +2166,26 @@ TODO:
2163
2166
  ##
2164
2167
 
2165
2168
 
2169
+ @dc.dataclass(frozen=True)
2170
+ class ObjMarshalOptions:
2171
+ raw_bytes: bool = False
2172
+
2173
+
2166
2174
  class ObjMarshaler(abc.ABC):
2167
2175
  @abc.abstractmethod
2168
- def marshal(self, o: ta.Any) -> ta.Any:
2176
+ def marshal(self, o: ta.Any, opts: ObjMarshalOptions) -> ta.Any:
2169
2177
  raise NotImplementedError
2170
2178
 
2171
2179
  @abc.abstractmethod
2172
- def unmarshal(self, o: ta.Any) -> ta.Any:
2180
+ def unmarshal(self, o: ta.Any, opts: ObjMarshalOptions) -> ta.Any:
2173
2181
  raise NotImplementedError
2174
2182
 
2175
2183
 
2176
2184
  class NopObjMarshaler(ObjMarshaler):
2177
- def marshal(self, o: ta.Any) -> ta.Any:
2185
+ def marshal(self, o: ta.Any, opts: ObjMarshalOptions) -> ta.Any:
2178
2186
  return o
2179
2187
 
2180
- def unmarshal(self, o: ta.Any) -> ta.Any:
2188
+ def unmarshal(self, o: ta.Any, opts: ObjMarshalOptions) -> ta.Any:
2181
2189
  return o
2182
2190
 
2183
2191
 
@@ -2185,29 +2193,29 @@ class NopObjMarshaler(ObjMarshaler):
2185
2193
  class ProxyObjMarshaler(ObjMarshaler):
2186
2194
  m: ta.Optional[ObjMarshaler] = None
2187
2195
 
2188
- def marshal(self, o: ta.Any) -> ta.Any:
2189
- return check_not_none(self.m).marshal(o)
2196
+ def marshal(self, o: ta.Any, opts: ObjMarshalOptions) -> ta.Any:
2197
+ return check_not_none(self.m).marshal(o, opts)
2190
2198
 
2191
- def unmarshal(self, o: ta.Any) -> ta.Any:
2192
- return check_not_none(self.m).unmarshal(o)
2199
+ def unmarshal(self, o: ta.Any, opts: ObjMarshalOptions) -> ta.Any:
2200
+ return check_not_none(self.m).unmarshal(o, opts)
2193
2201
 
2194
2202
 
2195
2203
  @dc.dataclass(frozen=True)
2196
2204
  class CastObjMarshaler(ObjMarshaler):
2197
2205
  ty: type
2198
2206
 
2199
- def marshal(self, o: ta.Any) -> ta.Any:
2207
+ def marshal(self, o: ta.Any, opts: ObjMarshalOptions) -> ta.Any:
2200
2208
  return o
2201
2209
 
2202
- def unmarshal(self, o: ta.Any) -> ta.Any:
2210
+ def unmarshal(self, o: ta.Any, opts: ObjMarshalOptions) -> ta.Any:
2203
2211
  return self.ty(o)
2204
2212
 
2205
2213
 
2206
2214
  class DynamicObjMarshaler(ObjMarshaler):
2207
- def marshal(self, o: ta.Any) -> ta.Any:
2215
+ def marshal(self, o: ta.Any, opts: ObjMarshalOptions) -> ta.Any:
2208
2216
  return marshal_obj(o)
2209
2217
 
2210
- def unmarshal(self, o: ta.Any) -> ta.Any:
2218
+ def unmarshal(self, o: ta.Any, opts: ObjMarshalOptions) -> ta.Any:
2211
2219
  return o
2212
2220
 
2213
2221
 
@@ -2215,21 +2223,36 @@ class DynamicObjMarshaler(ObjMarshaler):
2215
2223
  class Base64ObjMarshaler(ObjMarshaler):
2216
2224
  ty: type
2217
2225
 
2218
- def marshal(self, o: ta.Any) -> ta.Any:
2226
+ def marshal(self, o: ta.Any, opts: ObjMarshalOptions) -> ta.Any:
2219
2227
  return base64.b64encode(o).decode('ascii')
2220
2228
 
2221
- def unmarshal(self, o: ta.Any) -> ta.Any:
2229
+ def unmarshal(self, o: ta.Any, opts: ObjMarshalOptions) -> ta.Any:
2222
2230
  return self.ty(base64.b64decode(o))
2223
2231
 
2224
2232
 
2233
+ @dc.dataclass(frozen=True)
2234
+ class BytesSwitchedObjMarshaler(ObjMarshaler):
2235
+ m: ObjMarshaler
2236
+
2237
+ def marshal(self, o: ta.Any, opts: ObjMarshalOptions) -> ta.Any:
2238
+ if opts.raw_bytes:
2239
+ return o
2240
+ return self.m.marshal(o, opts)
2241
+
2242
+ def unmarshal(self, o: ta.Any, opts: ObjMarshalOptions) -> ta.Any:
2243
+ if opts.raw_bytes:
2244
+ return o
2245
+ return self.m.unmarshal(o, opts)
2246
+
2247
+
2225
2248
  @dc.dataclass(frozen=True)
2226
2249
  class EnumObjMarshaler(ObjMarshaler):
2227
2250
  ty: type
2228
2251
 
2229
- def marshal(self, o: ta.Any) -> ta.Any:
2252
+ def marshal(self, o: ta.Any, opts: ObjMarshalOptions) -> ta.Any:
2230
2253
  return o.name
2231
2254
 
2232
- def unmarshal(self, o: ta.Any) -> ta.Any:
2255
+ def unmarshal(self, o: ta.Any, opts: ObjMarshalOptions) -> ta.Any:
2233
2256
  return self.ty.__members__[o] # type: ignore
2234
2257
 
2235
2258
 
@@ -2237,15 +2260,15 @@ class EnumObjMarshaler(ObjMarshaler):
2237
2260
  class OptionalObjMarshaler(ObjMarshaler):
2238
2261
  item: ObjMarshaler
2239
2262
 
2240
- def marshal(self, o: ta.Any) -> ta.Any:
2263
+ def marshal(self, o: ta.Any, opts: ObjMarshalOptions) -> ta.Any:
2241
2264
  if o is None:
2242
2265
  return None
2243
- return self.item.marshal(o)
2266
+ return self.item.marshal(o, opts)
2244
2267
 
2245
- def unmarshal(self, o: ta.Any) -> ta.Any:
2268
+ def unmarshal(self, o: ta.Any, opts: ObjMarshalOptions) -> ta.Any:
2246
2269
  if o is None:
2247
2270
  return None
2248
- return self.item.unmarshal(o)
2271
+ return self.item.unmarshal(o, opts)
2249
2272
 
2250
2273
 
2251
2274
  @dc.dataclass(frozen=True)
@@ -2254,11 +2277,11 @@ class MappingObjMarshaler(ObjMarshaler):
2254
2277
  km: ObjMarshaler
2255
2278
  vm: ObjMarshaler
2256
2279
 
2257
- def marshal(self, o: ta.Any) -> ta.Any:
2258
- return {self.km.marshal(k): self.vm.marshal(v) for k, v in o.items()}
2280
+ def marshal(self, o: ta.Any, opts: ObjMarshalOptions) -> ta.Any:
2281
+ return {self.km.marshal(k, opts): self.vm.marshal(v, opts) for k, v in o.items()}
2259
2282
 
2260
- def unmarshal(self, o: ta.Any) -> ta.Any:
2261
- return self.ty((self.km.unmarshal(k), self.vm.unmarshal(v)) for k, v in o.items())
2283
+ def unmarshal(self, o: ta.Any, opts: ObjMarshalOptions) -> ta.Any:
2284
+ return self.ty((self.km.unmarshal(k, opts), self.vm.unmarshal(v, opts)) for k, v in o.items())
2262
2285
 
2263
2286
 
2264
2287
  @dc.dataclass(frozen=True)
@@ -2266,11 +2289,11 @@ class IterableObjMarshaler(ObjMarshaler):
2266
2289
  ty: type
2267
2290
  item: ObjMarshaler
2268
2291
 
2269
- def marshal(self, o: ta.Any) -> ta.Any:
2270
- return [self.item.marshal(e) for e in o]
2292
+ def marshal(self, o: ta.Any, opts: ObjMarshalOptions) -> ta.Any:
2293
+ return [self.item.marshal(e, opts) for e in o]
2271
2294
 
2272
- def unmarshal(self, o: ta.Any) -> ta.Any:
2273
- return self.ty(self.item.unmarshal(e) for e in o)
2295
+ def unmarshal(self, o: ta.Any, opts: ObjMarshalOptions) -> ta.Any:
2296
+ return self.ty(self.item.unmarshal(e, opts) for e in o)
2274
2297
 
2275
2298
 
2276
2299
  @dc.dataclass(frozen=True)
@@ -2279,11 +2302,11 @@ class DataclassObjMarshaler(ObjMarshaler):
2279
2302
  fs: ta.Mapping[str, ObjMarshaler]
2280
2303
  nonstrict: bool = False
2281
2304
 
2282
- def marshal(self, o: ta.Any) -> ta.Any:
2283
- return {k: m.marshal(getattr(o, k)) for k, m in self.fs.items()}
2305
+ def marshal(self, o: ta.Any, opts: ObjMarshalOptions) -> ta.Any:
2306
+ return {k: m.marshal(getattr(o, k), opts) for k, m in self.fs.items()}
2284
2307
 
2285
- def unmarshal(self, o: ta.Any) -> ta.Any:
2286
- return self.ty(**{k: self.fs[k].unmarshal(v) for k, v in o.items() if not self.nonstrict or k in self.fs})
2308
+ def unmarshal(self, o: ta.Any, opts: ObjMarshalOptions) -> ta.Any:
2309
+ return self.ty(**{k: self.fs[k].unmarshal(v, opts) for k, v in o.items() if not self.nonstrict or k in self.fs})
2287
2310
 
2288
2311
 
2289
2312
  @dc.dataclass(frozen=True)
@@ -2303,50 +2326,50 @@ class PolymorphicObjMarshaler(ObjMarshaler):
2303
2326
  {i.tag: i for i in impls},
2304
2327
  )
2305
2328
 
2306
- def marshal(self, o: ta.Any) -> ta.Any:
2329
+ def marshal(self, o: ta.Any, opts: ObjMarshalOptions) -> ta.Any:
2307
2330
  impl = self.impls_by_ty[type(o)]
2308
- return {impl.tag: impl.m.marshal(o)}
2331
+ return {impl.tag: impl.m.marshal(o, opts)}
2309
2332
 
2310
- def unmarshal(self, o: ta.Any) -> ta.Any:
2333
+ def unmarshal(self, o: ta.Any, opts: ObjMarshalOptions) -> ta.Any:
2311
2334
  [(t, v)] = o.items()
2312
2335
  impl = self.impls_by_tag[t]
2313
- return impl.m.unmarshal(v)
2336
+ return impl.m.unmarshal(v, opts)
2314
2337
 
2315
2338
 
2316
2339
  @dc.dataclass(frozen=True)
2317
2340
  class DatetimeObjMarshaler(ObjMarshaler):
2318
2341
  ty: type
2319
2342
 
2320
- def marshal(self, o: ta.Any) -> ta.Any:
2343
+ def marshal(self, o: ta.Any, opts: ObjMarshalOptions) -> ta.Any:
2321
2344
  return o.isoformat()
2322
2345
 
2323
- def unmarshal(self, o: ta.Any) -> ta.Any:
2346
+ def unmarshal(self, o: ta.Any, opts: ObjMarshalOptions) -> ta.Any:
2324
2347
  return self.ty.fromisoformat(o) # type: ignore
2325
2348
 
2326
2349
 
2327
2350
  class DecimalObjMarshaler(ObjMarshaler):
2328
- def marshal(self, o: ta.Any) -> ta.Any:
2351
+ def marshal(self, o: ta.Any, opts: ObjMarshalOptions) -> ta.Any:
2329
2352
  return str(check_isinstance(o, decimal.Decimal))
2330
2353
 
2331
- def unmarshal(self, v: ta.Any) -> ta.Any:
2354
+ def unmarshal(self, v: ta.Any, opts: ObjMarshalOptions) -> ta.Any:
2332
2355
  return decimal.Decimal(check_isinstance(v, str))
2333
2356
 
2334
2357
 
2335
2358
  class FractionObjMarshaler(ObjMarshaler):
2336
- def marshal(self, o: ta.Any) -> ta.Any:
2359
+ def marshal(self, o: ta.Any, opts: ObjMarshalOptions) -> ta.Any:
2337
2360
  fr = check_isinstance(o, fractions.Fraction)
2338
2361
  return [fr.numerator, fr.denominator]
2339
2362
 
2340
- def unmarshal(self, v: ta.Any) -> ta.Any:
2363
+ def unmarshal(self, v: ta.Any, opts: ObjMarshalOptions) -> ta.Any:
2341
2364
  num, denom = check_isinstance(v, list)
2342
2365
  return fractions.Fraction(num, denom)
2343
2366
 
2344
2367
 
2345
2368
  class UuidObjMarshaler(ObjMarshaler):
2346
- def marshal(self, o: ta.Any) -> ta.Any:
2369
+ def marshal(self, o: ta.Any, opts: ObjMarshalOptions) -> ta.Any:
2347
2370
  return str(o)
2348
2371
 
2349
- def unmarshal(self, o: ta.Any) -> ta.Any:
2372
+ def unmarshal(self, o: ta.Any, opts: ObjMarshalOptions) -> ta.Any:
2350
2373
  return uuid.UUID(o)
2351
2374
 
2352
2375
 
@@ -2356,7 +2379,7 @@ class UuidObjMarshaler(ObjMarshaler):
2356
2379
  _DEFAULT_OBJ_MARSHALERS: ta.Dict[ta.Any, ObjMarshaler] = {
2357
2380
  **{t: NopObjMarshaler() for t in (type(None),)},
2358
2381
  **{t: CastObjMarshaler(t) for t in (int, float, str, bool)},
2359
- **{t: Base64ObjMarshaler(t) for t in (bytes, bytearray)},
2382
+ **{t: BytesSwitchedObjMarshaler(Base64ObjMarshaler(t)) for t in (bytes, bytearray)},
2360
2383
  **{t: IterableObjMarshaler(t, DynamicObjMarshaler()) for t in (list, tuple, set, frozenset)},
2361
2384
  **{t: MappingObjMarshaler(t, DynamicObjMarshaler(), DynamicObjMarshaler()) for t in (dict,)},
2362
2385
 
@@ -2382,120 +2405,172 @@ _OBJ_MARSHALER_GENERIC_ITERABLE_TYPES: ta.Dict[ta.Any, type] = {
2382
2405
  }
2383
2406
 
2384
2407
 
2385
- def _make_obj_marshaler(
2386
- ty: ta.Any,
2387
- rec: ta.Callable[[ta.Any], ObjMarshaler],
2388
- *,
2389
- nonstrict_dataclasses: bool = False,
2390
- ) -> ObjMarshaler:
2391
- if isinstance(ty, type):
2392
- if abc.ABC in ty.__bases__:
2393
- return PolymorphicObjMarshaler.of([ # type: ignore
2394
- PolymorphicObjMarshaler.Impl(
2395
- ity,
2396
- ity.__qualname__,
2397
- rec(ity),
2398
- )
2399
- for ity in deep_subclasses(ty)
2400
- if abc.ABC not in ity.__bases__
2401
- ])
2402
-
2403
- if issubclass(ty, enum.Enum):
2404
- return EnumObjMarshaler(ty)
2405
-
2406
- if dc.is_dataclass(ty):
2407
- return DataclassObjMarshaler(
2408
- ty,
2409
- {f.name: rec(f.type) for f in dc.fields(ty)},
2410
- nonstrict=nonstrict_dataclasses,
2411
- )
2408
+ ##
2412
2409
 
2413
- if is_generic_alias(ty):
2414
- try:
2415
- mt = _OBJ_MARSHALER_GENERIC_MAPPING_TYPES[ta.get_origin(ty)]
2416
- except KeyError:
2417
- pass
2418
- else:
2419
- k, v = ta.get_args(ty)
2420
- return MappingObjMarshaler(mt, rec(k), rec(v))
2421
2410
 
2422
- try:
2423
- st = _OBJ_MARSHALER_GENERIC_ITERABLE_TYPES[ta.get_origin(ty)]
2424
- except KeyError:
2425
- pass
2426
- else:
2427
- [e] = ta.get_args(ty)
2428
- return IterableObjMarshaler(st, rec(e))
2411
+ class ObjMarshalerManager:
2412
+ def __init__(
2413
+ self,
2414
+ *,
2415
+ default_options: ObjMarshalOptions = ObjMarshalOptions(),
2429
2416
 
2430
- if is_union_alias(ty):
2431
- return OptionalObjMarshaler(rec(get_optional_alias_arg(ty)))
2417
+ default_obj_marshalers: ta.Dict[ta.Any, ObjMarshaler] = _DEFAULT_OBJ_MARSHALERS, # noqa
2418
+ generic_mapping_types: ta.Dict[ta.Any, type] = _OBJ_MARSHALER_GENERIC_MAPPING_TYPES, # noqa
2419
+ generic_iterable_types: ta.Dict[ta.Any, type] = _OBJ_MARSHALER_GENERIC_ITERABLE_TYPES, # noqa
2420
+ ) -> None:
2421
+ super().__init__()
2432
2422
 
2433
- raise TypeError(ty)
2423
+ self._default_options = default_options
2434
2424
 
2425
+ self._obj_marshalers = dict(default_obj_marshalers)
2426
+ self._generic_mapping_types = generic_mapping_types
2427
+ self._generic_iterable_types = generic_iterable_types
2435
2428
 
2436
- ##
2429
+ self._lock = threading.RLock()
2430
+ self._marshalers: ta.Dict[ta.Any, ObjMarshaler] = dict(_DEFAULT_OBJ_MARSHALERS)
2431
+ self._proxies: ta.Dict[ta.Any, ProxyObjMarshaler] = {}
2437
2432
 
2433
+ #
2438
2434
 
2439
- _OBJ_MARSHALERS_LOCK = threading.RLock()
2435
+ def make_obj_marshaler(
2436
+ self,
2437
+ ty: ta.Any,
2438
+ rec: ta.Callable[[ta.Any], ObjMarshaler],
2439
+ *,
2440
+ nonstrict_dataclasses: bool = False,
2441
+ ) -> ObjMarshaler:
2442
+ if isinstance(ty, type):
2443
+ if abc.ABC in ty.__bases__:
2444
+ return PolymorphicObjMarshaler.of([ # type: ignore
2445
+ PolymorphicObjMarshaler.Impl(
2446
+ ity,
2447
+ ity.__qualname__,
2448
+ rec(ity),
2449
+ )
2450
+ for ity in deep_subclasses(ty)
2451
+ if abc.ABC not in ity.__bases__
2452
+ ])
2453
+
2454
+ if issubclass(ty, enum.Enum):
2455
+ return EnumObjMarshaler(ty)
2456
+
2457
+ if dc.is_dataclass(ty):
2458
+ return DataclassObjMarshaler(
2459
+ ty,
2460
+ {f.name: rec(f.type) for f in dc.fields(ty)},
2461
+ nonstrict=nonstrict_dataclasses,
2462
+ )
2440
2463
 
2441
- _OBJ_MARSHALERS: ta.Dict[ta.Any, ObjMarshaler] = dict(_DEFAULT_OBJ_MARSHALERS)
2464
+ if is_generic_alias(ty):
2465
+ try:
2466
+ mt = self._generic_mapping_types[ta.get_origin(ty)]
2467
+ except KeyError:
2468
+ pass
2469
+ else:
2470
+ k, v = ta.get_args(ty)
2471
+ return MappingObjMarshaler(mt, rec(k), rec(v))
2442
2472
 
2443
- _OBJ_MARSHALER_PROXIES: ta.Dict[ta.Any, ProxyObjMarshaler] = {}
2473
+ try:
2474
+ st = self._generic_iterable_types[ta.get_origin(ty)]
2475
+ except KeyError:
2476
+ pass
2477
+ else:
2478
+ [e] = ta.get_args(ty)
2479
+ return IterableObjMarshaler(st, rec(e))
2444
2480
 
2481
+ if is_union_alias(ty):
2482
+ return OptionalObjMarshaler(rec(get_optional_alias_arg(ty)))
2445
2483
 
2446
- def register_opj_marshaler(ty: ta.Any, m: ObjMarshaler) -> None:
2447
- with _OBJ_MARSHALERS_LOCK:
2448
- if ty in _OBJ_MARSHALERS:
2449
- raise KeyError(ty)
2450
- _OBJ_MARSHALERS[ty] = m
2484
+ raise TypeError(ty)
2451
2485
 
2486
+ #
2487
+
2488
+ def register_opj_marshaler(self, ty: ta.Any, m: ObjMarshaler) -> None:
2489
+ with self._lock:
2490
+ if ty in self._obj_marshalers:
2491
+ raise KeyError(ty)
2492
+ self._obj_marshalers[ty] = m
2493
+
2494
+ def get_obj_marshaler(
2495
+ self,
2496
+ ty: ta.Any,
2497
+ *,
2498
+ no_cache: bool = False,
2499
+ **kwargs: ta.Any,
2500
+ ) -> ObjMarshaler:
2501
+ with self._lock:
2502
+ if not no_cache:
2503
+ try:
2504
+ return self._obj_marshalers[ty]
2505
+ except KeyError:
2506
+ pass
2452
2507
 
2453
- def get_obj_marshaler(
2454
- ty: ta.Any,
2455
- *,
2456
- no_cache: bool = False,
2457
- **kwargs: ta.Any,
2458
- ) -> ObjMarshaler:
2459
- with _OBJ_MARSHALERS_LOCK:
2460
- if not no_cache:
2461
2508
  try:
2462
- return _OBJ_MARSHALERS[ty]
2509
+ return self._proxies[ty]
2463
2510
  except KeyError:
2464
2511
  pass
2465
2512
 
2466
- try:
2467
- return _OBJ_MARSHALER_PROXIES[ty]
2468
- except KeyError:
2469
- pass
2513
+ rec = functools.partial(
2514
+ self.get_obj_marshaler,
2515
+ no_cache=no_cache,
2516
+ **kwargs,
2517
+ )
2470
2518
 
2471
- rec = functools.partial(
2472
- get_obj_marshaler,
2473
- no_cache=no_cache,
2474
- **kwargs,
2475
- )
2519
+ p = ProxyObjMarshaler()
2520
+ self._proxies[ty] = p
2521
+ try:
2522
+ m = self.make_obj_marshaler(ty, rec, **kwargs)
2523
+ finally:
2524
+ del self._proxies[ty]
2525
+ p.m = m
2476
2526
 
2477
- p = ProxyObjMarshaler()
2478
- _OBJ_MARSHALER_PROXIES[ty] = p
2479
- try:
2480
- m = _make_obj_marshaler(ty, rec, **kwargs)
2481
- finally:
2482
- del _OBJ_MARSHALER_PROXIES[ty]
2483
- p.m = m
2527
+ if not no_cache:
2528
+ self._obj_marshalers[ty] = m
2529
+ return m
2530
+
2531
+ #
2484
2532
 
2485
- if not no_cache:
2486
- _OBJ_MARSHALERS[ty] = m
2487
- return m
2533
+ def marshal_obj(
2534
+ self,
2535
+ o: ta.Any,
2536
+ ty: ta.Any = None,
2537
+ opts: ta.Optional[ObjMarshalOptions] = None,
2538
+ ) -> ta.Any:
2539
+ m = self.get_obj_marshaler(ty if ty is not None else type(o))
2540
+ return m.marshal(o, opts or self._default_options)
2541
+
2542
+ def unmarshal_obj(
2543
+ self,
2544
+ o: ta.Any,
2545
+ ty: ta.Union[ta.Type[T], ta.Any],
2546
+ opts: ta.Optional[ObjMarshalOptions] = None,
2547
+ ) -> T:
2548
+ m = self.get_obj_marshaler(ty)
2549
+ return m.unmarshal(o, opts or self._default_options)
2550
+
2551
+ def roundtrip_obj(
2552
+ self,
2553
+ o: ta.Any,
2554
+ ty: ta.Any = None,
2555
+ opts: ta.Optional[ObjMarshalOptions] = None,
2556
+ ) -> ta.Any:
2557
+ if ty is None:
2558
+ ty = type(o)
2559
+ m: ta.Any = self.marshal_obj(o, ty, opts)
2560
+ u: ta.Any = self.unmarshal_obj(m, ty, opts)
2561
+ return u
2488
2562
 
2489
2563
 
2490
2564
  ##
2491
2565
 
2492
2566
 
2493
- def marshal_obj(o: ta.Any, ty: ta.Any = None) -> ta.Any:
2494
- return get_obj_marshaler(ty if ty is not None else type(o)).marshal(o)
2567
+ OBJ_MARSHALER_MANAGER = ObjMarshalerManager()
2495
2568
 
2569
+ register_opj_marshaler = OBJ_MARSHALER_MANAGER.register_opj_marshaler
2570
+ get_obj_marshaler = OBJ_MARSHALER_MANAGER.get_obj_marshaler
2496
2571
 
2497
- def unmarshal_obj(o: ta.Any, ty: ta.Union[ta.Type[T], ta.Any]) -> T:
2498
- return get_obj_marshaler(ty).unmarshal(o)
2572
+ marshal_obj = OBJ_MARSHALER_MANAGER.marshal_obj
2573
+ unmarshal_obj = OBJ_MARSHALER_MANAGER.unmarshal_obj
2499
2574
 
2500
2575
 
2501
2576
  ########################################
@@ -3058,6 +3133,16 @@ class ThreadWorkerGroup:
3058
3133
  ##
3059
3134
 
3060
3135
 
3136
+ SUBPROCESS_CHANNEL_OPTION_VALUES: ta.Mapping[SubprocessChannelOption, int] = {
3137
+ 'pipe': subprocess.PIPE,
3138
+ 'stdout': subprocess.STDOUT,
3139
+ 'devnull': subprocess.DEVNULL,
3140
+ }
3141
+
3142
+
3143
+ ##
3144
+
3145
+
3061
3146
  _SUBPROCESS_SHELL_WRAP_EXECS = False
3062
3147
 
3063
3148