omlish 0.0.0.dev433__py3-none-any.whl → 0.0.0.dev435__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 (54) hide show
  1. omlish/__about__.py +2 -2
  2. omlish/asyncs/all.py +0 -13
  3. omlish/concurrent/__init__.py +0 -17
  4. omlish/concurrent/all.py +17 -0
  5. omlish/configs/types.py +1 -1
  6. omlish/daemons/__init__.py +70 -0
  7. omlish/dataclasses/errors.py +1 -1
  8. omlish/formats/json/stream/lexing.py +12 -6
  9. omlish/formats/json/stream/utils.py +28 -2
  10. omlish/formats/json5/stream.py +82 -0
  11. omlish/funcs/genmachine.py +1 -1
  12. omlish/http/coro/server/server.py +1 -1
  13. omlish/inject/__init__.py +152 -126
  14. omlish/inject/binder.py +7 -4
  15. omlish/inject/impl/elements.py +6 -8
  16. omlish/inject/impl/injector.py +58 -32
  17. omlish/inject/impl/inspect.py +1 -0
  18. omlish/inject/impl/maysync.py +44 -0
  19. omlish/inject/impl/multis.py +5 -5
  20. omlish/inject/impl/privates.py +8 -8
  21. omlish/inject/impl/providers.py +24 -31
  22. omlish/inject/impl/providers2.py +43 -0
  23. omlish/inject/impl/scopes.py +19 -25
  24. omlish/inject/impl/sync.py +42 -0
  25. omlish/inject/injector.py +9 -11
  26. omlish/inject/inspect.py +1 -3
  27. omlish/inject/listeners.py +4 -4
  28. omlish/inject/managed.py +52 -20
  29. omlish/inject/maysync.py +27 -0
  30. omlish/inject/providers.py +6 -0
  31. omlish/inject/scopes.py +38 -10
  32. omlish/inject/sync.py +46 -0
  33. omlish/lang/__init__.py +12 -3
  34. omlish/lang/asyncs.py +18 -0
  35. omlish/lang/contextmanagers.py +23 -0
  36. omlish/lite/asyncs.py +21 -0
  37. omlish/lite/attrops.py +1 -1
  38. omlish/lite/inject.py +4 -4
  39. omlish/lite/maysync.py +21 -0
  40. omlish/marshal/__init__.py +20 -8
  41. omlish/os/atomics.py +1 -1
  42. omlish/reflect/ops.py +9 -0
  43. omlish/reflect/types.py +19 -6
  44. omlish/sockets/addresses.py +1 -1
  45. omlish/sql/queries/params.py +1 -1
  46. {omlish-0.0.0.dev433.dist-info → omlish-0.0.0.dev435.dist-info}/METADATA +1 -4
  47. {omlish-0.0.0.dev433.dist-info → omlish-0.0.0.dev435.dist-info}/RECORD +51 -47
  48. omlish/asyncs/bridge.py +0 -359
  49. omlish/asyncs/utils.py +0 -18
  50. omlish/formats/json5/streams.py +0 -22
  51. {omlish-0.0.0.dev433.dist-info → omlish-0.0.0.dev435.dist-info}/WHEEL +0 -0
  52. {omlish-0.0.0.dev433.dist-info → omlish-0.0.0.dev435.dist-info}/entry_points.txt +0 -0
  53. {omlish-0.0.0.dev433.dist-info → omlish-0.0.0.dev435.dist-info}/licenses/LICENSE +0 -0
  54. {omlish-0.0.0.dev433.dist-info → omlish-0.0.0.dev435.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,42 @@
1
+ import typing as ta
2
+
3
+ from ... import lang
4
+ from ..elements import Elements
5
+ from ..injector import AsyncInjector
6
+ from ..inspect import KwargsTarget
7
+ from ..keys import Key
8
+ from ..sync import Injector
9
+ from .elements import ElementCollection
10
+ from .injector import AsyncInjectorImpl
11
+
12
+
13
+ ##
14
+
15
+
16
+ class InjectorImpl(Injector, lang.Final):
17
+ _ai: AsyncInjector
18
+
19
+ def try_provide(self, key: ta.Any) -> lang.Maybe[ta.Any]:
20
+ return lang.sync_await(self._ai.try_provide(key))
21
+
22
+ def provide(self, key: ta.Any) -> ta.Any:
23
+ return lang.sync_await(self._ai.provide(key))
24
+
25
+ def provide_kwargs(self, kt: KwargsTarget) -> ta.Mapping[str, ta.Any]:
26
+ return lang.sync_await(self._ai.provide_kwargs(kt))
27
+
28
+ def inject(self, obj: ta.Any) -> ta.Any:
29
+ return lang.sync_await(self._ai.inject(obj))
30
+
31
+
32
+ def create_injector(es: Elements) -> Injector:
33
+ si = InjectorImpl()
34
+ ai = AsyncInjectorImpl(
35
+ ElementCollection(es),
36
+ internal_consts={
37
+ Key(Injector): si,
38
+ },
39
+ )
40
+ si._ai = ai # noqa
41
+ lang.sync_await(ai._init()) # noqa
42
+ return si
omlish/inject/injector.py CHANGED
@@ -8,10 +8,8 @@ from .inspect import KwargsTarget
8
8
  from .keys import Key
9
9
 
10
10
 
11
- if ta.TYPE_CHECKING:
11
+ with lang.auto_proxy_import(globals()):
12
12
  from .impl import injector as _injector
13
- else:
14
- _injector = lang.proxy_import('.impl.injector', __package__)
15
13
 
16
14
 
17
15
  T = ta.TypeVar('T')
@@ -20,29 +18,29 @@ T = ta.TypeVar('T')
20
18
  ##
21
19
 
22
20
 
23
- class Injector(lang.Abstract):
21
+ class AsyncInjector(lang.Abstract):
24
22
  @abc.abstractmethod
25
- def try_provide(self, key: ta.Any) -> lang.Maybe[ta.Any]:
23
+ def try_provide(self, key: ta.Any) -> ta.Awaitable[lang.Maybe[ta.Any]]:
26
24
  raise NotImplementedError
27
25
 
28
26
  @abc.abstractmethod
29
- def provide(self, key: ta.Any) -> ta.Any:
27
+ def provide(self, key: ta.Any) -> ta.Awaitable[ta.Any]:
30
28
  raise NotImplementedError
31
29
 
32
30
  @abc.abstractmethod
33
- def provide_kwargs(self, kt: KwargsTarget) -> ta.Mapping[str, ta.Any]:
31
+ def provide_kwargs(self, kt: KwargsTarget) -> ta.Awaitable[ta.Mapping[str, ta.Any]]:
34
32
  raise NotImplementedError
35
33
 
36
34
  @abc.abstractmethod
37
- def inject(self, obj: ta.Any) -> ta.Any:
35
+ def inject(self, obj: ta.Any) -> ta.Awaitable[ta.Any]:
38
36
  raise NotImplementedError
39
37
 
40
38
  def __getitem__(
41
39
  self,
42
40
  target: Key[T] | type[T],
43
- ) -> T:
41
+ ) -> ta.Awaitable[T]:
44
42
  return self.provide(target)
45
43
 
46
44
 
47
- def create_injector(*args: Elemental) -> Injector:
48
- return _injector.create_injector(as_elements(*args))
45
+ def create_async_injector(*args: Elemental) -> ta.Awaitable[AsyncInjector]:
46
+ return _injector.create_async_injector(as_elements(*args))
omlish/inject/inspect.py CHANGED
@@ -4,10 +4,8 @@ from .. import lang
4
4
  from .keys import Key
5
5
 
6
6
 
7
- if ta.TYPE_CHECKING:
7
+ with lang.auto_proxy_import(globals()):
8
8
  from .impl import inspect as _inspect
9
- else:
10
- _inspect = lang.proxy_import('.impl.inspect', __package__)
11
9
 
12
10
 
13
11
  T = ta.TypeVar('T')
@@ -4,7 +4,7 @@ from .. import dataclasses as dc
4
4
  from .. import lang
5
5
  from .bindings import Binding
6
6
  from .elements import Element
7
- from .injector import Injector
7
+ from .injector import AsyncInjector
8
8
  from .keys import Key
9
9
 
10
10
 
@@ -12,11 +12,11 @@ from .keys import Key
12
12
 
13
13
 
14
14
  ProvisionListener: ta.TypeAlias = ta.Callable[[
15
- Injector,
15
+ AsyncInjector,
16
16
  Key,
17
17
  Binding | None,
18
- ta.Callable[[], ta.Any],
19
- ], ta.Callable[[], ta.Any]]
18
+ ta.Callable[[], ta.Awaitable[ta.Any]],
19
+ ], ta.Awaitable[ta.Any]]
20
20
 
21
21
 
22
22
  @dc.dataclass(frozen=True)
omlish/inject/managed.py CHANGED
@@ -9,14 +9,12 @@ from .. import lang
9
9
  from .binder import bind
10
10
  from .elements import Elemental
11
11
  from .impl.inspect import build_kwargs_target
12
- from .injector import Injector
13
- from .injector import create_injector
14
12
 
15
13
 
16
- if ta.TYPE_CHECKING:
17
- from ..asyncs import all as _asyncs
18
- else:
19
- _asyncs = lang.proxy_import('..asyncs.all', __package__)
14
+ with lang.auto_proxy_import(globals()):
15
+ from . import injector as _injector
16
+ from . import maysync as _maysync
17
+ from . import sync as _sync
20
18
 
21
19
 
22
20
  T = ta.TypeVar('T')
@@ -25,9 +23,43 @@ T = ta.TypeVar('T')
25
23
  ##
26
24
 
27
25
 
26
+ @contextlib.asynccontextmanager
27
+ async def create_async_managed_injector(*args: Elemental) -> ta.AsyncGenerator['_injector.AsyncInjector']:
28
+ ai = await _injector.create_async_injector(
29
+ bind(contextlib.AsyncExitStack, singleton=True, eager=True),
30
+ *args,
31
+ )
32
+ async with (await ai[contextlib.AsyncExitStack]):
33
+ yield ai
34
+
35
+
36
+ def make_async_managed_provider(
37
+ fac: ta.Callable[..., T],
38
+ *fns: ta.Callable[[T], ta.AsyncContextManager[T]],
39
+ ) -> ta.Callable[..., ta.Awaitable[T]]:
40
+ kt = build_kwargs_target(fac)
41
+
42
+ async def _provide(
43
+ ai: _injector.AsyncInjector,
44
+ aes: contextlib.AsyncExitStack,
45
+ ):
46
+ obj = await ai.inject(kt)
47
+ if not fns:
48
+ obj = await aes.enter_async_context(obj)
49
+ else:
50
+ for fn in fns:
51
+ await aes.enter_async_context(fn(obj))
52
+ return obj
53
+
54
+ return _provide
55
+
56
+
57
+ ##
58
+
59
+
28
60
  @contextlib.contextmanager
29
- def create_managed_injector(*args: Elemental) -> ta.Generator[Injector]:
30
- i = create_injector(
61
+ def create_managed_injector(*args: Elemental) -> ta.Generator['_sync.Injector']:
62
+ i = _sync.create_injector(
31
63
  bind(contextlib.ExitStack, singleton=True, eager=True),
32
64
  *args,
33
65
  )
@@ -42,7 +74,7 @@ def make_managed_provider(
42
74
  kt = build_kwargs_target(fac)
43
75
 
44
76
  def _provide(
45
- i: Injector,
77
+ i: _sync.Injector,
46
78
  es: contextlib.ExitStack,
47
79
  ):
48
80
  obj = i.inject(kt)
@@ -59,32 +91,32 @@ def make_managed_provider(
59
91
  ##
60
92
 
61
93
 
62
- @contextlib.asynccontextmanager
63
- async def create_async_managed_injector(*args: Elemental) -> ta.AsyncGenerator[Injector]:
64
- i = await _asyncs.s_to_a(create_injector)(
65
- bind(contextlib.AsyncExitStack, singleton=True, eager=True),
94
+ @contextlib.contextmanager
95
+ def create_maysync_managed_injector(*args: Elemental) -> ta.Generator['_maysync.MaysyncInjector']:
96
+ i = _maysync.create_maysync_injector(
97
+ bind(contextlib.ExitStack, singleton=True, eager=True),
66
98
  *args,
67
99
  )
68
- async with i[contextlib.AsyncExitStack]:
100
+ with i[contextlib.ExitStack]:
69
101
  yield i
70
102
 
71
103
 
72
- def make_async_managed_provider(
104
+ def make_maysync_managed_provider(
73
105
  fac: ta.Callable[..., T],
74
- *fns: ta.Callable[[T], ta.AsyncContextManager[T]],
106
+ *fns: ta.Callable[[T], ta.ContextManager[T]],
75
107
  ) -> ta.Callable[..., T]:
76
108
  kt = build_kwargs_target(fac)
77
109
 
78
110
  def _provide(
79
- i: Injector,
80
- aes: contextlib.AsyncExitStack,
111
+ i: _maysync.MaysyncInjector,
112
+ es: contextlib.ExitStack,
81
113
  ):
82
114
  obj = i.inject(kt)
83
115
  if not fns:
84
- obj = _asyncs.a_to_s(aes.enter_async_context)(obj)
116
+ obj = es.enter_context(obj)
85
117
  else:
86
118
  for fn in fns:
87
- _asyncs.a_to_s(aes.enter_async_context)(fn(obj))
119
+ es.enter_context(fn(obj))
88
120
  return obj
89
121
 
90
122
  return _provide
@@ -0,0 +1,27 @@
1
+ import typing as ta
2
+
3
+ from .. import lang
4
+ from .elements import Elemental
5
+ from .elements import as_elements
6
+ from .sync import Injector
7
+
8
+
9
+ with lang.auto_proxy_import(globals()):
10
+ from .impl import maysync as _maysync
11
+
12
+
13
+ T = ta.TypeVar('T')
14
+
15
+
16
+ ##
17
+
18
+
19
+ class MaysyncInjector(Injector, lang.Abstract):
20
+ pass
21
+
22
+
23
+ ##
24
+
25
+
26
+ def create_maysync_injector(*args: Elemental) -> MaysyncInjector:
27
+ return _maysync.create_maysync_injector(as_elements(*args))
@@ -17,6 +17,12 @@ class Provider(lang.Abstract):
17
17
  pass
18
18
 
19
19
 
20
+ @dc.dataclass(frozen=True)
21
+ @dc.extra_class_params(cache_hash=True)
22
+ class AsyncFnProvider(Provider):
23
+ fn: ta.Any = dc.xfield(validate=callable)
24
+
25
+
20
26
  @dc.dataclass(frozen=True)
21
27
  @dc.extra_class_params(cache_hash=True)
22
28
  class FnProvider(Provider):
omlish/inject/scopes.py CHANGED
@@ -7,16 +7,17 @@ from .. import dataclasses as dc
7
7
  from .. import lang
8
8
  from .bindings import Binding
9
9
  from .elements import Element
10
+ from .injector import AsyncInjector
10
11
  from .keys import Key
11
12
  from .keys import as_key
12
13
  from .providers import Provider
13
14
  from .types import Scope
14
15
 
15
16
 
16
- if ta.TYPE_CHECKING:
17
- from . import injector as injector_
18
- else:
19
- injector_ = lang.proxy_import('.injector', __package__)
17
+ with lang.auto_proxy_import(globals()):
18
+ from . import injector as _injector
19
+ from . import maysync as _maysync
20
+ from . import sync as _sync
20
21
 
21
22
 
22
23
  ##
@@ -65,7 +66,7 @@ class SeededScope(Scope, lang.Final):
65
66
 
66
67
  class Manager(lang.Abstract):
67
68
  @abc.abstractmethod
68
- def __call__(self, seeds: ta.Mapping[Key, ta.Any]) -> ta.ContextManager[None]:
69
+ def __call__(self, seeds: ta.Mapping[Key, ta.Any]) -> ta.AsyncContextManager[None]:
69
70
  raise NotImplementedError
70
71
 
71
72
 
@@ -81,11 +82,38 @@ def bind_scope_seed(k: ta.Any, ss: SeededScope) -> Element:
81
82
  return Binding(k, ScopeSeededProvider(ss, k))
82
83
 
83
84
 
84
- @contextlib.contextmanager
85
- def enter_seeded_scope(
86
- i: injector_.Injector,
85
+ ##
86
+
87
+
88
+ @contextlib.asynccontextmanager
89
+ async def async_enter_seeded_scope(
90
+ i: '_injector.AsyncInjector',
87
91
  ss: SeededScope,
88
92
  keys: ta.Mapping[Key, ta.Any],
89
- ) -> ta.Generator[None]:
90
- with i.provide(Key(SeededScope.Manager, tag=ss))(keys):
93
+ ) -> ta.AsyncGenerator[None]:
94
+ async with (await i.provide(Key(SeededScope.Manager, tag=ss)))(keys):
91
95
  yield
96
+
97
+
98
+ def enter_seeded_scope(
99
+ i: '_sync.Injector',
100
+ ss: SeededScope,
101
+ keys: ta.Mapping[Key, ta.Any],
102
+ ) -> ta.ContextManager[None]:
103
+ return lang.run_maysync_context_manager(async_enter_seeded_scope(
104
+ i[AsyncInjector],
105
+ ss,
106
+ keys,
107
+ ))
108
+
109
+
110
+ def maysync_enter_seeded_scope(
111
+ i: '_maysync.MaysyncInjector',
112
+ ss: SeededScope,
113
+ keys: ta.Mapping[Key, ta.Any],
114
+ ) -> ta.ContextManager[None]:
115
+ return lang.sync_async_context_manager(async_enter_seeded_scope(
116
+ i[AsyncInjector],
117
+ ss,
118
+ keys,
119
+ ))
omlish/inject/sync.py ADDED
@@ -0,0 +1,46 @@
1
+ import abc
2
+ import typing as ta
3
+
4
+ from .. import lang
5
+ from .elements import Elemental
6
+ from .elements import as_elements
7
+ from .inspect import KwargsTarget
8
+ from .keys import Key
9
+
10
+
11
+ with lang.auto_proxy_import(globals()):
12
+ from .impl import sync as _sync
13
+
14
+
15
+ T = ta.TypeVar('T')
16
+
17
+
18
+ ##
19
+
20
+
21
+ class Injector(lang.Abstract):
22
+ @abc.abstractmethod
23
+ def try_provide(self, key: ta.Any) -> lang.Maybe[ta.Any]:
24
+ raise NotImplementedError
25
+
26
+ @abc.abstractmethod
27
+ def provide(self, key: ta.Any) -> ta.Any:
28
+ raise NotImplementedError
29
+
30
+ @abc.abstractmethod
31
+ def provide_kwargs(self, kt: KwargsTarget) -> ta.Mapping[str, ta.Any]:
32
+ raise NotImplementedError
33
+
34
+ @abc.abstractmethod
35
+ def inject(self, obj: ta.Any) -> ta.Any:
36
+ raise NotImplementedError
37
+
38
+ def __getitem__(
39
+ self,
40
+ target: Key[T] | type[T],
41
+ ) -> T:
42
+ return self.provide(target)
43
+
44
+
45
+ def create_injector(*args: Elemental) -> Injector:
46
+ return _sync.create_injector(as_elements(*args))
omlish/lang/__init__.py CHANGED
@@ -15,6 +15,9 @@ with _auto_proxy_init(
15
15
 
16
16
  sync_await,
17
17
  sync_async_list,
18
+
19
+ SyncAsyncContextManager,
20
+ sync_async_context_manager,
18
21
  )
19
22
 
20
23
  from .attrstorage import ( # noqa
@@ -184,6 +187,9 @@ with _auto_proxy_init(
184
187
  Timer,
185
188
 
186
189
  double_check_setdefault,
190
+
191
+ call_with_exit_stack,
192
+ call_with_async_exit_stack,
187
193
  )
188
194
 
189
195
  from .datetimes import ( # noqa
@@ -487,9 +493,6 @@ with _auto_proxy_init(
487
493
  )
488
494
 
489
495
  from ..lite.maysync import ( # noqa
490
- mark_maysync,
491
- is_maysync,
492
-
493
496
  AnyMaysyncFn,
494
497
 
495
498
  MaywaitableAlreadyConsumedError,
@@ -504,6 +507,12 @@ with _auto_proxy_init(
504
507
  is_running_maysync,
505
508
 
506
509
  run_maysync,
510
+
511
+ RunMaysyncContextManager,
512
+ run_maysync_context_manager,
513
+
514
+ mark_maysync,
515
+ is_maysync,
507
516
  )
508
517
 
509
518
  from ..lite.objects import ( # noqa
omlish/lang/asyncs.py CHANGED
@@ -79,3 +79,21 @@ def sync_async_list(
79
79
  raise TypeError(lst)
80
80
 
81
81
  return lst
82
+
83
+
84
+ @ta.final
85
+ class SyncAsyncContextManager(ta.Generic[T]):
86
+ def __init__(self, acm: ta.AsyncContextManager[T]) -> None:
87
+ self._acm = acm
88
+
89
+ def __repr__(self) -> str:
90
+ return f'{self.__class__.__name__}({self._acm!r})'
91
+
92
+ def __enter__(self) -> T:
93
+ return sync_await(self._acm.__aenter__())
94
+
95
+ def __exit__(self, exc_type, exc_val, exc_tb):
96
+ return sync_await(self._acm.__aexit__(exc_type, exc_val, exc_tb))
97
+
98
+
99
+ sync_async_context_manager = SyncAsyncContextManager
@@ -20,6 +20,8 @@ T = ta.TypeVar('T')
20
20
  K = ta.TypeVar('K')
21
21
  V = ta.TypeVar('V')
22
22
 
23
+ P = ta.ParamSpec('P')
24
+
23
25
 
24
26
  ##
25
27
 
@@ -382,3 +384,24 @@ def double_check_setdefault(
382
384
  v = fn()
383
385
  dct[k] = v
384
386
  return v
387
+
388
+
389
+ ##
390
+
391
+
392
+ def call_with_exit_stack(
393
+ fn: ta.Callable[ta.Concatenate[contextlib.ExitStack, P], T],
394
+ *args: ta.Any,
395
+ **kwargs: ta.Any,
396
+ ) -> T:
397
+ with contextlib.ExitStack() as es:
398
+ return fn(es, *args, **kwargs)
399
+
400
+
401
+ async def call_with_async_exit_stack(
402
+ fn: ta.Callable[ta.Concatenate[contextlib.AsyncExitStack, P], ta.Awaitable[T]],
403
+ *args: ta.Any,
404
+ **kwargs: ta.Any,
405
+ ) -> T:
406
+ async with contextlib.AsyncExitStack() as aes:
407
+ return await fn(aes, *args, **kwargs)
omlish/lite/asyncs.py CHANGED
@@ -18,3 +18,24 @@ def as_async(fn: ta.Callable[..., T], *, wrap: bool = False) -> ta.Callable[...,
18
18
  return fn(*args, **kwargs)
19
19
 
20
20
  return functools.wraps(fn)(inner) if wrap else inner
21
+
22
+
23
+ ##
24
+
25
+
26
+ @ta.final
27
+ class SyncToAsyncContextManager(ta.Generic[T]):
28
+ def __init__(self, cm: ta.ContextManager[T]) -> None:
29
+ self._cm = cm
30
+
31
+ def __repr__(self) -> str:
32
+ return f'{self.__class__.__name__}({self._cm!r})'
33
+
34
+ async def __aenter__(self) -> T:
35
+ return self._cm.__enter__()
36
+
37
+ async def __aexit__(self, exc_type, exc_value, traceback, /):
38
+ return self._cm.__exit__(exc_type, exc_value, traceback)
39
+
40
+
41
+ as_async_context_manager = SyncToAsyncContextManager
omlish/lite/attrops.py CHANGED
@@ -212,7 +212,7 @@ class AttrOps(ta.Generic[T]):
212
212
  return (
213
213
  f'{o.__class__.__module__ + "." if self._with_module else ""}'
214
214
  f'{o.__class__.__qualname__ if self._use_qualname else o.__class__.__name__}'
215
- f'{("@" + hex(id(o))[2:]) if self._with_id else ""}'
215
+ f'{("@" + hex(id(o))[2:]) if self._with_id else ""}' # noqa
216
216
  f'({vs})'
217
217
  )
218
218
 
omlish/lite/inject.py CHANGED
@@ -21,12 +21,12 @@ T = ta.TypeVar('T')
21
21
  U = ta.TypeVar('U')
22
22
 
23
23
 
24
- InjectorKeyCls = ta.Union[type, ta.NewType]
24
+ InjectorKeyCls = ta.Union[type, ta.NewType] # ta.TypeAlias
25
25
 
26
- InjectorProviderFn = ta.Callable[['Injector'], ta.Any]
27
- InjectorProviderFnMap = ta.Mapping['InjectorKey', 'InjectorProviderFn']
26
+ InjectorProviderFn = ta.Callable[['Injector'], ta.Any] # ta.TypeAlias
27
+ InjectorProviderFnMap = ta.Mapping['InjectorKey', 'InjectorProviderFn'] # ta.TypeAlias
28
28
 
29
- InjectorBindingOrBindings = ta.Union['InjectorBinding', 'InjectorBindings']
29
+ InjectorBindingOrBindings = ta.Union['InjectorBinding', 'InjectorBindings'] # ta.TypeAlias
30
30
 
31
31
 
32
32
  ###
omlish/lite/maysync.py CHANGED
@@ -523,6 +523,27 @@ def run_maysync(m):
523
523
  ##
524
524
 
525
525
 
526
+ @ta.final
527
+ class RunMaysyncContextManager(ta.Generic[T]):
528
+ def __init__(self, acm: ta.AsyncContextManager[T]) -> None:
529
+ self._acm = acm
530
+
531
+ def __repr__(self) -> str:
532
+ return f'{self.__class__.__name__}({self._acm!r})'
533
+
534
+ def __enter__(self) -> T:
535
+ return run_maysync(self._acm.__aenter__())
536
+
537
+ def __exit__(self, exc_type, exc_val, exc_tb):
538
+ return run_maysync(self._acm.__aexit__(exc_type, exc_val, exc_tb))
539
+
540
+
541
+ run_maysync_context_manager = RunMaysyncContextManager
542
+
543
+
544
+ ##
545
+
546
+
526
547
  _MAYSYNC_MARK_ATTR = '__maysync__'
527
548
 
528
549
 
@@ -1,14 +1,24 @@
1
1
  # ruff: noqa: I001
2
2
  """
3
3
  TODO:
4
- - redacted
5
- - strongly typed MarshalerFactory base class?
6
- - strongly typed Composite/Cached Marshaler/Unmarshaler factories - footgun
7
- - streaming? Start/EndObject, etc..
8
- - lang.Marker - class name, handle type[Foo]
9
- - can't disambiguate from str - can't coexist in bare union
10
- - factories being free MatchFns does more harm than good - in practice these are such big guns you want to write a
11
- class body if only ceremonially
4
+ - streaming?
5
+ - datatypes
6
+ - redacted
7
+ - lang.Marker - class name, handle type[Foo]
8
+ - pathlib.Path
9
+ - decimal.Decimal
10
+ - datetime.date, datetime.time
11
+ - ipaddress
12
+ - numpy types
13
+ - jackson switches
14
+ - accept_case_insensitive_enums
15
+ - accept_case_insensitive_properties
16
+ - accept_case_insensitive_values
17
+ - allow_coercion_of_scalars
18
+ - use_base_type_as_default_impl
19
+ - codegen
20
+ - context-local switches
21
+ - mutable_collections
12
22
  - simple lite interop like inj - alt ObjMarshalerManager impl for Context
13
23
 
14
24
  See:
@@ -16,6 +26,8 @@ See:
16
26
  - https://github.com/jcrist/msgspec
17
27
  - https://github.com/Fatal1ty/mashumaro
18
28
  - https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/serializers.md#custom-serializers
29
+ - https://github.com/yukinarit/pyserde
30
+ - https://github.com/FasterXML/jackson
19
31
  """
20
32
  from .. import dataclasses as _dc # noqa
21
33
 
omlish/os/atomics.py CHANGED
@@ -11,7 +11,7 @@ from ..lite.attrops import attr_repr
11
11
  from ..lite.check import check
12
12
 
13
13
 
14
- AtomicPathSwapKind = ta.Literal['dir', 'file']
14
+ AtomicPathSwapKind = ta.Literal['dir', 'file'] # ta.TypeAlias
15
15
  AtomicPathSwapState = ta.Literal['open', 'committed', 'aborted'] # ta.TypeAlias
16
16
 
17
17
 
omlish/reflect/ops.py CHANGED
@@ -1,3 +1,12 @@
1
+ """
2
+ TODO:
3
+ - visitor / transformer
4
+ - gson had an ObjectNavigator:
5
+ - https://github.com/google/gson/blob/f291c4d33ea5fcc52afcfa5713e519e663378bda/gson/src/main/java/com/google/gson/ObjectNavigator.java
6
+ - removed in 25c6ae177b1ca56db7f3c29eb574bdd032a06165
7
+ - uniform collection isinstance - items() for mappings, iter() for other
8
+ - also check instance type in isinstance not just items lol
9
+ """ # noqa
1
10
  import dataclasses as dc
2
11
  import typing as ta
3
12