omlish 0.0.0.dev4__py3-none-any.whl → 0.0.0.dev5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of omlish might be problematic. Click here for more details.

Files changed (86) hide show
  1. omlish/__about__.py +1 -1
  2. omlish/__init__.py +1 -1
  3. omlish/asyncs/__init__.py +1 -4
  4. omlish/asyncs/anyio.py +66 -0
  5. omlish/asyncs/flavors.py +27 -1
  6. omlish/asyncs/trio_asyncio.py +24 -18
  7. omlish/c3.py +1 -1
  8. omlish/cached.py +1 -2
  9. omlish/collections/__init__.py +4 -1
  10. omlish/collections/cache/impl.py +1 -1
  11. omlish/collections/indexed.py +1 -1
  12. omlish/collections/utils.py +38 -6
  13. omlish/configs/__init__.py +5 -0
  14. omlish/configs/classes.py +53 -0
  15. omlish/configs/dotenv.py +586 -0
  16. omlish/configs/props.py +589 -49
  17. omlish/dataclasses/impl/api.py +1 -1
  18. omlish/dataclasses/impl/as_.py +1 -1
  19. omlish/dataclasses/impl/fields.py +1 -0
  20. omlish/dataclasses/impl/init.py +1 -1
  21. omlish/dataclasses/impl/main.py +1 -0
  22. omlish/dataclasses/impl/metaclass.py +6 -1
  23. omlish/dataclasses/impl/order.py +1 -1
  24. omlish/dataclasses/impl/reflect.py +15 -2
  25. omlish/defs.py +1 -1
  26. omlish/diag/procfs.py +29 -1
  27. omlish/diag/procstats.py +32 -0
  28. omlish/diag/replserver/console.py +3 -3
  29. omlish/diag/replserver/server.py +6 -5
  30. omlish/diag/threads.py +86 -0
  31. omlish/docker.py +19 -0
  32. omlish/fnpairs.py +26 -18
  33. omlish/graphs/dags.py +113 -0
  34. omlish/graphs/domination.py +268 -0
  35. omlish/graphs/trees.py +2 -2
  36. omlish/http/__init__.py +25 -0
  37. omlish/http/asgi.py +131 -0
  38. omlish/http/consts.py +31 -4
  39. omlish/http/cookies.py +194 -0
  40. omlish/http/dates.py +70 -0
  41. omlish/http/encodings.py +6 -0
  42. omlish/http/json.py +273 -0
  43. omlish/http/sessions.py +197 -0
  44. omlish/inject/__init__.py +8 -2
  45. omlish/inject/bindings.py +3 -3
  46. omlish/inject/exceptions.py +3 -3
  47. omlish/inject/impl/elements.py +33 -24
  48. omlish/inject/impl/injector.py +1 -0
  49. omlish/inject/impl/multis.py +74 -0
  50. omlish/inject/impl/providers.py +19 -39
  51. omlish/inject/{proxy.py → impl/proxy.py} +2 -2
  52. omlish/inject/impl/scopes.py +1 -0
  53. omlish/inject/injector.py +1 -0
  54. omlish/inject/keys.py +3 -9
  55. omlish/inject/multis.py +70 -0
  56. omlish/inject/providers.py +23 -23
  57. omlish/inject/scopes.py +7 -3
  58. omlish/inject/types.py +0 -8
  59. omlish/iterators.py +13 -0
  60. omlish/json.py +2 -1
  61. omlish/lang/__init__.py +4 -0
  62. omlish/lang/classes/restrict.py +1 -1
  63. omlish/lang/classes/virtual.py +2 -2
  64. omlish/lang/contextmanagers.py +64 -0
  65. omlish/lang/datetimes.py +6 -5
  66. omlish/lang/functions.py +10 -0
  67. omlish/lang/imports.py +11 -2
  68. omlish/lang/typing.py +1 -0
  69. omlish/logs/utils.py +1 -1
  70. omlish/marshal/datetimes.py +1 -1
  71. omlish/reflect.py +8 -2
  72. omlish/sync.py +70 -0
  73. omlish/term.py +6 -1
  74. omlish/testing/pytest/__init__.py +5 -0
  75. omlish/testing/pytest/helpers.py +0 -24
  76. omlish/testing/pytest/inject/harness.py +1 -1
  77. omlish/testing/pytest/marks.py +48 -0
  78. omlish/testing/pytest/plugins/__init__.py +2 -0
  79. omlish/testing/pytest/plugins/managermarks.py +60 -0
  80. omlish/testing/testing.py +10 -0
  81. omlish/text/delimit.py +4 -0
  82. {omlish-0.0.0.dev4.dist-info → omlish-0.0.0.dev5.dist-info}/METADATA +1 -1
  83. {omlish-0.0.0.dev4.dist-info → omlish-0.0.0.dev5.dist-info}/RECORD +86 -69
  84. {omlish-0.0.0.dev4.dist-info → omlish-0.0.0.dev5.dist-info}/WHEEL +1 -1
  85. {omlish-0.0.0.dev4.dist-info → omlish-0.0.0.dev5.dist-info}/LICENSE +0 -0
  86. {omlish-0.0.0.dev4.dist-info → omlish-0.0.0.dev5.dist-info}/top_level.txt +0 -0
@@ -10,6 +10,8 @@ Multi's + Scopes:
10
10
 
11
11
  Element Types:
12
12
  - Binding
13
+ - SetBinding
14
+ - MapBinding
13
15
  - Eager
14
16
  - Overrides
15
17
  - Expose
@@ -27,16 +29,22 @@ from ..elements import Element
27
29
  from ..elements import Elements
28
30
  from ..exceptions import DuplicateKeyError
29
31
  from ..keys import Key
32
+ from ..multis import MapBinding
33
+ from ..multis import MapProvider
34
+ from ..multis import SetBinding
35
+ from ..multis import SetProvider
30
36
  from ..overrides import Overrides
31
37
  from ..private import Expose
32
38
  from ..private import Private
33
39
  from ..scopes import ScopeBinding
34
40
  from ..types import Scope
35
41
  from .bindings import BindingImpl
36
- from .providers import MultiProviderImpl
42
+ from .multis import make_multi_provider_impl
43
+ from .providers import ProviderImpl
37
44
  from .providers import make_provider_impl
38
45
  from .scopes import make_scope_impl
39
46
 
47
+
40
48
  if ta.TYPE_CHECKING:
41
49
  from . import private as private_
42
50
  else:
@@ -92,10 +100,13 @@ class ElementCollection(lang.Final):
92
100
  pi = self._get_private_info(e)
93
101
  self._build_raw_element_multimap(pi.owner_elements(), out)
94
102
 
103
+ elif isinstance(e, (SetBinding, MapBinding)):
104
+ add(e.multi_key, e)
105
+
95
106
  elif isinstance(e, Overrides):
96
107
  ovr = self._build_raw_element_multimap(e.ovr)
97
108
  src = self._build_raw_element_multimap(e.src)
98
- for k, b in src.items():
109
+ for k, b in src.items(): # FIXME: merge None keys?
99
110
  try:
100
111
  bs = ovr[k]
101
112
  except KeyError:
@@ -117,36 +128,34 @@ class ElementCollection(lang.Final):
117
128
 
118
129
  ##
119
130
 
120
- def _make_binding_impls(self, e: Element) -> ta.Iterable[BindingImpl]:
121
- if isinstance(e, Binding):
122
- p = make_provider_impl(e.provider)
123
- return (BindingImpl(e.key, p, e.scope, e),)
124
-
125
- elif isinstance(e, (Eager, Expose)):
126
- return ()
127
-
128
- else:
129
- raise TypeError(e)
130
-
131
131
  def _build_binding_impl_map(self, em: ta.Mapping[Key | None, ta.Sequence[Element]]) -> dict[Key, BindingImpl]:
132
132
  pm: dict[Key, BindingImpl] = {}
133
- mm: dict[Key, list[BindingImpl]] = {}
134
133
  for k, es in em.items():
135
134
  if k is None:
136
135
  continue
137
136
 
138
- bis = [bi for e in es for bi in self._make_binding_impls(e)]
139
- if k.multi:
140
- mm.setdefault(k, []).extend(bis)
141
- else:
142
- if len(bis) > 1:
137
+ es_by_ty = col.multi_map_by(type, es)
138
+
139
+ es_by_ty.pop(Eager, None)
140
+ es_by_ty.pop(Expose, None)
141
+
142
+ if (bs := es_by_ty.pop(Binding, None)):
143
+ if len(bs) > 1:
143
144
  raise DuplicateKeyError(k)
144
- [pm[k]] = bis
145
145
 
146
- if mm:
147
- for k, aps in mm.items():
148
- mp = MultiProviderImpl([ap.provider for ap in aps])
149
- pm[k] = BindingImpl(k, mp) # FIXME: SCOPING
146
+ b: Binding = check.isinstance(check.single(bs), Binding)
147
+ p: ProviderImpl
148
+
149
+ if isinstance(b.provider, (SetProvider, MapProvider)):
150
+ p = make_multi_provider_impl(b.provider, es_by_ty)
151
+
152
+ else:
153
+ p = make_provider_impl(b.provider)
154
+
155
+ pm[k] = BindingImpl(b.key, p, b.scope, b)
156
+
157
+ if es_by_ty:
158
+ raise TypeError(set(es_by_ty))
150
159
 
151
160
  return pm
152
161
 
@@ -9,6 +9,7 @@ TODO:
9
9
  - ** eagers in any scope, on scope init/open
10
10
  - injection listeners
11
11
  - unions - raise on ambiguous - usecase: sql.AsyncEngineLike
12
+ - multiple live request scopes on single injector - use private injectors?
12
13
  """
13
14
  import contextlib
14
15
  import typing as ta
@@ -0,0 +1,74 @@
1
+ import typing as ta
2
+
3
+ from ... import dataclasses as dc
4
+ from ... import lang
5
+ from ..elements import Element
6
+ from ..injector import Injector
7
+ from ..multis import MapBinding
8
+ from ..multis import MapProvider
9
+ from ..multis import SetBinding
10
+ from ..multis import SetProvider
11
+ from ..providers import LinkProvider
12
+ from ..providers import Provider
13
+ from .providers import LinkProviderImpl
14
+ from .providers import ProviderImpl
15
+
16
+
17
+ @dc.dataclass(frozen=True, eq=False)
18
+ class SetProviderImpl(ProviderImpl, lang.Final):
19
+ ps: ta.Sequence[ProviderImpl]
20
+
21
+ @property
22
+ def providers(self) -> ta.Iterable[Provider]:
23
+ for p in self.ps:
24
+ yield from p.providers
25
+
26
+ def provide(self, injector: Injector) -> ta.Any:
27
+ rv = set()
28
+ for ep in self.ps:
29
+ o = ep.provide(injector)
30
+ rv.add(o)
31
+ return rv
32
+
33
+
34
+ @dc.dataclass(frozen=True, eq=False)
35
+ class MapProviderImpl(ProviderImpl, lang.Final):
36
+ class Entry(ta.NamedTuple):
37
+ k: ta.Any
38
+ v: ProviderImpl
39
+
40
+ es: ta.Sequence[Entry]
41
+
42
+ @property
43
+ def providers(self) -> ta.Iterable[Provider]:
44
+ for e in self.es:
45
+ yield from e.v.providers
46
+
47
+ def provide(self, injector: Injector) -> ta.Any:
48
+ rv = {}
49
+ for e in self.es:
50
+ o = e.v.provide(injector)
51
+ rv[e.k] = o
52
+ return rv
53
+
54
+
55
+ def make_multi_provider_impl(p: Provider, es_by_ty: ta.MutableMapping[type, list[Element]]) -> ProviderImpl:
56
+ if isinstance(p, SetProvider):
57
+ sbs: ta.Iterable[SetBinding] = es_by_ty.pop(SetBinding, ()) # type: ignore
58
+ return SetProviderImpl([
59
+ LinkProviderImpl(LinkProvider(sb.dst))
60
+ for sb in sbs
61
+ ])
62
+
63
+ elif isinstance(p, MapProvider):
64
+ mbs: ta.Iterable[MapBinding] = es_by_ty.pop(MapBinding, ()) # type: ignore
65
+ return MapProviderImpl([
66
+ MapProviderImpl.Entry(
67
+ mb.map_key,
68
+ LinkProviderImpl(LinkProvider(mb.dst)),
69
+ )
70
+ for mb in mbs
71
+ ])
72
+
73
+ else:
74
+ raise TypeError(p)
@@ -5,10 +5,9 @@ TODO:
5
5
  import abc
6
6
  import typing as ta
7
7
 
8
- from .. import Cls
9
- from ... import check
10
8
  from ... import dataclasses as dc
11
9
  from ... import lang
10
+ from ... import reflect as rfl
12
11
  from ..injector import Injector
13
12
  from ..inspect import KwargsTarget
14
13
  from ..providers import ConstProvider
@@ -19,6 +18,9 @@ from ..providers import Provider
19
18
  from .inspect import build_kwargs_target
20
19
 
21
20
 
21
+ ##
22
+
23
+
22
24
  class ProviderImpl(lang.Abstract):
23
25
  @property
24
26
  @abc.abstractmethod
@@ -30,14 +32,20 @@ class ProviderImpl(lang.Abstract):
30
32
  raise NotImplementedError
31
33
 
32
34
 
35
+ ##
36
+
37
+
33
38
  @dc.dataclass(frozen=True, eq=False)
34
39
  class InternalProvider(Provider):
35
40
  impl: ProviderImpl
36
41
 
37
- def provided_cls(self) -> Cls | None:
42
+ def provided_ty(self) -> rfl.Type | None:
38
43
  raise TypeError
39
44
 
40
45
 
46
+ ##
47
+
48
+
41
49
  @dc.dataclass(frozen=True, eq=False)
42
50
  class CallableProviderImpl(ProviderImpl, lang.Final):
43
51
  p: FnProvider | CtorProvider
@@ -51,6 +59,9 @@ class CallableProviderImpl(ProviderImpl, lang.Final):
51
59
  return injector.inject(self.kt)
52
60
 
53
61
 
62
+ ##
63
+
64
+
54
65
  @dc.dataclass(frozen=True, eq=False)
55
66
  class ConstProviderImpl(ProviderImpl, lang.Final):
56
67
  p: ConstProvider
@@ -63,6 +74,9 @@ class ConstProviderImpl(ProviderImpl, lang.Final):
63
74
  return self.p.v
64
75
 
65
76
 
77
+ ##
78
+
79
+
66
80
  @dc.dataclass(frozen=True, eq=False)
67
81
  class LinkProviderImpl(ProviderImpl, lang.Final):
68
82
  p: LinkProvider
@@ -75,46 +89,12 @@ class LinkProviderImpl(ProviderImpl, lang.Final):
75
89
  return injector.provide(self.p.k)
76
90
 
77
91
 
78
- _ILLEGAL_MULTI_TYPES = (str, bytes, bytearray)
79
-
80
-
81
- def _unnest_multi_providers(ps: ta.Iterable[ProviderImpl]) -> ta.Sequence[ProviderImpl]:
82
- lst = []
83
-
84
- def rec(o):
85
- if isinstance(o, MultiProviderImpl):
86
- for c in o.ps:
87
- rec(c)
88
- else:
89
- lst.append(check.isinstance(o, ProviderImpl))
90
-
91
- for o in ps:
92
- rec(o)
93
- return tuple(lst)
94
-
95
-
96
- @dc.dataclass(frozen=True, eq=False)
97
- class MultiProviderImpl(ProviderImpl, lang.Final):
98
- ps: ta.Sequence[ProviderImpl] = dc.xfield(coerce=_unnest_multi_providers)
99
-
100
- @property
101
- def providers(self) -> ta.Iterable[Provider]:
102
- for p in self.ps:
103
- yield from p.providers
104
-
105
- def provide(self, injector: Injector) -> ta.Any:
106
- rv = []
107
- for ep in self.ps:
108
- o = ep.provide(injector)
109
- if isinstance(o, _ILLEGAL_MULTI_TYPES):
110
- raise TypeError(o)
111
- rv.extend(o)
112
- return rv
92
+ ##
113
93
 
114
94
 
115
95
  PROVIDER_IMPLS_BY_PROVIDER: dict[type[Provider], ta.Callable[..., ProviderImpl]] = {
116
96
  FnProvider: lambda p: CallableProviderImpl(p, build_kwargs_target(p.fn)),
117
- CtorProvider: lambda p: CallableProviderImpl(p, build_kwargs_target(p.cls)),
97
+ CtorProvider: lambda p: CallableProviderImpl(p, build_kwargs_target(p.ty)),
118
98
  ConstProvider: ConstProviderImpl,
119
99
  LinkProvider: LinkProviderImpl,
120
100
  InternalProvider: lambda p: p.impl,
@@ -1,7 +1,7 @@
1
1
  import typing as ta
2
2
 
3
- from .. import lang
4
- from .. import check
3
+ from ... import check
4
+ from ... import lang
5
5
 
6
6
 
7
7
  @lang.cached_function
@@ -25,6 +25,7 @@ from .bindings import BindingImpl
25
25
  from .providers import PROVIDER_IMPLS_BY_PROVIDER
26
26
  from .providers import ProviderImpl
27
27
 
28
+
28
29
  if ta.TYPE_CHECKING:
29
30
  from . import injector as injector_
30
31
  else:
omlish/inject/injector.py CHANGED
@@ -6,6 +6,7 @@ from .elements import Elements
6
6
  from .inspect import KwargsTarget
7
7
  from .keys import Key
8
8
 
9
+
9
10
  _impl = lang.proxy_import('.impl.injector', __package__)
10
11
 
11
12
 
omlish/inject/keys.py CHANGED
@@ -3,6 +3,7 @@ import typing as ta
3
3
 
4
4
  from .. import dataclasses as dc
5
5
  from .. import lang
6
+ from .. import reflect as rfl
6
7
 
7
8
 
8
9
  T = ta.TypeVar('T')
@@ -14,9 +15,8 @@ T = ta.TypeVar('T')
14
15
  @dc.dataclass(frozen=True)
15
16
  @dc.extra_params(cache_hash=True)
16
17
  class Key(lang.Final, ta.Generic[T]):
17
- cls: type[T] | ta.NewType
18
+ ty: rfl.Type = dc.xfield(coerce=rfl.type_)
18
19
  tag: ta.Any = dc.field(default=None, kw_only=True)
19
- multi: bool = dc.field(default=False, kw_only=True)
20
20
 
21
21
 
22
22
  ##
@@ -27,17 +27,11 @@ def as_key(o: ta.Any) -> Key:
27
27
  raise TypeError(o)
28
28
  if isinstance(o, Key):
29
29
  return o
30
- if isinstance(o, (type, ta.NewType)): # noqa
31
- return Key(o)
32
- raise TypeError(o)
30
+ return Key(rfl.type_(o))
33
31
 
34
32
 
35
33
  ##
36
34
 
37
35
 
38
- def multi(o: ta.Any) -> Key:
39
- return dc.replace(as_key(o), multi=True)
40
-
41
-
42
36
  def tag(o: ta.Any, t: ta.Any) -> Key:
43
37
  return dc.replace(as_key(o), tag=t)
@@ -0,0 +1,70 @@
1
+ """
2
+ TODO:
3
+ - scopes
4
+ """
5
+ import collections.abc
6
+ import typing as ta
7
+
8
+ from .. import dataclasses as dc
9
+ from .. import lang
10
+ from .. import reflect as rfl
11
+ from .bindings import Binding
12
+ from .elements import Element
13
+ from .keys import Key
14
+ from .keys import as_key
15
+ from .providers import Provider
16
+
17
+
18
+ ##
19
+
20
+
21
+ def _check_set_multi_key(mk: Key) -> bool:
22
+ return rfl.get_concrete_type(mk.ty) is collections.abc.Set
23
+
24
+
25
+ @dc.dataclass(frozen=True)
26
+ @dc.extra_params(cache_hash=True)
27
+ class SetBinding(Element, lang.Final):
28
+ multi_key: Key = dc.xfield(check=_check_set_multi_key)
29
+ dst: Key = dc.xfield()
30
+
31
+
32
+ @dc.dataclass(frozen=True, eq=False)
33
+ class SetProvider(Provider):
34
+ multi_key: Key = dc.xfield(check=_check_set_multi_key)
35
+
36
+ def provided_ty(self) -> rfl.Type | None:
37
+ return self.multi_key.ty
38
+
39
+
40
+ def bind_set_provider(multi_key: ta.Any) -> Element:
41
+ multi_key = as_key(multi_key)
42
+ return Binding(multi_key, SetProvider(multi_key))
43
+
44
+
45
+ ##
46
+
47
+
48
+ def _check_map_multi_key(mk: Key) -> bool:
49
+ return rfl.get_concrete_type(mk.ty) is collections.abc.Mapping
50
+
51
+
52
+ @dc.dataclass(frozen=True)
53
+ @dc.extra_params(cache_hash=True)
54
+ class MapBinding(Element, lang.Final):
55
+ multi_key: Key = dc.xfield(check=_check_map_multi_key)
56
+ map_key: ta.Any = dc.xfield(())
57
+ dst: Key = dc.xfield(())
58
+
59
+
60
+ @dc.dataclass(frozen=True, eq=False)
61
+ class MapProvider(Provider):
62
+ multi_key: Key = dc.xfield(check=_check_map_multi_key)
63
+
64
+ def provided_ty(self) -> rfl.Type | None:
65
+ return self.multi_key.ty
66
+
67
+
68
+ def bind_map_provider(multi_key: ta.Any) -> Element:
69
+ multi_key = as_key(multi_key)
70
+ return Binding(multi_key, MapProvider(multi_key))
@@ -4,12 +4,12 @@ import typing as ta
4
4
  from .. import check
5
5
  from .. import dataclasses as dc
6
6
  from .. import lang
7
+ from .. import reflect as rfl
7
8
  from .elements import Element
8
9
  from .elements import Elements
9
10
  from .impl.inspect import signature
10
11
  from .keys import Key
11
12
  from .keys import as_key
12
- from .types import Cls
13
13
 
14
14
 
15
15
  class _Missing(lang.NotInstantiable):
@@ -21,7 +21,7 @@ class _Missing(lang.NotInstantiable):
21
21
 
22
22
  class Provider(lang.Abstract):
23
23
  @abc.abstractmethod
24
- def provided_cls(self) -> Cls | None:
24
+ def provided_ty(self) -> rfl.Type | None:
25
25
  raise NotImplementedError
26
26
 
27
27
 
@@ -47,19 +47,19 @@ def as_provider(o: ta.Any) -> Provider:
47
47
  @dc.dataclass(frozen=True, eq=False)
48
48
  class FnProvider(Provider):
49
49
  fn: ta.Any
50
- cls: Cls | None = None
50
+ ty: rfl.Type | None = None
51
51
 
52
- def provided_cls(self) -> Cls | None:
53
- return self.cls
52
+ def provided_ty(self) -> rfl.Type | None:
53
+ return self.ty
54
54
 
55
55
 
56
- def fn(fn: ta.Any, cls: Cls | None = _Missing) -> Provider:
56
+ def fn(fn: ta.Any, ty: rfl.Type | None = _Missing) -> Provider:
57
57
  check.not_isinstance(fn, type)
58
58
  check.callable(fn)
59
- if cls is _Missing:
59
+ if ty is _Missing:
60
60
  sig = signature(fn)
61
- cls = check.isinstance(sig.return_annotation, type)
62
- return FnProvider(fn, cls)
61
+ ty = check.isinstance(sig.return_annotation, type)
62
+ return FnProvider(fn, ty)
63
63
 
64
64
 
65
65
  ##
@@ -67,15 +67,15 @@ def fn(fn: ta.Any, cls: Cls | None = _Missing) -> Provider:
67
67
 
68
68
  @dc.dataclass(frozen=True, eq=False)
69
69
  class CtorProvider(Provider):
70
- cls: type
70
+ ty: type
71
71
 
72
- def provided_cls(self) -> Cls:
73
- return self.cls
72
+ def provided_ty(self) -> type:
73
+ return self.ty
74
74
 
75
75
 
76
- def ctor(cls: type) -> Provider:
77
- check.isinstance(cls, type)
78
- return CtorProvider(cls)
76
+ def ctor(ty: type) -> Provider:
77
+ check.isinstance(ty, type)
78
+ return CtorProvider(ty)
79
79
 
80
80
 
81
81
  ##
@@ -84,16 +84,16 @@ def ctor(cls: type) -> Provider:
84
84
  @dc.dataclass(frozen=True, eq=False)
85
85
  class ConstProvider(Provider):
86
86
  v: ta.Any
87
- cls: Cls | None = None
87
+ ty: rfl.Type | None = None
88
88
 
89
- def provided_cls(self) -> Cls | None:
90
- return self.cls
89
+ def provided_ty(self) -> rfl.Type | None:
90
+ return self.ty
91
91
 
92
92
 
93
- def const(v: ta.Any, cls: Cls | None = _Missing) -> Provider:
94
- if cls is _Missing:
95
- cls = type(v)
96
- return ConstProvider(v, cls)
93
+ def const(v: ta.Any, ty: rfl.Type | None = _Missing) -> Provider:
94
+ if ty is _Missing:
95
+ ty = type(v)
96
+ return ConstProvider(v, ty)
97
97
 
98
98
 
99
99
  ##
@@ -103,7 +103,7 @@ def const(v: ta.Any, cls: Cls | None = _Missing) -> Provider:
103
103
  class LinkProvider(Provider):
104
104
  k: Key
105
105
 
106
- def provided_cls(self) -> Cls | None:
106
+ def provided_ty(self) -> rfl.Type | None:
107
107
  return None
108
108
 
109
109
 
omlish/inject/scopes.py CHANGED
@@ -5,21 +5,25 @@ import typing as ta
5
5
  from .. import check
6
6
  from .. import dataclasses as dc
7
7
  from .. import lang
8
+ from .. import reflect as rfl
8
9
  from .bindings import Binding
9
10
  from .bindings import as_binding
10
11
  from .elements import Element
11
12
  from .keys import Key
12
13
  from .keys import as_key
13
14
  from .providers import Provider
14
- from .types import Cls
15
15
  from .types import Scope
16
16
 
17
+
17
18
  if ta.TYPE_CHECKING:
18
19
  from . import injector as injector_
19
20
  else:
20
21
  injector_ = lang.proxy_import('.injector', __package__)
21
22
 
22
23
 
24
+ ##
25
+
26
+
23
27
  @dc.dataclass(frozen=True)
24
28
  @dc.extra_params(cache_hash=True)
25
29
  class ScopeBinding(Element, lang.Final):
@@ -65,8 +69,8 @@ class ScopeSeededProvider(Provider):
65
69
  ss: SeededScope = dc.xfield(coerce=check.of_isinstance(SeededScope))
66
70
  key: Key = dc.xfield(coerce=check.of_isinstance(Key))
67
71
 
68
- def provided_cls(self) -> Cls | None:
69
- return self.key.cls
72
+ def provided_ty(self) -> rfl.Type | None:
73
+ return self.key.ty
70
74
 
71
75
 
72
76
  def bind_scope_seed(ss: SeededScope, k: ta.Any) -> Element:
omlish/inject/types.py CHANGED
@@ -1,17 +1,9 @@
1
- import typing as ta
2
-
3
1
  from .. import lang
4
2
 
5
3
 
6
4
  ##
7
5
 
8
6
 
9
- Cls = type | ta.NewType
10
-
11
-
12
- ##
13
-
14
-
15
7
  class Scope(lang.Abstract):
16
8
  def __repr__(self) -> str:
17
9
  return type(self).__name__
omlish/iterators.py CHANGED
@@ -218,3 +218,16 @@ def expand_indexed_pairs(
218
218
  if idx < width_:
219
219
  result[idx] = value
220
220
  return result
221
+
222
+
223
+ ##
224
+ # https://docs.python.org/3/library/itertools.html#itertools-recipes
225
+
226
+
227
+ def sliding_window(it: ta.Iterable[T], n: int) -> ta.Iterator[tuple[T, ...]]:
228
+ # sliding_window('ABCDEFG', 4) -> ABCD BCDE CDEF DEFG
229
+ iterator = iter(it)
230
+ window = collections.deque(itertools.islice(iterator, n - 1), maxlen=n)
231
+ for x in iterator:
232
+ window.append(x)
233
+ yield tuple(window)
omlish/json.py CHANGED
@@ -127,6 +127,7 @@ import typing as ta
127
127
 
128
128
  from . import lang
129
129
 
130
+
130
131
  if ta.TYPE_CHECKING:
131
132
  import orjson as _orjson
132
133
  import ujson as _ujson
@@ -165,7 +166,7 @@ dumps_pretty: ta.Callable[..., str] = functools.partial(dumps, **PRETTY_KWARGS)
165
166
  COMPACT_SEPARATORS = (',', ':')
166
167
 
167
168
  COMPACT_KWARGS: ta.Mapping[str, ta.Any] = dict(
168
- indent=0,
169
+ indent=None,
169
170
  separators=COMPACT_SEPARATORS,
170
171
  )
171
172
 
omlish/lang/__init__.py CHANGED
@@ -46,7 +46,9 @@ from .cmp import ( # noqa
46
46
  )
47
47
 
48
48
  from .contextmanagers import ( # noqa
49
+ AsyncContextManager,
49
50
  ContextManaged,
51
+ ContextManager,
50
52
  ContextWrapped,
51
53
  DefaultLockable,
52
54
  ExitStacked,
@@ -90,6 +92,7 @@ from .exceptions import ( # noqa
90
92
  from .functions import ( # noqa
91
93
  Args,
92
94
  VoidError,
95
+ as_async,
93
96
  constant,
94
97
  finally_,
95
98
  identity,
@@ -108,6 +111,7 @@ from .functions import ( # noqa
108
111
  )
109
112
 
110
113
  from .imports import ( # noqa
114
+ can_import,
111
115
  import_all,
112
116
  import_module,
113
117
  import_module_attr,
@@ -89,7 +89,7 @@ class PackageSealed:
89
89
  class NotInstantiable(Abstract):
90
90
  __slots__ = ()
91
91
 
92
- def __new__(cls, *args, **kwargs):
92
+ def __new__(cls, *args, **kwargs): # noqa
93
93
  raise TypeError
94
94
 
95
95
 
@@ -3,8 +3,8 @@ import types
3
3
  import typing as ta
4
4
 
5
5
  from .abstract import make_abstract
6
- from .restrict import NotInstantiable
7
6
  from .restrict import Final
7
+ from .restrict import NotInstantiable
8
8
 
9
9
 
10
10
  T = ta.TypeVar('T')
@@ -122,7 +122,7 @@ class Callable(NotInstantiable, Final, ta.Generic[T]):
122
122
 
123
123
  @classmethod
124
124
  def __subclasscheck__(cls, subclass: type) -> bool:
125
- if not hasattr(subclass, '__call__'):
125
+ if not hasattr(subclass, '__call__'): # noqa
126
126
  return False
127
127
  call = subclass.__call__
128
128
  if isinstance(call, types.MethodWrapperType) and call.__self__ is subclass: