omlish 0.0.0.dev447__py3-none-any.whl → 0.0.0.dev493__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.
- omlish/.omlish-manifests.json +12 -0
- omlish/README.md +199 -0
- omlish/__about__.py +21 -16
- omlish/argparse/all.py +17 -9
- omlish/argparse/cli.py +16 -3
- omlish/argparse/utils.py +21 -0
- omlish/asyncs/asyncio/rlock.py +110 -0
- omlish/asyncs/asyncio/sync.py +43 -0
- omlish/asyncs/asyncio/utils.py +2 -0
- omlish/asyncs/sync.py +25 -0
- omlish/bootstrap/_marshal.py +1 -1
- omlish/bootstrap/diag.py +12 -21
- omlish/bootstrap/main.py +2 -5
- omlish/bootstrap/sys.py +27 -28
- omlish/cexts/__init__.py +0 -0
- omlish/cexts/include/omlish/omlish.hh +1 -0
- omlish/collections/__init__.py +13 -1
- omlish/collections/attrregistry.py +210 -0
- omlish/collections/cache/impl.py +1 -0
- omlish/collections/identity.py +1 -0
- omlish/collections/mappings.py +28 -0
- omlish/collections/trie.py +5 -1
- omlish/collections/utils.py +77 -0
- omlish/concurrent/all.py +2 -1
- omlish/concurrent/futures.py +25 -0
- omlish/concurrent/threadlets.py +1 -1
- omlish/daemons/reparent.py +2 -3
- omlish/daemons/spawning.py +2 -3
- omlish/dataclasses/__init__.py +2 -0
- omlish/dataclasses/impl/api/classes/decorator.py +3 -0
- omlish/dataclasses/impl/api/classes/make.py +3 -0
- omlish/dataclasses/impl/concerns/repr.py +15 -2
- omlish/dataclasses/impl/configs.py +97 -37
- omlish/dataclasses/impl/generation/compilation.py +21 -19
- omlish/dataclasses/impl/generation/globals.py +1 -0
- omlish/dataclasses/impl/generation/ops.py +1 -0
- omlish/dataclasses/impl/generation/plans.py +2 -17
- omlish/dataclasses/impl/generation/processor.py +106 -25
- omlish/dataclasses/impl/processing/base.py +8 -0
- omlish/dataclasses/impl/processing/driving.py +19 -7
- omlish/dataclasses/specs.py +1 -0
- omlish/dataclasses/tools/modifiers.py +5 -0
- omlish/diag/_pycharm/runhack.py +1 -1
- omlish/diag/cmds/__init__.py +0 -0
- omlish/diag/{lslocks.py → cmds/lslocks.py} +6 -6
- omlish/diag/{lsof.py → cmds/lsof.py} +6 -6
- omlish/diag/{ps.py → cmds/ps.py} +6 -6
- omlish/diag/pycharm.py +16 -2
- omlish/diag/pydevd.py +58 -40
- omlish/diag/replserver/console.py +1 -1
- omlish/dispatch/__init__.py +18 -12
- omlish/dispatch/methods.py +50 -140
- omlish/dom/rendering.py +1 -1
- omlish/formats/dotenv.py +1 -1
- omlish/formats/json/stream/__init__.py +13 -0
- omlish/funcs/guard.py +225 -0
- omlish/graphs/dot/rendering.py +1 -1
- omlish/http/all.py +44 -4
- omlish/http/clients/asyncs.py +33 -27
- omlish/http/clients/base.py +17 -1
- omlish/http/clients/coro/__init__.py +0 -0
- omlish/http/clients/coro/sync.py +171 -0
- omlish/http/clients/default.py +208 -29
- omlish/http/clients/executor.py +56 -0
- omlish/http/clients/httpx.py +72 -11
- omlish/http/clients/middleware.py +181 -0
- omlish/http/clients/sync.py +33 -27
- omlish/http/clients/syncasync.py +49 -0
- omlish/http/clients/urllib.py +6 -3
- omlish/http/coro/client/connection.py +15 -6
- omlish/http/coro/io.py +2 -0
- omlish/http/flasky/__init__.py +40 -0
- omlish/http/flasky/_compat.py +2 -0
- omlish/http/flasky/api.py +82 -0
- omlish/http/flasky/app.py +203 -0
- omlish/http/flasky/cvs.py +59 -0
- omlish/http/flasky/requests.py +20 -0
- omlish/http/flasky/responses.py +23 -0
- omlish/http/flasky/routes.py +23 -0
- omlish/http/flasky/types.py +15 -0
- omlish/http/urls.py +67 -0
- omlish/inject/__init__.py +57 -29
- omlish/inject/_dataclasses.py +5148 -0
- omlish/inject/binder.py +11 -52
- omlish/inject/eagers.py +2 -0
- omlish/inject/elements.py +27 -0
- omlish/inject/helpers/__init__.py +0 -0
- omlish/inject/{utils.py → helpers/constfn.py} +3 -3
- omlish/inject/{tags.py → helpers/id.py} +2 -2
- omlish/inject/helpers/late.py +76 -0
- omlish/inject/{managed.py → helpers/managed.py} +10 -10
- omlish/inject/helpers/multis.py +143 -0
- omlish/inject/helpers/wrappers.py +54 -0
- omlish/inject/impl/elements.py +54 -21
- omlish/inject/impl/injector.py +29 -25
- omlish/inject/impl/inspect.py +10 -1
- omlish/inject/impl/maysync.py +3 -4
- omlish/inject/impl/multis.py +3 -0
- omlish/inject/impl/sync.py +3 -4
- omlish/inject/injector.py +31 -2
- omlish/inject/inspect.py +35 -0
- omlish/inject/maysync.py +2 -4
- omlish/inject/multis.py +8 -0
- omlish/inject/overrides.py +3 -3
- omlish/inject/privates.py +6 -0
- omlish/inject/providers.py +3 -2
- omlish/inject/sync.py +5 -4
- omlish/io/buffers.py +118 -0
- omlish/io/readers.py +29 -0
- omlish/iterators/transforms.py +2 -2
- omlish/lang/__init__.py +180 -97
- omlish/lang/_asyncs.cc +186 -0
- omlish/lang/asyncs.py +17 -0
- omlish/lang/casing.py +11 -0
- omlish/lang/contextmanagers.py +28 -4
- omlish/lang/functions.py +31 -22
- omlish/lang/imports/_capture.cc +11 -9
- omlish/lang/imports/capture.py +363 -170
- omlish/lang/imports/proxy.py +455 -152
- omlish/lang/lazyglobals.py +22 -9
- omlish/lang/params.py +17 -0
- omlish/lang/recursion.py +0 -1
- omlish/lang/sequences.py +124 -0
- omlish/lifecycles/README.md +30 -0
- omlish/lifecycles/__init__.py +87 -13
- omlish/lifecycles/_dataclasses.py +1388 -0
- omlish/lifecycles/base.py +178 -64
- omlish/lifecycles/contextmanagers.py +113 -4
- omlish/lifecycles/controller.py +150 -87
- omlish/lifecycles/injection.py +143 -0
- omlish/lifecycles/listeners.py +56 -0
- omlish/lifecycles/managed.py +142 -0
- omlish/lifecycles/manager.py +218 -93
- omlish/lifecycles/states.py +2 -0
- omlish/lifecycles/transitions.py +3 -0
- omlish/lifecycles/unwrap.py +57 -0
- omlish/lite/abstract.py +54 -24
- omlish/lite/asyncs.py +2 -2
- omlish/lite/attrops.py +2 -0
- omlish/lite/contextmanagers.py +4 -4
- omlish/lite/dataclasses.py +44 -0
- omlish/lite/maybes.py +8 -0
- omlish/lite/maysync.py +1 -5
- omlish/lite/pycharm.py +1 -1
- omlish/lite/typing.py +24 -0
- omlish/logs/_amalg.py +1 -1
- omlish/logs/all.py +25 -11
- omlish/logs/asyncs.py +73 -0
- omlish/logs/base.py +101 -12
- omlish/logs/contexts.py +4 -1
- omlish/logs/lists.py +125 -0
- omlish/logs/modules.py +19 -1
- omlish/logs/std/loggers.py +6 -1
- omlish/logs/std/noisy.py +11 -9
- omlish/logs/{standard.py → std/standard.py} +3 -4
- omlish/logs/utils.py +17 -2
- omlish/manifests/loading.py +2 -1
- omlish/marshal/__init__.py +33 -13
- omlish/marshal/_dataclasses.py +2774 -0
- omlish/marshal/base/configs.py +12 -0
- omlish/marshal/base/contexts.py +36 -21
- omlish/marshal/base/funcs.py +8 -11
- omlish/marshal/base/options.py +8 -0
- omlish/marshal/base/registries.py +146 -44
- omlish/marshal/base/types.py +40 -16
- omlish/marshal/composite/iterables.py +33 -20
- omlish/marshal/composite/literals.py +20 -18
- omlish/marshal/composite/mappings.py +36 -23
- omlish/marshal/composite/maybes.py +29 -19
- omlish/marshal/composite/newtypes.py +16 -16
- omlish/marshal/composite/optionals.py +14 -14
- omlish/marshal/composite/special.py +15 -15
- omlish/marshal/composite/unions/__init__.py +0 -0
- omlish/marshal/composite/unions/literals.py +93 -0
- omlish/marshal/composite/unions/primitives.py +103 -0
- omlish/marshal/factories/invalidate.py +18 -68
- omlish/marshal/factories/method.py +26 -0
- omlish/marshal/factories/moduleimport/factories.py +22 -65
- omlish/marshal/factories/multi.py +13 -25
- omlish/marshal/factories/recursive.py +42 -56
- omlish/marshal/factories/typecache.py +29 -74
- omlish/marshal/factories/typemap.py +42 -43
- omlish/marshal/objects/dataclasses.py +129 -106
- omlish/marshal/objects/marshal.py +18 -14
- omlish/marshal/objects/namedtuples.py +48 -42
- omlish/marshal/objects/unmarshal.py +19 -15
- omlish/marshal/polymorphism/marshal.py +9 -11
- omlish/marshal/polymorphism/metadata.py +16 -5
- omlish/marshal/polymorphism/standard.py +13 -1
- omlish/marshal/polymorphism/unions.py +15 -105
- omlish/marshal/polymorphism/unmarshal.py +9 -10
- omlish/marshal/singular/enums.py +14 -18
- omlish/marshal/standard.py +10 -6
- omlish/marshal/trivial/any.py +1 -1
- omlish/marshal/trivial/forbidden.py +21 -26
- omlish/metadata.py +23 -1
- omlish/os/forkhooks.py +4 -0
- omlish/os/pidfiles/pinning.py +2 -2
- omlish/reflect/__init__.py +43 -26
- omlish/reflect/ops.py +10 -1
- omlish/reflect/types.py +1 -0
- omlish/secrets/marshal.py +1 -1
- omlish/specs/jmespath/__init__.py +12 -3
- omlish/specs/jmespath/_dataclasses.py +2893 -0
- omlish/specs/jmespath/ast.py +1 -1
- omlish/specs/jsonrpc/__init__.py +13 -0
- omlish/specs/jsonrpc/_marshal.py +32 -23
- omlish/specs/jsonrpc/conns.py +10 -7
- omlish/specs/jsonschema/_marshal.py +1 -1
- omlish/specs/jsonschema/keywords/__init__.py +7 -0
- omlish/specs/jsonschema/keywords/_dataclasses.py +1644 -0
- omlish/specs/openapi/_marshal.py +31 -22
- omlish/sql/__init__.py +24 -5
- omlish/sql/{tabledefs/alchemy.py → alchemy/tabledefs.py} +2 -2
- omlish/sql/api/dbapi.py +1 -1
- omlish/sql/dbapi/__init__.py +15 -0
- omlish/sql/{dbapi.py → dbapi/drivers.py} +2 -2
- omlish/sql/queries/__init__.py +3 -0
- omlish/sql/queries/_marshal.py +2 -2
- omlish/sql/queries/rendering.py +1 -1
- omlish/sql/tabledefs/_marshal.py +1 -1
- omlish/subprocesses/base.py +4 -0
- omlish/subprocesses/editor.py +1 -1
- omlish/sync.py +155 -21
- omlish/term/alt.py +60 -0
- omlish/term/confirm.py +8 -8
- omlish/term/pager.py +235 -0
- omlish/term/terminfo.py +935 -0
- omlish/term/termstate.py +67 -0
- omlish/term/vt100/terminal.py +0 -3
- omlish/testing/pytest/plugins/asyncs/fixtures.py +4 -1
- omlish/testing/pytest/plugins/asyncs/plugin.py +2 -0
- omlish/testing/pytest/plugins/skips.py +2 -1
- omlish/testing/unittest/main.py +3 -3
- omlish/text/docwrap/__init__.py +3 -0
- omlish/text/docwrap/__main__.py +11 -0
- omlish/text/docwrap/api.py +83 -0
- omlish/text/docwrap/cli.py +91 -0
- omlish/text/docwrap/groups.py +84 -0
- omlish/text/docwrap/lists.py +167 -0
- omlish/text/docwrap/parts.py +146 -0
- omlish/text/docwrap/reflowing.py +106 -0
- omlish/text/docwrap/rendering.py +151 -0
- omlish/text/docwrap/utils.py +11 -0
- omlish/text/docwrap/wrapping.py +59 -0
- omlish/text/filecache.py +2 -2
- omlish/text/lorem.py +6 -0
- omlish/text/parts.py +2 -2
- omlish/text/textwrap.py +51 -0
- omlish/typedvalues/marshal.py +85 -59
- omlish/typedvalues/values.py +2 -1
- {omlish-0.0.0.dev447.dist-info → omlish-0.0.0.dev493.dist-info}/METADATA +36 -32
- {omlish-0.0.0.dev447.dist-info → omlish-0.0.0.dev493.dist-info}/RECORD +260 -199
- omlish/dataclasses/impl/generation/mangling.py +0 -18
- omlish/funcs/match.py +0 -227
- omlish/lifecycles/abstract.py +0 -86
- omlish/marshal/factories/match.py +0 -34
- omlish/marshal/factories/simple.py +0 -28
- /omlish/inject/{impl → helpers}/proxy.py +0 -0
- /omlish/inject/impl/{providers2.py → providersmap.py} +0 -0
- /omlish/sql/{abc.py → dbapi/abc.py} +0 -0
- {omlish-0.0.0.dev447.dist-info → omlish-0.0.0.dev493.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev447.dist-info → omlish-0.0.0.dev493.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev447.dist-info → omlish-0.0.0.dev493.dist-info}/licenses/LICENSE +0 -0
- {omlish-0.0.0.dev447.dist-info → omlish-0.0.0.dev493.dist-info}/top_level.txt +0 -0
omlish/dispatch/methods.py
CHANGED
|
@@ -4,13 +4,11 @@ TODO:
|
|
|
4
4
|
- ALT: A.f(super(), ... ? :/
|
|
5
5
|
- classmethod/staticmethod
|
|
6
6
|
"""
|
|
7
|
-
import contextlib
|
|
8
7
|
import functools
|
|
9
8
|
import typing as ta
|
|
10
|
-
import weakref
|
|
11
9
|
|
|
12
10
|
from .. import check
|
|
13
|
-
from .. import
|
|
11
|
+
from .. import collections as col
|
|
14
12
|
from .dispatch import Dispatcher
|
|
15
13
|
from .impls import get_impl_func_cls_set
|
|
16
14
|
|
|
@@ -34,9 +32,8 @@ class Method(ta.Generic[P, R]):
|
|
|
34
32
|
it must be explicitly `@register`'ed itself. This is a feature, allowing for selective de-registration of
|
|
35
33
|
implementations in subclasses via name shadowing.
|
|
36
34
|
|
|
37
|
-
Methods
|
|
38
|
-
|
|
39
|
-
visitors.
|
|
35
|
+
Methods can choose to allow external installation of implementations outside of direct subclasses. This is to be
|
|
36
|
+
used *extremely* rarely - basically only in the rare case of externally extensible type hierarchies with visitors.
|
|
40
37
|
"""
|
|
41
38
|
|
|
42
39
|
def __init__(
|
|
@@ -45,6 +42,7 @@ class Method(ta.Generic[P, R]):
|
|
|
45
42
|
*,
|
|
46
43
|
installable: bool = False,
|
|
47
44
|
requires_override: bool = False,
|
|
45
|
+
instance_cache: bool = False,
|
|
48
46
|
) -> None:
|
|
49
47
|
super().__init__()
|
|
50
48
|
|
|
@@ -53,9 +51,16 @@ class Method(ta.Generic[P, R]):
|
|
|
53
51
|
|
|
54
52
|
self._func = func
|
|
55
53
|
self._installable = installable
|
|
56
|
-
self.
|
|
54
|
+
self._instance_cache = instance_cache
|
|
57
55
|
|
|
58
|
-
self.
|
|
56
|
+
self._registry: col.AttrRegistry[ta.Callable, Method._Entry] = col.AttrRegistry(
|
|
57
|
+
requires_override=requires_override,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
self._cache: col.AttrRegistryCache[ta.Callable, Method._Entry, ta.Callable] = col.AttrRegistryCache(
|
|
61
|
+
self._registry,
|
|
62
|
+
self._prepare,
|
|
63
|
+
)
|
|
59
64
|
|
|
60
65
|
# bpo-45678: special-casing for classmethod/staticmethod in Python <=3.9, as functools.update_wrapper doesn't
|
|
61
66
|
# work properly in singledispatchmethod.__get__ if it is applied to an unbound classmethod/staticmethod
|
|
@@ -68,19 +73,12 @@ class Method(ta.Generic[P, R]):
|
|
|
68
73
|
self._is_abstractmethod = getattr(func, '__isabstractmethod__', False) # noqa
|
|
69
74
|
self.update_wrapper(self)
|
|
70
75
|
|
|
71
|
-
self._dispatch_func_cache: dict[ta.Any, ta.Callable] = {}
|
|
72
|
-
|
|
73
|
-
def dispatch_func_cache_remove(k, self_ref=weakref.ref(self)):
|
|
74
|
-
if (ref_self := self_ref()) is not None:
|
|
75
|
-
cache = ref_self._dispatch_func_cache # noqa
|
|
76
|
-
with contextlib.suppress(KeyError):
|
|
77
|
-
del cache[k]
|
|
78
|
-
|
|
79
|
-
self._dispatch_func_cache_remove = dispatch_func_cache_remove
|
|
80
|
-
|
|
81
76
|
self._owner: type | None = None
|
|
82
77
|
self._name: str | None = None
|
|
83
78
|
|
|
79
|
+
class _Entry:
|
|
80
|
+
cls_set: frozenset[type]
|
|
81
|
+
|
|
84
82
|
def __set_name__(self, owner, name):
|
|
85
83
|
if self._owner is None:
|
|
86
84
|
self._owner = owner
|
|
@@ -102,83 +100,29 @@ class Method(ta.Generic[P, R]):
|
|
|
102
100
|
|
|
103
101
|
def register(self, impl: T, cls_set: frozenset[type] | None = None) -> T:
|
|
104
102
|
check.callable(impl)
|
|
105
|
-
if impl not in self._impls:
|
|
106
|
-
self._impls[impl] = cls_set # type: ignore
|
|
107
|
-
self._dispatch_func_cache.clear()
|
|
108
|
-
|
|
109
|
-
return impl
|
|
110
|
-
|
|
111
|
-
def _is_impl(self, obj: ta.Any) -> bool:
|
|
112
|
-
try:
|
|
113
|
-
hash(obj)
|
|
114
|
-
except TypeError:
|
|
115
|
-
return False
|
|
116
|
-
|
|
117
|
-
return obj in self._impls
|
|
118
103
|
|
|
119
|
-
|
|
120
|
-
if
|
|
121
|
-
|
|
104
|
+
entry = Method._Entry()
|
|
105
|
+
if cls_set is not None:
|
|
106
|
+
entry.cls_set = cls_set
|
|
122
107
|
|
|
123
|
-
|
|
124
|
-
try:
|
|
125
|
-
mro_pos = mro.index(owner_cls)
|
|
126
|
-
except ValueError:
|
|
127
|
-
raise TypeError(f'Owner class {owner_cls} not in mro of instance class {instance_cls}') from None
|
|
108
|
+
self._registry.register(ta.cast(ta.Callable, impl), entry)
|
|
128
109
|
|
|
129
|
-
|
|
130
|
-
for cur_cls in mro[:mro_pos + 1]:
|
|
131
|
-
for att, obj in cur_cls.__dict__.items():
|
|
132
|
-
if att not in mro_dct:
|
|
133
|
-
if not self._is_impl(obj):
|
|
134
|
-
continue
|
|
135
|
-
|
|
136
|
-
try:
|
|
137
|
-
lst = mro_dct[att]
|
|
138
|
-
except KeyError:
|
|
139
|
-
lst = mro_dct[att] = []
|
|
140
|
-
lst.append((cur_cls, obj))
|
|
141
|
-
|
|
142
|
-
#
|
|
110
|
+
return impl
|
|
143
111
|
|
|
112
|
+
def _build_dispatcher(self, collected: ta.Mapping[str, tuple[ta.Callable, _Entry]]) -> Dispatcher[str]:
|
|
144
113
|
disp: Dispatcher[str] = Dispatcher()
|
|
145
114
|
|
|
146
|
-
|
|
147
|
-
for att, lst in mro_dct.items():
|
|
148
|
-
if not lst:
|
|
149
|
-
raise RuntimeError
|
|
150
|
-
_, obj = lst[-1]
|
|
151
|
-
|
|
152
|
-
if len(lst) > 1:
|
|
153
|
-
if self._requires_override and not lang.is_override(obj):
|
|
154
|
-
raise lang.RequiresOverrideError(
|
|
155
|
-
att,
|
|
156
|
-
instance_cls,
|
|
157
|
-
lst[-1][0],
|
|
158
|
-
lst[0][0],
|
|
159
|
-
)
|
|
160
|
-
|
|
161
|
-
if not self._is_impl(obj):
|
|
162
|
-
continue
|
|
163
|
-
|
|
164
|
-
cls_set = self._impls[obj]
|
|
165
|
-
if cls_set is None:
|
|
166
|
-
cls_set = get_impl_func_cls_set(obj, arg_offset=1)
|
|
167
|
-
self._impls[obj] = cls_set
|
|
168
|
-
|
|
115
|
+
for a, (f, e) in collected.items():
|
|
169
116
|
try:
|
|
170
|
-
|
|
171
|
-
except
|
|
172
|
-
|
|
173
|
-
else:
|
|
174
|
-
raise TypeError(f'Duplicate impl: {owner_cls} {instance_cls} {att} {ex_att}')
|
|
175
|
-
seen[obj] = att
|
|
117
|
+
cls_set = e.cls_set
|
|
118
|
+
except AttributeError:
|
|
119
|
+
cls_set = e.cls_set = get_impl_func_cls_set(f, arg_offset=1)
|
|
176
120
|
|
|
177
|
-
disp.register(
|
|
121
|
+
disp.register(a, cls_set)
|
|
178
122
|
|
|
179
123
|
return disp
|
|
180
124
|
|
|
181
|
-
def
|
|
125
|
+
def _build_dispatch_func(self, disp: Dispatcher[str]) -> ta.Callable:
|
|
182
126
|
dispatch = disp.dispatch
|
|
183
127
|
type_ = type
|
|
184
128
|
getattr_ = getattr
|
|
@@ -190,25 +134,16 @@ class Method(ta.Generic[P, R]):
|
|
|
190
134
|
raise TypeError(f'{func_name} requires at least 1 positional argument')
|
|
191
135
|
|
|
192
136
|
if (impl_att := dispatch(type_(args[0]))) is not None:
|
|
193
|
-
|
|
194
|
-
return fn(*args, **kwargs)
|
|
137
|
+
return getattr_(self, impl_att)(*args, **kwargs)
|
|
195
138
|
|
|
196
139
|
return base_func.__get__(self)(*args, **kwargs) # noqa
|
|
197
140
|
|
|
198
141
|
self.update_wrapper(__call__)
|
|
199
142
|
return __call__
|
|
200
143
|
|
|
201
|
-
def
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
return self._dispatch_func_cache[cls_ref]
|
|
205
|
-
except KeyError:
|
|
206
|
-
pass
|
|
207
|
-
del cls_ref
|
|
208
|
-
|
|
209
|
-
att_disp = self.build_attr_dispatcher(instance_cls)
|
|
210
|
-
func = self.build_dispatch_func(att_disp)
|
|
211
|
-
self._dispatch_func_cache[weakref.ref(instance_cls, self._dispatch_func_cache_remove)] = func
|
|
144
|
+
def _prepare(self, instance_cls: type, collected: ta.Mapping[str, tuple[ta.Callable, _Entry]]) -> ta.Callable:
|
|
145
|
+
disp = self._build_dispatcher(collected)
|
|
146
|
+
func = self._build_dispatch_func(disp)
|
|
212
147
|
return func
|
|
213
148
|
|
|
214
149
|
def __get__(self, instance, owner=None):
|
|
@@ -216,16 +151,21 @@ class Method(ta.Generic[P, R]):
|
|
|
216
151
|
# FIXME: classmethod/staticmethod
|
|
217
152
|
return self
|
|
218
153
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
154
|
+
if self._instance_cache:
|
|
155
|
+
try:
|
|
156
|
+
return instance.__dict__[self._name]
|
|
157
|
+
except KeyError:
|
|
158
|
+
pass
|
|
159
|
+
|
|
160
|
+
bound = self._cache.get(type(instance)).__get__(instance, owner) # noqa
|
|
161
|
+
|
|
162
|
+
if self._instance_cache:
|
|
163
|
+
instance.__dict__[self._name] = bound
|
|
164
|
+
|
|
165
|
+
return bound
|
|
225
166
|
|
|
226
167
|
def __call__(self, *args: P.args, **kwargs: P.kwargs) -> R:
|
|
227
168
|
instance, *rest = args
|
|
228
|
-
instance_cls = type(instance)
|
|
229
169
|
|
|
230
170
|
# if instance_cls is super:
|
|
231
171
|
# owner = instance.__self_class__.__mro__[instance.__self_class__.__mro__.index(instance.__thisclass__) + 1]
|
|
@@ -233,55 +173,25 @@ class Method(ta.Generic[P, R]):
|
|
|
233
173
|
# func = self.build_dispatch_func(att_disp)
|
|
234
174
|
# return func.__get__(instance, instance.__thisclass__)(*rest, **kwargs)
|
|
235
175
|
|
|
236
|
-
|
|
237
|
-
func = self._dispatch_func_cache[weakref.ref(instance_cls)]
|
|
238
|
-
except KeyError:
|
|
239
|
-
func = self.get_dispatch_func(instance_cls)
|
|
240
|
-
return func.__get__(instance)(*rest, **kwargs) # noqa
|
|
176
|
+
return self.__get__(instance)(*rest, **kwargs)
|
|
241
177
|
|
|
242
178
|
|
|
243
179
|
##
|
|
244
180
|
|
|
245
181
|
|
|
246
|
-
@ta.overload
|
|
247
|
-
def method(
|
|
248
|
-
func: ta.Callable[P, R],
|
|
249
|
-
/,
|
|
250
|
-
*,
|
|
251
|
-
installable: bool = False,
|
|
252
|
-
requires_override: bool = False,
|
|
253
|
-
) -> Method[P, R]: # noqa
|
|
254
|
-
...
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
@ta.overload
|
|
258
182
|
def method(
|
|
259
|
-
func: None = None,
|
|
260
|
-
/,
|
|
261
183
|
*,
|
|
262
184
|
installable: bool = False,
|
|
263
185
|
requires_override: bool = False,
|
|
186
|
+
instance_cache: bool = False,
|
|
264
187
|
) -> ta.Callable[[ta.Callable[P, R]], Method[P, R]]: # noqa
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
def method(
|
|
269
|
-
func=None,
|
|
270
|
-
/,
|
|
271
|
-
*,
|
|
272
|
-
installable=False,
|
|
273
|
-
requires_override=False,
|
|
274
|
-
):
|
|
275
|
-
kw = dict(
|
|
188
|
+
return functools.partial(
|
|
189
|
+
Method, # type: ignore[arg-type]
|
|
276
190
|
installable=installable,
|
|
277
191
|
requires_override=requires_override,
|
|
192
|
+
instance_cache=instance_cache,
|
|
278
193
|
)
|
|
279
194
|
|
|
280
|
-
if func is None:
|
|
281
|
-
return functools.partial(Method, **kw)
|
|
282
|
-
|
|
283
|
-
return Method(func, **kw)
|
|
284
|
-
|
|
285
195
|
|
|
286
196
|
#
|
|
287
197
|
|
|
@@ -305,7 +215,7 @@ def install_method(
|
|
|
305
215
|
if on is None:
|
|
306
216
|
cls = owner
|
|
307
217
|
else:
|
|
308
|
-
cls = check.issubclass(on, owner)
|
|
218
|
+
cls = check.issubclass(on, owner) # noqa
|
|
309
219
|
|
|
310
220
|
check.arg(not hasattr(cls, a))
|
|
311
221
|
setattr(cls, a, fn)
|
omlish/dom/rendering.py
CHANGED
omlish/formats/dotenv.py
CHANGED
|
@@ -584,7 +584,7 @@ def dotenv_values(
|
|
|
584
584
|
For example, `foo=bar` results in `{"foo": "bar"}` whereas `foo` alone results in
|
|
585
585
|
`{"foo": None}`
|
|
586
586
|
|
|
587
|
-
|
|
587
|
+
Args:
|
|
588
588
|
path: Absolute or relative path to the .env file.
|
|
589
589
|
stream: `StringIO` object with .env content, used if `path` is `None`.
|
|
590
590
|
verbose: Whether to output a warning if the .env file is missing.
|
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
"""
|
|
2
|
+
A generator powered, configurable, mostly fully streaming JSON parser.
|
|
3
|
+
|
|
4
|
+
Regarding the 'streamyness' of the subsystems:
|
|
5
|
+
- Lexing only buffers for string and number literals.
|
|
6
|
+
- Parsing maintains only a stack that scales by nesting depth.
|
|
7
|
+
- Building values will obviously hold everything under the topmost object it's building until it's finished.
|
|
8
|
+
|
|
9
|
+
It's reasonably optimized, but performance is not a primary or even secondary goal: its goal is flexibility. If speed
|
|
10
|
+
matters use a native library.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
|
|
1
14
|
from .building import ( # noqa
|
|
2
15
|
JsonValueBuilder,
|
|
3
16
|
)
|
omlish/funcs/guard.py
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
import functools
|
|
3
|
+
import operator
|
|
4
|
+
import typing as ta
|
|
5
|
+
|
|
6
|
+
from .. import check
|
|
7
|
+
from .. import collections as col
|
|
8
|
+
from .. import lang
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
T = ta.TypeVar('T')
|
|
12
|
+
T_co = ta.TypeVar('T_co', covariant=True)
|
|
13
|
+
U = ta.TypeVar('U')
|
|
14
|
+
P = ta.ParamSpec('P')
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
##
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class GuardFn(ta.Protocol[P, T_co]):
|
|
21
|
+
def __get__(self, instance, owner=None): ...
|
|
22
|
+
|
|
23
|
+
def __call__(self, *args: P.args, **kwargs: P.kwargs) -> ta.Callable[[], T_co] | None: ...
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
##
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@ta.final
|
|
30
|
+
class DumbGuardFn(ta.Generic[P, T]):
|
|
31
|
+
def __init__(self, fn: ta.Callable[P, T]) -> None:
|
|
32
|
+
self._fn = fn
|
|
33
|
+
|
|
34
|
+
def __get__(self, instance, owner=None):
|
|
35
|
+
return DumbGuardFn(self._fn.__get__(instance, owner)) # noqa
|
|
36
|
+
|
|
37
|
+
def __call__(self, *args: P.args, **kwargs: P.kwargs) -> ta.Callable[[], T]:
|
|
38
|
+
return functools.partial(self._fn, *args, **kwargs)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
dumb = DumbGuardFn
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
##
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class AmbiguousGuardFnError(Exception):
|
|
48
|
+
pass
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@ta.final
|
|
52
|
+
class MultiGuardFn(ta.Generic[P, T]):
|
|
53
|
+
def __init__(
|
|
54
|
+
self,
|
|
55
|
+
*children: GuardFn[P, T],
|
|
56
|
+
default: GuardFn[P, T] | None = None,
|
|
57
|
+
strict: bool = False,
|
|
58
|
+
) -> None:
|
|
59
|
+
self._children, self._default, self._strict = children, default, strict
|
|
60
|
+
|
|
61
|
+
lang.attr_ops(lambda self: (
|
|
62
|
+
self._children,
|
|
63
|
+
self._default,
|
|
64
|
+
self._strict,
|
|
65
|
+
)).install(locals())
|
|
66
|
+
|
|
67
|
+
def __get__(self, instance, owner=None):
|
|
68
|
+
return MultiGuardFn(*map(operator.methodcaller('__get__', instance, owner), self._children), default=self._default.__get__(instance, owner) if self._default is not None else None, strict=self._strict) # noqa
|
|
69
|
+
|
|
70
|
+
def __call__(self, *args: P.args, **kwargs: P.kwargs) -> ta.Callable[[], T] | None:
|
|
71
|
+
matches = []
|
|
72
|
+
for c in self._children:
|
|
73
|
+
if (m := c(*args, **kwargs)) is not None:
|
|
74
|
+
if not self._strict:
|
|
75
|
+
return m
|
|
76
|
+
matches.append(m)
|
|
77
|
+
if not matches:
|
|
78
|
+
if (dfl := self._default) is not None:
|
|
79
|
+
return dfl(*args, **kwargs)
|
|
80
|
+
else:
|
|
81
|
+
return None
|
|
82
|
+
elif len(matches) > 1:
|
|
83
|
+
raise AmbiguousGuardFnError
|
|
84
|
+
else:
|
|
85
|
+
return matches[0]
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
multi = MultiGuardFn
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
##
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class _BaseGuardFnMethod(lang.Abstract, ta.Generic[P, T]):
|
|
95
|
+
def __init__(
|
|
96
|
+
self,
|
|
97
|
+
*,
|
|
98
|
+
strict: bool = False,
|
|
99
|
+
requires_override: bool = False,
|
|
100
|
+
instance_cache: bool = False,
|
|
101
|
+
default: GuardFn[P, T] | None = None,
|
|
102
|
+
) -> None:
|
|
103
|
+
super().__init__()
|
|
104
|
+
|
|
105
|
+
self._strict = strict
|
|
106
|
+
self._instance_cache = instance_cache
|
|
107
|
+
self._default = default
|
|
108
|
+
|
|
109
|
+
self._registry: col.AttrRegistry[ta.Callable, None] = col.AttrRegistry(
|
|
110
|
+
requires_override=requires_override,
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
self._cache: col.AttrRegistryCache[ta.Callable, None, MultiGuardFn] = col.AttrRegistryCache(
|
|
114
|
+
self._registry,
|
|
115
|
+
self._prepare,
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
_owner: type | None = None
|
|
119
|
+
_name: str | None = None
|
|
120
|
+
|
|
121
|
+
def __set_name__(self, owner, name):
|
|
122
|
+
if self._owner is None:
|
|
123
|
+
self._owner = owner
|
|
124
|
+
if self._name is None:
|
|
125
|
+
self._name = name
|
|
126
|
+
|
|
127
|
+
def register(self, fn: U) -> U:
|
|
128
|
+
check.callable(fn)
|
|
129
|
+
self._registry.register(ta.cast(ta.Callable, fn), None)
|
|
130
|
+
return fn
|
|
131
|
+
|
|
132
|
+
def _prepare(self, instance_cls: type, collected: ta.Mapping[str, tuple[ta.Callable, None]]) -> MultiGuardFn:
|
|
133
|
+
return MultiGuardFn(
|
|
134
|
+
*[getattr(instance_cls, a) for a in collected],
|
|
135
|
+
default=self._default,
|
|
136
|
+
strict=self._strict,
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
@abc.abstractmethod
|
|
140
|
+
def _bind(self, instance, owner):
|
|
141
|
+
raise NotImplementedError
|
|
142
|
+
|
|
143
|
+
def __get__(self, instance, owner=None):
|
|
144
|
+
if instance is None:
|
|
145
|
+
return self
|
|
146
|
+
|
|
147
|
+
if self._instance_cache:
|
|
148
|
+
try:
|
|
149
|
+
return instance.__dict__[self._name]
|
|
150
|
+
except KeyError:
|
|
151
|
+
pass
|
|
152
|
+
|
|
153
|
+
bound = self._bind(instance, owner)
|
|
154
|
+
|
|
155
|
+
if self._instance_cache:
|
|
156
|
+
instance.__dict__[self._name] = bound
|
|
157
|
+
|
|
158
|
+
return bound
|
|
159
|
+
|
|
160
|
+
def _call(self, *args, **kwargs):
|
|
161
|
+
instance, *rest = args
|
|
162
|
+
return self.__get__(instance)(*rest, **kwargs)
|
|
163
|
+
|
|
164
|
+
#
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
@ta.final
|
|
168
|
+
class GuardFnMethod(_BaseGuardFnMethod[P, T]):
|
|
169
|
+
def _bind(self, instance, owner):
|
|
170
|
+
return self._cache.get(type(instance)).__get__(instance, owner) # noqa
|
|
171
|
+
|
|
172
|
+
def __call__(self, *args: P.args, **kwargs: P.kwargs) -> ta.Callable[[], T] | None:
|
|
173
|
+
return self._call(*args, **kwargs)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def method(
|
|
177
|
+
*,
|
|
178
|
+
strict: bool = False,
|
|
179
|
+
requires_override: bool = False,
|
|
180
|
+
instance_cache: bool = False,
|
|
181
|
+
default: bool = False,
|
|
182
|
+
) -> ta.Callable[[ta.Callable[P, T]], GuardFnMethod[P, T]]: # noqa
|
|
183
|
+
def inner(fn):
|
|
184
|
+
return GuardFnMethod(
|
|
185
|
+
strict=strict,
|
|
186
|
+
requires_override=requires_override,
|
|
187
|
+
instance_cache=instance_cache,
|
|
188
|
+
default=fn if default else None,
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
return inner
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
#
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
@ta.final
|
|
198
|
+
class ImmediateGuardFnMethod(_BaseGuardFnMethod[P, T]):
|
|
199
|
+
def _bind(self, instance, owner):
|
|
200
|
+
gf = self._cache.get(type(instance)).__get__(instance, owner) # noqa
|
|
201
|
+
|
|
202
|
+
def inner(*args, **kwargs):
|
|
203
|
+
return gf(*args, **kwargs)() # Note: cannot be None due to non-optional default
|
|
204
|
+
|
|
205
|
+
return inner
|
|
206
|
+
|
|
207
|
+
def __call__(self, *args: P.args, **kwargs: P.kwargs) -> T:
|
|
208
|
+
return self._call(*args, **kwargs)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def immediate_method(
|
|
212
|
+
*,
|
|
213
|
+
strict: bool = False,
|
|
214
|
+
requires_override: bool = False,
|
|
215
|
+
instance_cache: bool = False,
|
|
216
|
+
) -> ta.Callable[[ta.Callable[P, T]], ImmediateGuardFnMethod[P, T]]: # noqa
|
|
217
|
+
def inner(fn):
|
|
218
|
+
return ImmediateGuardFnMethod(
|
|
219
|
+
strict=strict,
|
|
220
|
+
requires_override=requires_override,
|
|
221
|
+
instance_cache=instance_cache,
|
|
222
|
+
default=(lambda *args, **kwargs: lambda: fn(*args, **kwargs)),
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
return inner
|
omlish/graphs/dot/rendering.py
CHANGED
omlish/http/all.py
CHANGED
|
@@ -4,9 +4,18 @@ from .. import lang as _lang
|
|
|
4
4
|
with _lang.auto_proxy_init(globals()):
|
|
5
5
|
##
|
|
6
6
|
|
|
7
|
+
from .clients.asyncs import ( # noqa
|
|
8
|
+
AsyncStreamHttpResponse,
|
|
9
|
+
|
|
10
|
+
async_close_http_client_response,
|
|
11
|
+
async_closing_http_client_response,
|
|
12
|
+
async_read_http_client_response,
|
|
13
|
+
|
|
14
|
+
AsyncHttpClient,
|
|
15
|
+
)
|
|
16
|
+
|
|
7
17
|
from .clients.base import ( # noqa
|
|
8
18
|
DEFAULT_ENCODING,
|
|
9
|
-
|
|
10
19
|
is_success_status,
|
|
11
20
|
|
|
12
21
|
HttpRequest,
|
|
@@ -14,34 +23,63 @@ with _lang.auto_proxy_init(globals()):
|
|
|
14
23
|
BaseHttpResponse,
|
|
15
24
|
HttpResponse,
|
|
16
25
|
|
|
26
|
+
HttpClientContext,
|
|
27
|
+
|
|
17
28
|
HttpClientError,
|
|
18
29
|
HttpStatusError,
|
|
30
|
+
|
|
31
|
+
BaseHttpClient,
|
|
19
32
|
)
|
|
20
33
|
|
|
21
34
|
from .clients.default import ( # noqa
|
|
22
35
|
client,
|
|
36
|
+
manage_client,
|
|
23
37
|
|
|
24
38
|
request,
|
|
39
|
+
|
|
40
|
+
async_client,
|
|
41
|
+
manage_async_client,
|
|
42
|
+
|
|
43
|
+
async_request,
|
|
25
44
|
)
|
|
26
45
|
|
|
27
46
|
from .clients.httpx import ( # noqa
|
|
28
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,
|
|
29
61
|
)
|
|
30
62
|
|
|
31
63
|
from .clients.sync import ( # noqa
|
|
32
64
|
StreamHttpResponse,
|
|
33
65
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
66
|
+
close_http_client_response,
|
|
67
|
+
closing_http_client_response,
|
|
68
|
+
read_http_client_response,
|
|
37
69
|
|
|
38
70
|
HttpClient,
|
|
39
71
|
)
|
|
40
72
|
|
|
73
|
+
from .clients.syncasync import ( # noqa
|
|
74
|
+
SyncAsyncHttpClient,
|
|
75
|
+
)
|
|
76
|
+
|
|
41
77
|
from .clients.urllib import ( # noqa
|
|
42
78
|
UrllibHttpClient,
|
|
43
79
|
)
|
|
44
80
|
|
|
81
|
+
from . import asgi # noqa
|
|
82
|
+
|
|
45
83
|
from . import consts # noqa
|
|
46
84
|
|
|
47
85
|
from .cookies import ( # noqa
|
|
@@ -80,3 +118,5 @@ with _lang.auto_proxy_init(globals()):
|
|
|
80
118
|
MultipartEncoder,
|
|
81
119
|
MultipartField,
|
|
82
120
|
)
|
|
121
|
+
|
|
122
|
+
from . import wsgi # noqa
|