omlish 0.0.0.dev469__py3-none-any.whl → 0.0.0.dev471__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.
- omlish/__about__.py +2 -2
- omlish/http/all.py +27 -7
- omlish/http/clients/asyncs.py +8 -8
- omlish/http/clients/middleware.py +6 -3
- omlish/http/clients/sync.py +8 -8
- omlish/http/clients/syncasync.py +43 -0
- omlish/inject/__init__.py +4 -0
- omlish/inject/elements.py +17 -0
- omlish/inject/impl/elements.py +17 -2
- omlish/inject/impl/injector.py +17 -19
- omlish/inject/impl/inspect.py +7 -1
- omlish/inject/impl/maysync.py +3 -4
- omlish/inject/impl/sync.py +3 -4
- omlish/inject/injector.py +31 -2
- omlish/inject/maysync.py +2 -4
- omlish/inject/sync.py +5 -4
- omlish/lang/imports/proxy.py +10 -1
- omlish/term/pager.py +235 -0
- omlish/term/terminfo.py +935 -0
- omlish/term/termstate.py +67 -0
- {omlish-0.0.0.dev469.dist-info → omlish-0.0.0.dev471.dist-info}/METADATA +1 -1
- {omlish-0.0.0.dev469.dist-info → omlish-0.0.0.dev471.dist-info}/RECORD +27 -23
- /omlish/inject/impl/{providers2.py → providersmap.py} +0 -0
- {omlish-0.0.0.dev469.dist-info → omlish-0.0.0.dev471.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev469.dist-info → omlish-0.0.0.dev471.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev469.dist-info → omlish-0.0.0.dev471.dist-info}/licenses/LICENSE +0 -0
- {omlish-0.0.0.dev469.dist-info → omlish-0.0.0.dev471.dist-info}/top_level.txt +0 -0
omlish/__about__.py
CHANGED
omlish/http/all.py
CHANGED
|
@@ -7,16 +7,15 @@ with _lang.auto_proxy_init(globals()):
|
|
|
7
7
|
from .clients.asyncs import ( # noqa
|
|
8
8
|
AsyncStreamHttpResponse,
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
async_close_http_client_response,
|
|
11
|
+
async_closing_http_client_response,
|
|
12
|
+
async_read_http_client_response,
|
|
13
13
|
|
|
14
14
|
AsyncHttpClient,
|
|
15
15
|
)
|
|
16
16
|
|
|
17
17
|
from .clients.base import ( # noqa
|
|
18
18
|
DEFAULT_ENCODING,
|
|
19
|
-
|
|
20
19
|
is_success_status,
|
|
21
20
|
|
|
22
21
|
HttpRequest,
|
|
@@ -24,8 +23,12 @@ with _lang.auto_proxy_init(globals()):
|
|
|
24
23
|
BaseHttpResponse,
|
|
25
24
|
HttpResponse,
|
|
26
25
|
|
|
26
|
+
HttpClientContext,
|
|
27
|
+
|
|
27
28
|
HttpClientError,
|
|
28
29
|
HttpStatusError,
|
|
30
|
+
|
|
31
|
+
BaseHttpClient,
|
|
29
32
|
)
|
|
30
33
|
|
|
31
34
|
from .clients.default import ( # noqa
|
|
@@ -42,18 +45,35 @@ with _lang.auto_proxy_init(globals()):
|
|
|
42
45
|
|
|
43
46
|
from .clients.httpx import ( # noqa
|
|
44
47
|
HttpxHttpClient,
|
|
48
|
+
|
|
49
|
+
HttpxAsyncHttpClient,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
from .clients.middleware import ( # noqa
|
|
53
|
+
HttpClientMiddleware,
|
|
54
|
+
AbstractMiddlewareHttpClient,
|
|
55
|
+
|
|
56
|
+
MiddlewareHttpClient,
|
|
57
|
+
MiddlewareAsyncHttpClient,
|
|
58
|
+
|
|
59
|
+
TooManyRedirectsHttpClientError,
|
|
60
|
+
RedirectHandlingHttpClientMiddleware,
|
|
45
61
|
)
|
|
46
62
|
|
|
47
63
|
from .clients.sync import ( # noqa
|
|
48
64
|
StreamHttpResponse,
|
|
49
65
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
66
|
+
close_http_client_response,
|
|
67
|
+
closing_http_client_response,
|
|
68
|
+
read_http_client_response,
|
|
53
69
|
|
|
54
70
|
HttpClient,
|
|
55
71
|
)
|
|
56
72
|
|
|
73
|
+
from .clients.syncasync import ( # noqa
|
|
74
|
+
SyncAsyncHttpClient,
|
|
75
|
+
)
|
|
76
|
+
|
|
57
77
|
from .clients.urllib import ( # noqa
|
|
58
78
|
UrllibHttpClient,
|
|
59
79
|
)
|
omlish/http/clients/asyncs.py
CHANGED
|
@@ -57,13 +57,13 @@ class AsyncStreamHttpResponse(BaseHttpResponse):
|
|
|
57
57
|
|
|
58
58
|
async def close(self) -> None:
|
|
59
59
|
if (c := self._closer) is not None:
|
|
60
|
-
await c()
|
|
60
|
+
await c() # noqa
|
|
61
61
|
|
|
62
62
|
|
|
63
63
|
#
|
|
64
64
|
|
|
65
65
|
|
|
66
|
-
async def
|
|
66
|
+
async def async_close_http_client_response(resp: BaseHttpResponse) -> None:
|
|
67
67
|
if isinstance(resp, HttpResponse):
|
|
68
68
|
pass
|
|
69
69
|
|
|
@@ -75,7 +75,7 @@ async def async_close_response(resp: BaseHttpResponse) -> None:
|
|
|
75
75
|
|
|
76
76
|
|
|
77
77
|
@contextlib.asynccontextmanager
|
|
78
|
-
async def
|
|
78
|
+
async def async_closing_http_client_response(resp: BaseHttpResponseT) -> ta.AsyncGenerator[BaseHttpResponseT, None]:
|
|
79
79
|
if isinstance(resp, HttpResponse):
|
|
80
80
|
yield resp
|
|
81
81
|
return
|
|
@@ -90,7 +90,7 @@ async def async_closing_response(resp: BaseHttpResponseT) -> ta.AsyncGenerator[B
|
|
|
90
90
|
raise TypeError(resp)
|
|
91
91
|
|
|
92
92
|
|
|
93
|
-
async def
|
|
93
|
+
async def async_read_http_client_response(resp: BaseHttpResponse) -> HttpResponse:
|
|
94
94
|
if isinstance(resp, HttpResponse):
|
|
95
95
|
return resp
|
|
96
96
|
|
|
@@ -121,12 +121,12 @@ class AsyncHttpClient(BaseHttpClient, Abstract):
|
|
|
121
121
|
context: ta.Optional[HttpClientContext] = None,
|
|
122
122
|
check: bool = False,
|
|
123
123
|
) -> HttpResponse:
|
|
124
|
-
async with
|
|
124
|
+
async with async_closing_http_client_response(await self.stream_request(
|
|
125
125
|
req,
|
|
126
126
|
context=context,
|
|
127
127
|
check=check,
|
|
128
128
|
)) as resp:
|
|
129
|
-
return await
|
|
129
|
+
return await async_read_http_client_response(resp)
|
|
130
130
|
|
|
131
131
|
async def stream_request(
|
|
132
132
|
self,
|
|
@@ -146,10 +146,10 @@ class AsyncHttpClient(BaseHttpClient, Abstract):
|
|
|
146
146
|
cause = resp.underlying
|
|
147
147
|
else:
|
|
148
148
|
cause = None
|
|
149
|
-
raise HttpStatusError(await
|
|
149
|
+
raise HttpStatusError(await async_read_http_client_response(resp)) from cause # noqa
|
|
150
150
|
|
|
151
151
|
except Exception:
|
|
152
|
-
await
|
|
152
|
+
await async_close_http_client_response(resp)
|
|
153
153
|
raise
|
|
154
154
|
|
|
155
155
|
return resp
|
|
@@ -23,7 +23,7 @@ from .base import HttpClientError
|
|
|
23
23
|
from .base import HttpRequest
|
|
24
24
|
from .sync import HttpClient
|
|
25
25
|
from .sync import StreamHttpResponse
|
|
26
|
-
from .sync import
|
|
26
|
+
from .sync import close_http_client_response
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
BaseHttpClientT = ta.TypeVar('BaseHttpClientT', bound=BaseHttpClient)
|
|
@@ -84,6 +84,9 @@ class AbstractMiddlewareHttpClient(Abstract, ta.Generic[BaseHttpClientT]):
|
|
|
84
84
|
return resp
|
|
85
85
|
|
|
86
86
|
|
|
87
|
+
#
|
|
88
|
+
|
|
89
|
+
|
|
87
90
|
class MiddlewareHttpClient(AbstractMiddlewareHttpClient[HttpClient], HttpClient):
|
|
88
91
|
def _stream_request(self, ctx: HttpClientContext, req: HttpRequest) -> StreamHttpResponse:
|
|
89
92
|
while True:
|
|
@@ -95,7 +98,7 @@ class MiddlewareHttpClient(AbstractMiddlewareHttpClient[HttpClient], HttpClient)
|
|
|
95
98
|
out = self._process_response(ctx, req, resp)
|
|
96
99
|
|
|
97
100
|
if isinstance(out, HttpRequest):
|
|
98
|
-
|
|
101
|
+
close_http_client_response(resp)
|
|
99
102
|
req = out
|
|
100
103
|
continue
|
|
101
104
|
|
|
@@ -106,7 +109,7 @@ class MiddlewareHttpClient(AbstractMiddlewareHttpClient[HttpClient], HttpClient)
|
|
|
106
109
|
raise TypeError(out) # noqa
|
|
107
110
|
|
|
108
111
|
except Exception:
|
|
109
|
-
|
|
112
|
+
close_http_client_response(resp)
|
|
110
113
|
raise
|
|
111
114
|
|
|
112
115
|
raise RuntimeError
|
omlish/http/clients/sync.py
CHANGED
|
@@ -57,13 +57,13 @@ class StreamHttpResponse(BaseHttpResponse):
|
|
|
57
57
|
|
|
58
58
|
def close(self) -> None:
|
|
59
59
|
if (c := self._closer) is not None:
|
|
60
|
-
c()
|
|
60
|
+
c() # noqa
|
|
61
61
|
|
|
62
62
|
|
|
63
63
|
#
|
|
64
64
|
|
|
65
65
|
|
|
66
|
-
def
|
|
66
|
+
def close_http_client_response(resp: BaseHttpResponse) -> None:
|
|
67
67
|
if isinstance(resp, HttpResponse):
|
|
68
68
|
pass
|
|
69
69
|
|
|
@@ -75,7 +75,7 @@ def close_response(resp: BaseHttpResponse) -> None:
|
|
|
75
75
|
|
|
76
76
|
|
|
77
77
|
@contextlib.contextmanager
|
|
78
|
-
def
|
|
78
|
+
def closing_http_client_response(resp: BaseHttpResponseT) -> ta.Iterator[BaseHttpResponseT]:
|
|
79
79
|
if isinstance(resp, HttpResponse):
|
|
80
80
|
yield resp
|
|
81
81
|
return
|
|
@@ -88,7 +88,7 @@ def closing_response(resp: BaseHttpResponseT) -> ta.Iterator[BaseHttpResponseT]:
|
|
|
88
88
|
raise TypeError(resp)
|
|
89
89
|
|
|
90
90
|
|
|
91
|
-
def
|
|
91
|
+
def read_http_client_response(resp: BaseHttpResponse) -> HttpResponse:
|
|
92
92
|
if isinstance(resp, HttpResponse):
|
|
93
93
|
return resp
|
|
94
94
|
|
|
@@ -119,12 +119,12 @@ class HttpClient(BaseHttpClient, Abstract):
|
|
|
119
119
|
context: ta.Optional[HttpClientContext] = None,
|
|
120
120
|
check: bool = False,
|
|
121
121
|
) -> HttpResponse:
|
|
122
|
-
with
|
|
122
|
+
with closing_http_client_response(self.stream_request(
|
|
123
123
|
req,
|
|
124
124
|
context=context,
|
|
125
125
|
check=check,
|
|
126
126
|
)) as resp:
|
|
127
|
-
return
|
|
127
|
+
return read_http_client_response(resp)
|
|
128
128
|
|
|
129
129
|
def stream_request(
|
|
130
130
|
self,
|
|
@@ -144,10 +144,10 @@ class HttpClient(BaseHttpClient, Abstract):
|
|
|
144
144
|
cause = resp.underlying
|
|
145
145
|
else:
|
|
146
146
|
cause = None
|
|
147
|
-
raise HttpStatusError(
|
|
147
|
+
raise HttpStatusError(read_http_client_response(resp)) from cause # noqa
|
|
148
148
|
|
|
149
149
|
except Exception:
|
|
150
|
-
|
|
150
|
+
close_http_client_response(resp)
|
|
151
151
|
raise
|
|
152
152
|
|
|
153
153
|
return resp
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# ruff: noqa: UP043 UP045
|
|
2
|
+
# @omlish-lite
|
|
3
|
+
import dataclasses as dc
|
|
4
|
+
|
|
5
|
+
from .asyncs import AsyncHttpClient
|
|
6
|
+
from .asyncs import AsyncStreamHttpResponse
|
|
7
|
+
from .base import HttpClientContext
|
|
8
|
+
from .base import HttpRequest
|
|
9
|
+
from .sync import HttpClient
|
|
10
|
+
from .sync import StreamHttpResponse
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
##
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class SyncAsyncHttpClient(AsyncHttpClient):
|
|
17
|
+
def __init__(self, client: HttpClient) -> None:
|
|
18
|
+
super().__init__()
|
|
19
|
+
|
|
20
|
+
self._client = client
|
|
21
|
+
|
|
22
|
+
@dc.dataclass(frozen=True)
|
|
23
|
+
class _StreamAdapter:
|
|
24
|
+
ul: StreamHttpResponse
|
|
25
|
+
|
|
26
|
+
async def read1(self, /, n: int = -1) -> bytes:
|
|
27
|
+
return self.ul.stream.read1(n)
|
|
28
|
+
|
|
29
|
+
async def close(self) -> None:
|
|
30
|
+
self.ul.close()
|
|
31
|
+
|
|
32
|
+
async def _stream_request(self, ctx: HttpClientContext, req: HttpRequest) -> AsyncStreamHttpResponse:
|
|
33
|
+
resp = self._client.stream_request(req, context=ctx)
|
|
34
|
+
return AsyncStreamHttpResponse(
|
|
35
|
+
status=resp.status,
|
|
36
|
+
headers=resp.headers,
|
|
37
|
+
request=req,
|
|
38
|
+
underlying=resp,
|
|
39
|
+
**(dict( # type: ignore
|
|
40
|
+
stream=(adapter := self._StreamAdapter(resp)),
|
|
41
|
+
_closer=adapter.close,
|
|
42
|
+
) if resp.has_data else {}),
|
|
43
|
+
)
|
omlish/inject/__init__.py
CHANGED
omlish/inject/elements.py
CHANGED
|
@@ -6,6 +6,12 @@ from .. import lang
|
|
|
6
6
|
from .impl.origins import HasOriginsImpl
|
|
7
7
|
|
|
8
8
|
|
|
9
|
+
if ta.TYPE_CHECKING:
|
|
10
|
+
from .impl import elements as _elements
|
|
11
|
+
else:
|
|
12
|
+
_elements = lang.proxy_import('.impl.elements', __package__)
|
|
13
|
+
|
|
14
|
+
|
|
9
15
|
##
|
|
10
16
|
|
|
11
17
|
|
|
@@ -74,3 +80,14 @@ def iter_elements(*args: Elemental) -> ta.Iterator[Element]:
|
|
|
74
80
|
yield from a
|
|
75
81
|
else:
|
|
76
82
|
raise TypeError(a)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
##
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class CollectedElements(lang.PackageSealed, lang.Abstract):
|
|
89
|
+
pass
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def collect_elements(es: Elements | CollectedElements) -> CollectedElements:
|
|
93
|
+
return _elements.collect_elements(es)
|
omlish/inject/impl/elements.py
CHANGED
|
@@ -27,6 +27,7 @@ from ... import collections as col
|
|
|
27
27
|
from ... import lang
|
|
28
28
|
from ..bindings import Binding
|
|
29
29
|
from ..eagers import Eager
|
|
30
|
+
from ..elements import CollectedElements
|
|
30
31
|
from ..elements import Element
|
|
31
32
|
from ..elements import Elements
|
|
32
33
|
from ..errors import ConflictingKeyError
|
|
@@ -47,7 +48,7 @@ from .multis import make_multi_provider_impl
|
|
|
47
48
|
from .origins import Origins
|
|
48
49
|
from .origins import set_origins
|
|
49
50
|
from .providers import ProviderImpl
|
|
50
|
-
from .
|
|
51
|
+
from .providersmap import make_provider_impl
|
|
51
52
|
from .scopes import make_scope_impl
|
|
52
53
|
|
|
53
54
|
|
|
@@ -80,7 +81,7 @@ _NON_BINDING_ELEMENT_TYPES: tuple[type[Element], ...] = (
|
|
|
80
81
|
)
|
|
81
82
|
|
|
82
83
|
|
|
83
|
-
class ElementCollection(lang.Final):
|
|
84
|
+
class ElementCollection(CollectedElements, lang.Final):
|
|
84
85
|
def __init__(self, es: Elements) -> None:
|
|
85
86
|
super().__init__()
|
|
86
87
|
|
|
@@ -208,6 +209,10 @@ class ElementCollection(lang.Final):
|
|
|
208
209
|
|
|
209
210
|
##
|
|
210
211
|
|
|
212
|
+
@lang.cached_function
|
|
213
|
+
def scope_binding_scopes(self) -> ta.Sequence[Scope]:
|
|
214
|
+
return [sb.scope for sb in self.elements_of_type(ScopeBinding)]
|
|
215
|
+
|
|
211
216
|
@lang.cached_function
|
|
212
217
|
def eager_keys_by_scope(self) -> ta.Mapping[Scope, ta.Sequence[Key]]:
|
|
213
218
|
bim = self.binding_impl_map()
|
|
@@ -216,3 +221,13 @@ class ElementCollection(lang.Final):
|
|
|
216
221
|
bi = bim[e.key]
|
|
217
222
|
ret.setdefault(bi.scope, []).append(e.key)
|
|
218
223
|
return ret
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
##
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def collect_elements(es: Elements | CollectedElements) -> ElementCollection:
|
|
230
|
+
if isinstance(es, CollectedElements):
|
|
231
|
+
return check.isinstance(es, ElementCollection)
|
|
232
|
+
else:
|
|
233
|
+
return ElementCollection(es)
|
omlish/inject/impl/injector.py
CHANGED
|
@@ -2,14 +2,12 @@
|
|
|
2
2
|
TODO:
|
|
3
3
|
- ** can currently bind in a child/private scope shadowing an external parent binding **
|
|
4
4
|
- better source tracking
|
|
5
|
-
- cache/export ElementCollections lol
|
|
6
5
|
- scope bindings, auto in root
|
|
7
6
|
- injector-internal / blacklisted bindings (Injector itself, default scopes) without rebuilding ElementCollection
|
|
8
7
|
- config - proxies, impl select, etc
|
|
9
8
|
- config is probably shared with ElementCollection... but not 'bound', must be shared everywhere
|
|
10
9
|
- InjectorRoot object?
|
|
11
10
|
- ** eagers in any scope, on scope init/open
|
|
12
|
-
- injection listeners
|
|
13
11
|
- unions - raise on ambiguous - usecase: sql.AsyncEngineLike
|
|
14
12
|
- multiple live request scopes on single injector - use private injectors?
|
|
15
13
|
- more listeners - UnboundKeyListener
|
|
@@ -24,7 +22,7 @@ import weakref
|
|
|
24
22
|
from ... import check
|
|
25
23
|
from ... import lang
|
|
26
24
|
from ...logs import all as logs
|
|
27
|
-
from ..elements import
|
|
25
|
+
from ..elements import CollectedElements
|
|
28
26
|
from ..errors import CyclicDependencyError
|
|
29
27
|
from ..errors import UnboundKeyError
|
|
30
28
|
from ..injector import AsyncInjector
|
|
@@ -33,7 +31,6 @@ from ..keys import Key
|
|
|
33
31
|
from ..keys import as_key
|
|
34
32
|
from ..listeners import ProvisionListener
|
|
35
33
|
from ..listeners import ProvisionListenerBinding
|
|
36
|
-
from ..scopes import ScopeBinding
|
|
37
34
|
from ..scopes import Singleton
|
|
38
35
|
from ..scopes import ThreadScope
|
|
39
36
|
from ..types import Scope
|
|
@@ -61,14 +58,12 @@ DEFAULT_SCOPES: list[Scope] = [
|
|
|
61
58
|
class AsyncInjectorImpl(AsyncInjector, lang.Final):
|
|
62
59
|
def __init__(
|
|
63
60
|
self,
|
|
64
|
-
ec:
|
|
61
|
+
ec: CollectedElements,
|
|
65
62
|
p: ta.Optional['AsyncInjectorImpl'] = None,
|
|
66
63
|
*,
|
|
67
64
|
internal_consts: dict[Key, ta.Any] | None = None,
|
|
68
65
|
) -> None:
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
self._ec = check.isinstance(ec, ElementCollection)
|
|
66
|
+
self._ec = (ec := check.isinstance(ec, ElementCollection))
|
|
72
67
|
self._p: AsyncInjectorImpl | None = check.isinstance(p, (AsyncInjectorImpl, None))
|
|
73
68
|
|
|
74
69
|
self._internal_consts: dict[Key, ta.Any] = {
|
|
@@ -77,28 +72,31 @@ class AsyncInjectorImpl(AsyncInjector, lang.Final):
|
|
|
77
72
|
}
|
|
78
73
|
|
|
79
74
|
self._bim = ec.binding_impl_map()
|
|
75
|
+
|
|
80
76
|
self._ekbs = ec.eager_keys_by_scope()
|
|
77
|
+
|
|
81
78
|
self._pls: tuple[ProvisionListener, ...] = tuple(
|
|
82
79
|
b.listener # type: ignore[attr-defined]
|
|
83
80
|
for b in itertools.chain(
|
|
84
81
|
ec.elements_of_type(ProvisionListenerBinding),
|
|
85
|
-
|
|
82
|
+
p._pls if p is not None else (), # noqa
|
|
86
83
|
)
|
|
87
84
|
)
|
|
88
85
|
|
|
89
|
-
self._cs: weakref.WeakSet[AsyncInjectorImpl] | None = None # noqa
|
|
90
86
|
self._root: AsyncInjectorImpl = p._root if p is not None else self # noqa
|
|
91
87
|
|
|
92
|
-
self.__cur_req: AsyncInjectorImpl._Request | None = None
|
|
93
|
-
|
|
94
|
-
ss = [
|
|
95
|
-
*DEFAULT_SCOPES,
|
|
96
|
-
*[sb.scope for sb in ec.elements_of_type(ScopeBinding)],
|
|
97
|
-
]
|
|
98
88
|
self._scopes: dict[Scope, ScopeImpl] = {
|
|
99
|
-
s: make_scope_impl(s)
|
|
89
|
+
s: make_scope_impl(s)
|
|
90
|
+
for s in itertools.chain(
|
|
91
|
+
DEFAULT_SCOPES,
|
|
92
|
+
ec.scope_binding_scopes(),
|
|
93
|
+
)
|
|
100
94
|
}
|
|
101
95
|
|
|
96
|
+
_cs: weakref.WeakSet['AsyncInjectorImpl'] | None = None # noqa
|
|
97
|
+
|
|
98
|
+
__cur_req: ta.Optional['AsyncInjectorImpl._Request'] = None
|
|
99
|
+
|
|
102
100
|
#
|
|
103
101
|
|
|
104
102
|
_has_run_init: bool = False
|
|
@@ -259,7 +257,7 @@ class AsyncInjectorImpl(AsyncInjector, lang.Final):
|
|
|
259
257
|
return obj(**kws)
|
|
260
258
|
|
|
261
259
|
|
|
262
|
-
async def create_async_injector(
|
|
263
|
-
i = AsyncInjectorImpl(
|
|
260
|
+
async def create_async_injector(ce: CollectedElements) -> AsyncInjector:
|
|
261
|
+
i = AsyncInjectorImpl(ce)
|
|
264
262
|
await i._init() # noqa
|
|
265
263
|
return i
|
omlish/inject/impl/inspect.py
CHANGED
|
@@ -75,6 +75,7 @@ def build_kwargs_target(
|
|
|
75
75
|
skip_args: int = 0,
|
|
76
76
|
skip_kwargs: ta.Iterable[str] | None = None,
|
|
77
77
|
raw_optional: bool = False,
|
|
78
|
+
non_strict: bool = False,
|
|
78
79
|
) -> KwargsTarget:
|
|
79
80
|
if isinstance(obj, KwargsTarget):
|
|
80
81
|
return obj
|
|
@@ -93,11 +94,15 @@ def build_kwargs_target(
|
|
|
93
94
|
continue
|
|
94
95
|
|
|
95
96
|
if p.annotation is inspect.Signature.empty:
|
|
97
|
+
if non_strict:
|
|
98
|
+
continue
|
|
96
99
|
if p.default is not inspect.Parameter.empty:
|
|
97
100
|
raise KeyError(f'{obj}, {p.name}')
|
|
98
101
|
continue
|
|
99
102
|
|
|
100
103
|
if p.kind not in (inspect.Parameter.POSITIONAL_OR_KEYWORD, inspect.Parameter.KEYWORD_ONLY):
|
|
104
|
+
if non_strict:
|
|
105
|
+
continue
|
|
101
106
|
raise TypeError(sig)
|
|
102
107
|
|
|
103
108
|
ann = p.annotation
|
|
@@ -122,7 +127,8 @@ def build_kwargs_target(
|
|
|
122
127
|
k = dc.replace(k, tag=pt)
|
|
123
128
|
|
|
124
129
|
if k in seen:
|
|
125
|
-
|
|
130
|
+
if not non_strict:
|
|
131
|
+
raise ConflictingKeyError(k)
|
|
126
132
|
seen.add(k)
|
|
127
133
|
|
|
128
134
|
kws.append(Kwarg(
|
omlish/inject/impl/maysync.py
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import typing as ta
|
|
2
2
|
|
|
3
3
|
from ... import lang
|
|
4
|
-
from ..elements import
|
|
4
|
+
from ..elements import CollectedElements
|
|
5
5
|
from ..injector import AsyncInjector
|
|
6
6
|
from ..inspect import KwargsTarget
|
|
7
7
|
from ..keys import Key
|
|
8
8
|
from ..maysync import MaysyncInjector
|
|
9
9
|
from ..sync import Injector
|
|
10
|
-
from .elements import ElementCollection
|
|
11
10
|
from .injector import AsyncInjectorImpl
|
|
12
11
|
|
|
13
12
|
|
|
@@ -30,10 +29,10 @@ class MaysyncInjectorImpl(MaysyncInjector, lang.Final):
|
|
|
30
29
|
return lang.run_maysync(self._ai.inject(obj))
|
|
31
30
|
|
|
32
31
|
|
|
33
|
-
def create_maysync_injector(
|
|
32
|
+
def create_maysync_injector(ce: CollectedElements) -> MaysyncInjector:
|
|
34
33
|
si = MaysyncInjectorImpl()
|
|
35
34
|
ai = AsyncInjectorImpl(
|
|
36
|
-
|
|
35
|
+
ce,
|
|
37
36
|
internal_consts={
|
|
38
37
|
Key(MaysyncInjector): si,
|
|
39
38
|
Key(Injector): si,
|
omlish/inject/impl/sync.py
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import typing as ta
|
|
2
2
|
|
|
3
3
|
from ... import lang
|
|
4
|
-
from ..elements import
|
|
4
|
+
from ..elements import CollectedElements
|
|
5
5
|
from ..injector import AsyncInjector
|
|
6
6
|
from ..inspect import KwargsTarget
|
|
7
7
|
from ..keys import Key
|
|
8
8
|
from ..sync import Injector
|
|
9
|
-
from .elements import ElementCollection
|
|
10
9
|
from .injector import AsyncInjectorImpl
|
|
11
10
|
|
|
12
11
|
|
|
@@ -29,10 +28,10 @@ class InjectorImpl(Injector, lang.Final):
|
|
|
29
28
|
return lang.sync_await(self._ai.inject(obj))
|
|
30
29
|
|
|
31
30
|
|
|
32
|
-
def create_injector(
|
|
31
|
+
def create_injector(ce: CollectedElements) -> Injector:
|
|
33
32
|
si = InjectorImpl()
|
|
34
33
|
ai = AsyncInjectorImpl(
|
|
35
|
-
|
|
34
|
+
ce,
|
|
36
35
|
internal_consts={
|
|
37
36
|
Key(Injector): si,
|
|
38
37
|
},
|
omlish/inject/injector.py
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import abc
|
|
2
2
|
import typing as ta
|
|
3
3
|
|
|
4
|
+
from .. import check
|
|
4
5
|
from .. import lang
|
|
6
|
+
from .elements import CollectedElements
|
|
5
7
|
from .elements import Elemental
|
|
6
8
|
from .elements import as_elements
|
|
9
|
+
from .elements import collect_elements
|
|
7
10
|
from .inspect import KwargsTarget
|
|
8
11
|
from .keys import Key
|
|
9
12
|
|
|
@@ -44,5 +47,31 @@ class AsyncInjector(lang.Abstract):
|
|
|
44
47
|
return self.provide(target)
|
|
45
48
|
|
|
46
49
|
|
|
47
|
-
|
|
48
|
-
|
|
50
|
+
##
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@ta.final
|
|
54
|
+
class _InjectorCreator(ta.Generic[T]):
|
|
55
|
+
def __init__(self, fac: ta.Callable[[CollectedElements], T]) -> None:
|
|
56
|
+
self._fac = fac
|
|
57
|
+
|
|
58
|
+
@ta.overload
|
|
59
|
+
def __call__(self, es: CollectedElements, /) -> T: ...
|
|
60
|
+
|
|
61
|
+
@ta.overload
|
|
62
|
+
def __call__(self, *es: Elemental) -> T: ...
|
|
63
|
+
|
|
64
|
+
def __call__(self, arg0, *argv):
|
|
65
|
+
ce: CollectedElements
|
|
66
|
+
if isinstance(arg0, CollectedElements):
|
|
67
|
+
check.arg(not argv)
|
|
68
|
+
ce = arg0
|
|
69
|
+
else:
|
|
70
|
+
ce = collect_elements(as_elements(arg0, *argv))
|
|
71
|
+
return self._fac(ce)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
##
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
create_async_injector = _InjectorCreator[ta.Awaitable[AsyncInjector]](lambda ce: _injector.create_async_injector(ce))
|
omlish/inject/maysync.py
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import typing as ta
|
|
2
2
|
|
|
3
3
|
from .. import lang
|
|
4
|
-
from .
|
|
5
|
-
from .elements import as_elements
|
|
4
|
+
from .injector import _InjectorCreator
|
|
6
5
|
from .sync import Injector
|
|
7
6
|
|
|
8
7
|
|
|
@@ -25,5 +24,4 @@ class MaysyncInjector(Injector, lang.Abstract):
|
|
|
25
24
|
##
|
|
26
25
|
|
|
27
26
|
|
|
28
|
-
|
|
29
|
-
return _maysync.create_maysync_injector(as_elements(*args))
|
|
27
|
+
create_maysync_injector = _InjectorCreator[MaysyncInjector](lambda ce: _maysync.create_maysync_injector(ce))
|
omlish/inject/sync.py
CHANGED
|
@@ -2,8 +2,7 @@ import abc
|
|
|
2
2
|
import typing as ta
|
|
3
3
|
|
|
4
4
|
from .. import lang
|
|
5
|
-
from .
|
|
6
|
-
from .elements import as_elements
|
|
5
|
+
from .injector import _InjectorCreator
|
|
7
6
|
from .inspect import KwargsTarget
|
|
8
7
|
from .keys import Key
|
|
9
8
|
|
|
@@ -44,5 +43,7 @@ class Injector(lang.Abstract):
|
|
|
44
43
|
return self.provide(target)
|
|
45
44
|
|
|
46
45
|
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
##
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
create_injector = _InjectorCreator[Injector](lambda ce: _sync.create_injector(ce))
|
omlish/lang/imports/proxy.py
CHANGED
|
@@ -342,6 +342,8 @@ def proxy_import(
|
|
|
342
342
|
spec: str,
|
|
343
343
|
package: str | None = None,
|
|
344
344
|
extras: ta.Iterable[str] | None = None,
|
|
345
|
+
*,
|
|
346
|
+
no_cache: bool = False,
|
|
345
347
|
) -> types.ModuleType:
|
|
346
348
|
"""'Legacy' proxy import mechanism."""
|
|
347
349
|
|
|
@@ -352,12 +354,19 @@ def proxy_import(
|
|
|
352
354
|
|
|
353
355
|
def __getattr__(att): # noqa
|
|
354
356
|
nonlocal omod
|
|
357
|
+
|
|
355
358
|
if omod is None:
|
|
356
359
|
omod = importlib.import_module(spec, package=package)
|
|
357
360
|
if extras:
|
|
358
361
|
for x in extras:
|
|
359
362
|
importlib.import_module(f'{spec}.{x}', package=package)
|
|
360
|
-
|
|
363
|
+
|
|
364
|
+
v = getattr(omod, att)
|
|
365
|
+
|
|
366
|
+
if not no_cache:
|
|
367
|
+
setattr(lmod, att, v)
|
|
368
|
+
|
|
369
|
+
return v
|
|
361
370
|
|
|
362
371
|
lmod = types.ModuleType(spec)
|
|
363
372
|
lmod.__getattr__ = __getattr__ # type: ignore[method-assign]
|