omlish 0.0.0.dev5__py3-none-any.whl → 0.0.0.dev7__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/__about__.py +109 -5
- omlish/__init__.py +0 -8
- omlish/asyncs/__init__.py +9 -9
- omlish/asyncs/anyio.py +123 -19
- omlish/asyncs/asyncio.py +23 -0
- omlish/asyncs/asyncs.py +9 -6
- omlish/asyncs/bridge.py +316 -0
- omlish/asyncs/trio_asyncio.py +7 -3
- omlish/bootstrap.py +737 -0
- omlish/check.py +1 -1
- omlish/collections/__init__.py +5 -0
- omlish/collections/exceptions.py +2 -0
- omlish/collections/identity.py +7 -0
- omlish/collections/utils.py +38 -9
- omlish/configs/strings.py +96 -0
- omlish/dataclasses/__init__.py +16 -0
- omlish/dataclasses/impl/copy.py +30 -0
- omlish/dataclasses/impl/descriptors.py +95 -0
- omlish/dataclasses/impl/exceptions.py +6 -0
- omlish/dataclasses/impl/fields.py +24 -25
- omlish/dataclasses/impl/init.py +4 -2
- omlish/dataclasses/impl/main.py +2 -0
- omlish/dataclasses/impl/reflect.py +1 -1
- omlish/dataclasses/utils.py +67 -0
- omlish/{lang/datetimes.py → datetimes.py} +8 -4
- omlish/diag/__init__.py +4 -0
- omlish/diag/procfs.py +2 -2
- omlish/{testing → diag}/pydevd.py +35 -0
- omlish/diag/threads.py +131 -48
- omlish/dispatch/_dispatch2.py +65 -0
- omlish/dispatch/_dispatch3.py +104 -0
- omlish/docker.py +16 -1
- omlish/fnpairs.py +11 -4
- omlish/formats/__init__.py +0 -0
- omlish/{configs → formats}/dotenv.py +15 -24
- omlish/{json.py → formats/json.py} +2 -1
- omlish/formats/yaml.py +223 -0
- omlish/graphs/trees.py +1 -1
- omlish/http/asgi.py +2 -1
- omlish/http/collections.py +15 -0
- omlish/http/consts.py +22 -1
- omlish/http/sessions.py +10 -3
- omlish/inject/__init__.py +49 -17
- omlish/inject/binder.py +185 -5
- omlish/inject/bindings.py +3 -36
- omlish/inject/eagers.py +2 -8
- omlish/inject/elements.py +31 -10
- omlish/inject/exceptions.py +1 -1
- omlish/inject/impl/elements.py +37 -12
- omlish/inject/impl/injector.py +72 -25
- omlish/inject/impl/inspect.py +33 -5
- omlish/inject/impl/origins.py +77 -0
- omlish/inject/impl/{private.py → privates.py} +2 -2
- omlish/inject/impl/scopes.py +6 -2
- omlish/inject/injector.py +8 -4
- omlish/inject/inspect.py +18 -0
- omlish/inject/keys.py +8 -14
- omlish/inject/listeners.py +26 -0
- omlish/inject/managed.py +76 -10
- omlish/inject/multis.py +68 -18
- omlish/inject/origins.py +30 -0
- omlish/inject/overrides.py +5 -4
- omlish/inject/{private.py → privates.py} +6 -10
- omlish/inject/providers.py +12 -85
- omlish/inject/scopes.py +13 -6
- omlish/inject/types.py +3 -1
- omlish/inject/utils.py +18 -0
- omlish/iterators.py +69 -2
- omlish/lang/__init__.py +24 -9
- omlish/lang/cached.py +2 -2
- omlish/lang/classes/restrict.py +12 -1
- omlish/lang/classes/simple.py +18 -8
- omlish/lang/contextmanagers.py +13 -4
- omlish/lang/descriptors.py +132 -1
- omlish/lang/functions.py +8 -28
- omlish/lang/imports.py +67 -0
- omlish/lang/iterables.py +60 -1
- omlish/lang/maybes.py +3 -0
- omlish/lang/objects.py +38 -0
- omlish/lang/strings.py +25 -0
- omlish/lang/sys.py +9 -0
- omlish/lang/typing.py +42 -0
- omlish/lifecycles/__init__.py +34 -0
- omlish/lifecycles/abstract.py +43 -0
- omlish/lifecycles/base.py +51 -0
- omlish/lifecycles/contextmanagers.py +74 -0
- omlish/lifecycles/controller.py +116 -0
- omlish/lifecycles/manager.py +161 -0
- omlish/lifecycles/states.py +43 -0
- omlish/lifecycles/transitions.py +64 -0
- omlish/lite/__init__.py +1 -0
- omlish/lite/cached.py +18 -0
- omlish/lite/check.py +29 -0
- omlish/lite/contextmanagers.py +18 -0
- omlish/lite/json.py +30 -0
- omlish/lite/logs.py +52 -0
- omlish/lite/marshal.py +316 -0
- omlish/lite/reflect.py +49 -0
- omlish/lite/runtime.py +18 -0
- omlish/lite/secrets.py +19 -0
- omlish/lite/strings.py +25 -0
- omlish/lite/subprocesses.py +112 -0
- omlish/logs/configs.py +15 -2
- omlish/logs/formatters.py +7 -2
- omlish/marshal/__init__.py +32 -0
- omlish/marshal/any.py +5 -5
- omlish/marshal/base.py +27 -11
- omlish/marshal/base64.py +24 -9
- omlish/marshal/dataclasses.py +34 -28
- omlish/marshal/datetimes.py +74 -18
- omlish/marshal/enums.py +14 -8
- omlish/marshal/exceptions.py +11 -1
- omlish/marshal/factories.py +59 -74
- omlish/marshal/forbidden.py +35 -0
- omlish/marshal/global_.py +11 -4
- omlish/marshal/iterables.py +21 -24
- omlish/marshal/mappings.py +23 -26
- omlish/marshal/naming.py +4 -0
- omlish/marshal/numbers.py +51 -0
- omlish/marshal/objects.py +1 -0
- omlish/marshal/optionals.py +11 -12
- omlish/marshal/polymorphism.py +86 -21
- omlish/marshal/primitives.py +4 -5
- omlish/marshal/standard.py +13 -8
- omlish/marshal/uuids.py +4 -5
- omlish/matchfns.py +218 -0
- omlish/os.py +64 -0
- omlish/reflect/__init__.py +39 -0
- omlish/reflect/isinstance.py +38 -0
- omlish/reflect/ops.py +84 -0
- omlish/reflect/subst.py +110 -0
- omlish/reflect/types.py +275 -0
- omlish/secrets/__init__.py +23 -0
- omlish/secrets/crypto.py +132 -0
- omlish/secrets/marshal.py +70 -0
- omlish/secrets/openssl.py +207 -0
- omlish/secrets/passwords.py +120 -0
- omlish/secrets/secrets.py +299 -0
- omlish/secrets/subprocesses.py +42 -0
- omlish/sql/dbs.py +7 -6
- omlish/sql/duckdb.py +136 -0
- omlish/sql/exprs.py +12 -0
- omlish/sql/secrets.py +10 -0
- omlish/sql/sqlean.py +17 -0
- omlish/term.py +2 -2
- omlish/testing/pytest/__init__.py +3 -2
- omlish/testing/pytest/inject/harness.py +3 -3
- omlish/testing/pytest/marks.py +4 -7
- omlish/testing/pytest/plugins/__init__.py +1 -0
- omlish/testing/pytest/plugins/asyncs.py +136 -0
- omlish/testing/pytest/plugins/pydevd.py +1 -1
- omlish/testing/pytest/plugins/switches.py +54 -19
- omlish/text/glyphsplit.py +97 -0
- omlish-0.0.0.dev7.dist-info/METADATA +50 -0
- omlish-0.0.0.dev7.dist-info/RECORD +268 -0
- {omlish-0.0.0.dev5.dist-info → omlish-0.0.0.dev7.dist-info}/WHEEL +1 -1
- omlish/reflect.py +0 -355
- omlish-0.0.0.dev5.dist-info/METADATA +0 -34
- omlish-0.0.0.dev5.dist-info/RECORD +0 -212
- /omlish/{asyncs/futures.py → concurrent.py} +0 -0
- /omlish/{configs → formats}/props.py +0 -0
- {omlish-0.0.0.dev5.dist-info → omlish-0.0.0.dev7.dist-info}/LICENSE +0 -0
- {omlish-0.0.0.dev5.dist-info → omlish-0.0.0.dev7.dist-info}/top_level.txt +0 -0
omlish/formats/yaml.py
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TODO:
|
|
3
|
+
- !! shared 'object format' node hierarchy
|
|
4
|
+
- fuse yaml and hocon - marks, *COMMENTS*, etc
|
|
5
|
+
- goal: perfect rewrites (comments, whitespace)
|
|
6
|
+
- or at least comments
|
|
7
|
+
- rename 'objects'? codecs/serde interplay still unresolved
|
|
8
|
+
"""
|
|
9
|
+
import datetime
|
|
10
|
+
import types
|
|
11
|
+
import typing as ta
|
|
12
|
+
|
|
13
|
+
from .. import check
|
|
14
|
+
from .. import dataclasses as dc
|
|
15
|
+
from .. import lang
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
if ta.TYPE_CHECKING:
|
|
19
|
+
import yaml
|
|
20
|
+
import yaml.nodes as yaml_nodes
|
|
21
|
+
else:
|
|
22
|
+
yaml = lang.proxy_import('yaml')
|
|
23
|
+
yaml_nodes = lang.proxy_import('yaml.nodes')
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
T = ta.TypeVar('T')
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dc.dataclass(frozen=True)
|
|
30
|
+
class NodeWrapped(lang.Final, ta.Generic[T]):
|
|
31
|
+
value: T
|
|
32
|
+
node: 'yaml_nodes.Node'
|
|
33
|
+
|
|
34
|
+
def __post_init__(self) -> None:
|
|
35
|
+
if isinstance(self.value, NodeWrapped):
|
|
36
|
+
raise TypeError(self.value)
|
|
37
|
+
if not isinstance(self.node, yaml_nodes.Node):
|
|
38
|
+
raise TypeError(self.node)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class NodeUnwrapper:
|
|
42
|
+
|
|
43
|
+
seq_types: tuple[type, ...] = (
|
|
44
|
+
list,
|
|
45
|
+
set,
|
|
46
|
+
tuple,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
def unwrap_seq(self, nw: NodeWrapped[T]) -> T:
|
|
50
|
+
return nw.value.__class__(map(self.unwrap, nw.value)) # type: ignore
|
|
51
|
+
|
|
52
|
+
map_types: tuple[type, ...] = (
|
|
53
|
+
dict,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
def unwrap_map(self, nw: NodeWrapped[T]) -> T:
|
|
57
|
+
return nw.value.__class__({self.unwrap(k): self.unwrap(v) for k, v in nw.value.items()}) # type: ignore
|
|
58
|
+
|
|
59
|
+
scalar_types: tuple[type, ...] = (
|
|
60
|
+
bool,
|
|
61
|
+
bytes,
|
|
62
|
+
datetime.datetime,
|
|
63
|
+
float,
|
|
64
|
+
int,
|
|
65
|
+
str,
|
|
66
|
+
type(None),
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
def unwrap_scalar(self, nw: NodeWrapped[T]) -> T:
|
|
70
|
+
return nw.value
|
|
71
|
+
|
|
72
|
+
def unwrap_unknown(self, nw: NodeWrapped[T]) -> T:
|
|
73
|
+
raise TypeError(nw.value)
|
|
74
|
+
|
|
75
|
+
def unwrap(self, nw: NodeWrapped[T]) -> T:
|
|
76
|
+
check.isinstance(nw, NodeWrapped)
|
|
77
|
+
if isinstance(nw.value, self.seq_types):
|
|
78
|
+
return self.unwrap_seq(nw)
|
|
79
|
+
elif isinstance(nw.value, self.map_types):
|
|
80
|
+
return self.unwrap_map(nw)
|
|
81
|
+
elif isinstance(nw.value, self.scalar_types):
|
|
82
|
+
return self.unwrap_scalar(nw)
|
|
83
|
+
else:
|
|
84
|
+
return self.unwrap_unknown(nw)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def unwrap(nw: NodeWrapped[T]) -> T:
|
|
88
|
+
return NodeUnwrapper().unwrap(nw)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class NodeWrappingConstructorMixin:
|
|
92
|
+
|
|
93
|
+
def __init__(self, *args, **kwargs):
|
|
94
|
+
super().__init__(*args, **kwargs)
|
|
95
|
+
|
|
96
|
+
ctors = {
|
|
97
|
+
fn.__name__: fn for fn in [
|
|
98
|
+
self.__class__.construct_yaml_omap,
|
|
99
|
+
self.__class__.construct_yaml_pairs,
|
|
100
|
+
]
|
|
101
|
+
}
|
|
102
|
+
self.yaml_constructors = {
|
|
103
|
+
tag: ctors.get(ctor.__name__, ctor)
|
|
104
|
+
for tag, ctor in self.yaml_constructors.items() # type: ignore # noqa
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
def construct_object(self, node, deep=False):
|
|
108
|
+
value = super().construct_object(node, deep=deep) # type: ignore
|
|
109
|
+
return NodeWrapped(value, node)
|
|
110
|
+
|
|
111
|
+
def __construct_yaml_pairs(self, node, fn):
|
|
112
|
+
omap = [] # type: ignore
|
|
113
|
+
gen = check.isinstance(fn(node), types.GeneratorType)
|
|
114
|
+
yield omap
|
|
115
|
+
uomap = next(gen)
|
|
116
|
+
lang.exhaust(gen)
|
|
117
|
+
for key, value in uomap: # type: ignore
|
|
118
|
+
omap.append(NodeWrapped((key, value), node))
|
|
119
|
+
|
|
120
|
+
def construct_yaml_omap(self, node):
|
|
121
|
+
return self.__construct_yaml_pairs(node, super().construct_yaml_omap) # type: ignore # noqa
|
|
122
|
+
|
|
123
|
+
def construct_yaml_pairs(self, node):
|
|
124
|
+
return self.__construct_yaml_pairs(node, super().construct_yaml_pairs) # type: ignore # noqa
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class _cached_class_property: # noqa
|
|
128
|
+
def __init__(self, fn):
|
|
129
|
+
super().__init__()
|
|
130
|
+
self._fn = fn
|
|
131
|
+
self._attr = None
|
|
132
|
+
|
|
133
|
+
def __call__(self, *args, **kwargs):
|
|
134
|
+
raise TypeError
|
|
135
|
+
|
|
136
|
+
def __set_name__(self, owner, name):
|
|
137
|
+
self._attr = '_' + name
|
|
138
|
+
|
|
139
|
+
def __get__(self, instance, owner=None):
|
|
140
|
+
if owner is None:
|
|
141
|
+
if instance is None:
|
|
142
|
+
raise RuntimeError
|
|
143
|
+
owner = instance.__class__
|
|
144
|
+
try:
|
|
145
|
+
return owner.__dict__[self._attr]
|
|
146
|
+
except KeyError:
|
|
147
|
+
ret = self._fn(owner)
|
|
148
|
+
setattr(owner, self._attr, ret) # type: ignore
|
|
149
|
+
return ret
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class WrappedLoaders(lang.Namespace):
|
|
153
|
+
|
|
154
|
+
@staticmethod
|
|
155
|
+
def _wrap(cls): # noqa
|
|
156
|
+
return type('NodeWrapping$' + cls.__name__, (NodeWrappingConstructorMixin, cls), {})
|
|
157
|
+
|
|
158
|
+
Base: type['yaml.BaseLoader'] = _cached_class_property(lambda cls: cls._wrap(yaml.BaseLoader)) # type: ignore
|
|
159
|
+
|
|
160
|
+
@classmethod
|
|
161
|
+
def base(cls, *args, **kwargs) -> 'yaml.BaseLoader':
|
|
162
|
+
return cls.Base(*args, **kwargs)
|
|
163
|
+
|
|
164
|
+
Full: type['yaml.FullLoader'] = _cached_class_property(lambda cls: cls._wrap(yaml.FullLoader)) # type: ignore
|
|
165
|
+
|
|
166
|
+
@classmethod
|
|
167
|
+
def full(cls, *args, **kwargs) -> 'yaml.FullLoader':
|
|
168
|
+
return cls.Full(*args, **kwargs)
|
|
169
|
+
|
|
170
|
+
Safe: type['yaml.SafeLoader'] = _cached_class_property(lambda cls: cls._wrap(yaml.SafeLoader)) # type: ignore
|
|
171
|
+
|
|
172
|
+
@classmethod
|
|
173
|
+
def safe(cls, *args, **kwargs) -> 'yaml.SafeLoader':
|
|
174
|
+
return cls.Safe(*args, **kwargs)
|
|
175
|
+
|
|
176
|
+
Unsafe: type['yaml.UnsafeLoader'] = _cached_class_property(lambda cls: cls._wrap(yaml.UnsafeLoader)) # type: ignore
|
|
177
|
+
|
|
178
|
+
@classmethod
|
|
179
|
+
def unsafe(cls, *args, **kwargs) -> 'yaml.UnsafeLoader':
|
|
180
|
+
return cls.Unsafe(*args, **kwargs)
|
|
181
|
+
|
|
182
|
+
CBase: type['yaml.CBaseLoader'] = _cached_class_property(lambda cls: cls._wrap(yaml.CBaseLoader)) # type: ignore
|
|
183
|
+
|
|
184
|
+
@classmethod
|
|
185
|
+
def cbase(cls, *args, **kwargs) -> 'yaml.CBaseLoader':
|
|
186
|
+
return cls.CBase(*args, **kwargs)
|
|
187
|
+
|
|
188
|
+
CFull: type['yaml.CFullLoader'] = _cached_class_property(lambda cls: cls._wrap(yaml.CFullLoader)) # type: ignore
|
|
189
|
+
|
|
190
|
+
@classmethod
|
|
191
|
+
def cfull(cls, *args, **kwargs) -> 'yaml.CFullLoader':
|
|
192
|
+
return cls.CFull(*args, **kwargs)
|
|
193
|
+
|
|
194
|
+
CSafe: type['yaml.CSafeLoader'] = _cached_class_property(lambda cls: cls._wrap(yaml.CSafeLoader)) # type: ignore
|
|
195
|
+
|
|
196
|
+
@classmethod
|
|
197
|
+
def csafe(cls, *args, **kwargs) -> 'yaml.CSafeLoader':
|
|
198
|
+
return cls.CSafe(*args, **kwargs)
|
|
199
|
+
|
|
200
|
+
CUnsafe: type['yaml.CUnsafeLoader'] = _cached_class_property(lambda cls: cls._wrap(yaml.CUnsafeLoader)) # type: ignore # noqa
|
|
201
|
+
|
|
202
|
+
@classmethod
|
|
203
|
+
def cunsafe(cls, *args, **kwargs) -> 'yaml.CUnsafeLoader':
|
|
204
|
+
return cls.CUnsafe(*args, **kwargs)
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def load(stream, Loader): # noqa
|
|
208
|
+
with lang.disposing(Loader(stream)) as loader:
|
|
209
|
+
return loader.get_single_data()
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def load_all(stream, Loader): # noqa
|
|
213
|
+
with lang.disposing(Loader(stream)) as loader:
|
|
214
|
+
while loader.check_data():
|
|
215
|
+
yield loader.get_data()
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def full_load(stream): # noqa
|
|
219
|
+
return load(stream, yaml.FullLoader)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def full_load_all(stream): # noqa # noqa
|
|
223
|
+
return load_all(stream, yaml.FullLoader)
|
omlish/graphs/trees.py
CHANGED
|
@@ -190,7 +190,7 @@ class BasicTreeAnalysis(ta.Generic[NodeT]):
|
|
|
190
190
|
e: ta.Any
|
|
191
191
|
d: ta.Any
|
|
192
192
|
if identity:
|
|
193
|
-
e, d = id, col.unique_map((id(n), n) for n, _ in pairs)
|
|
193
|
+
e, d = id, col.unique_map(((id(n), n) for n, _ in pairs), strict=True)
|
|
194
194
|
else:
|
|
195
195
|
e, d = lang.identity, lang.identity
|
|
196
196
|
tsd = {e(n): {e(p)} for n, p in parents_by_node.items()}
|
omlish/http/asgi.py
CHANGED
|
@@ -18,9 +18,10 @@ AsgiMessage: ta.TypeAlias = ta.Mapping[str, ta.Any]
|
|
|
18
18
|
AsgiRecv: ta.TypeAlias = ta.Callable[[], ta.Awaitable[AsgiMessage]]
|
|
19
19
|
AsgiSend: ta.TypeAlias = ta.Callable[[AsgiMessage], ta.Awaitable[None]]
|
|
20
20
|
AsgiApp: ta.TypeAlias = ta.Callable[[AsgiScope, AsgiRecv, AsgiSend], ta.Awaitable[None]]
|
|
21
|
+
AsgiWrapper: ta.TypeAlias = ta.Callable[[AsgiApp, AsgiScope, AsgiRecv, AsgiSend], ta.Awaitable[None]]
|
|
21
22
|
|
|
22
23
|
|
|
23
|
-
class
|
|
24
|
+
class AsgiApp_(abc.ABC): # noqa
|
|
24
25
|
@abc.abstractmethod
|
|
25
26
|
async def __call__(self, scope: AsgiScope, recv: AsgiRecv, send: AsgiSend) -> None:
|
|
26
27
|
raise NotImplementedError
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import typing as ta
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
V = ta.TypeVar('V')
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class HttpMap(ta.Mapping[str, V]):
|
|
8
|
+
def __getitem__(self, k):
|
|
9
|
+
raise NotImplementedError
|
|
10
|
+
|
|
11
|
+
def __len__(self):
|
|
12
|
+
raise NotImplementedError
|
|
13
|
+
|
|
14
|
+
def __iter__(self):
|
|
15
|
+
raise NotImplementedError
|
omlish/http/consts.py
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
"""
|
|
2
|
+
TODO:
|
|
3
|
+
- import mimetypes lol
|
|
4
|
+
"""
|
|
5
|
+
import base64
|
|
6
|
+
import http
|
|
2
7
|
|
|
3
8
|
|
|
4
9
|
##
|
|
@@ -31,6 +36,8 @@ STATUS_GATEWAY_TIMEOUT = format_status(http.HTTPStatus.GATEWAY_TIMEOUT)
|
|
|
31
36
|
|
|
32
37
|
|
|
33
38
|
HEADER_CONTENT_TYPE = b'Content-Type'
|
|
39
|
+
HEADER_ACCEPT = b'Accept'
|
|
40
|
+
|
|
34
41
|
CONTENT_CHARSET_UTF8 = b'charset=utf-8'
|
|
35
42
|
|
|
36
43
|
CONTENT_TYPE_BYTES = b'application/octet-stream'
|
|
@@ -43,5 +50,19 @@ CONTENT_TYPE_ICON = b'image/x-icon'
|
|
|
43
50
|
CONTENT_TYPE_JSON = b'application/json'
|
|
44
51
|
CONTENT_TYPE_JSON_UTF8 = b'; '.join([CONTENT_TYPE_JSON, CONTENT_CHARSET_UTF8])
|
|
45
52
|
|
|
53
|
+
CONTENT_TYPE_PNG = b'image/png'
|
|
54
|
+
|
|
46
55
|
CONTENT_TYPE_TEXT = b'text/plain'
|
|
47
56
|
CONTENT_TYPE_TEXT_UTF8 = b'; '.join([CONTENT_TYPE_TEXT, CONTENT_CHARSET_UTF8])
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
##
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
HEADER_AUTH = b'Authorization'
|
|
63
|
+
BEARER_AUTH_HEADER_PREFIX = b'Bearer '
|
|
64
|
+
BASIC_AUTH_HEADER_PREFIX = b'Basic '
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def format_basic_auth_header(username: str, password: str) -> bytes:
|
|
68
|
+
return BASIC_AUTH_HEADER_PREFIX + base64.b64encode(':'.join([username, password]).encode())
|
omlish/http/sessions.py
CHANGED
|
@@ -10,6 +10,7 @@ import zlib
|
|
|
10
10
|
|
|
11
11
|
from .. import fnpairs as fps
|
|
12
12
|
from .. import lang
|
|
13
|
+
from .. import secrets as sec
|
|
13
14
|
from .cookies import dump_cookie
|
|
14
15
|
from .cookies import parse_cookie
|
|
15
16
|
from .json import JSON_TAGGER
|
|
@@ -44,13 +45,19 @@ def bytes_to_int(bytestr: bytes) -> int:
|
|
|
44
45
|
class Signer:
|
|
45
46
|
@dc.dataclass(frozen=True)
|
|
46
47
|
class Config:
|
|
47
|
-
secret_key: str
|
|
48
|
+
secret_key: str | sec.SecretRef = dc.field()
|
|
48
49
|
salt: str = 'cookie-session'
|
|
49
50
|
|
|
50
|
-
def __init__(
|
|
51
|
+
def __init__(
|
|
52
|
+
self,
|
|
53
|
+
config: Config,
|
|
54
|
+
*,
|
|
55
|
+
secrets: sec.Secrets = sec.EMPTY_SECRETS,
|
|
56
|
+
) -> None:
|
|
51
57
|
super().__init__()
|
|
52
58
|
|
|
53
59
|
self._config = config
|
|
60
|
+
self._secrets = secrets
|
|
54
61
|
|
|
55
62
|
@lang.cached_function
|
|
56
63
|
def digest(self) -> ta.Any:
|
|
@@ -58,7 +65,7 @@ class Signer:
|
|
|
58
65
|
|
|
59
66
|
@lang.cached_function
|
|
60
67
|
def derive_key(self) -> bytes:
|
|
61
|
-
mac = hmac.new(self._config.secret_key.encode(), digestmod=self.digest())
|
|
68
|
+
mac = hmac.new(self._secrets.fix(self._config.secret_key).reveal().encode(), digestmod=self.digest())
|
|
62
69
|
mac.update(self._config.salt.encode())
|
|
63
70
|
return mac.digest()
|
|
64
71
|
|
omlish/inject/__init__.py
CHANGED
|
@@ -1,26 +1,30 @@
|
|
|
1
1
|
"""
|
|
2
2
|
~> https://github.com/google/guice/commit/70248eafa90cd70a68b293763e53f6aec656e73c
|
|
3
3
|
"""
|
|
4
|
+
from .binder import ( # noqa
|
|
5
|
+
bind,
|
|
6
|
+
bind_as_fn,
|
|
7
|
+
)
|
|
8
|
+
|
|
4
9
|
from .bindings import ( # noqa
|
|
5
10
|
Binding,
|
|
6
|
-
as_,
|
|
7
|
-
as_binding,
|
|
8
11
|
)
|
|
9
12
|
|
|
10
13
|
from .eagers import ( # noqa
|
|
11
|
-
|
|
14
|
+
Eager,
|
|
12
15
|
)
|
|
13
16
|
|
|
14
17
|
from .elements import ( # noqa
|
|
15
|
-
as_elements,
|
|
16
18
|
Element,
|
|
19
|
+
Elemental,
|
|
17
20
|
Elements,
|
|
21
|
+
as_elements,
|
|
18
22
|
)
|
|
19
23
|
|
|
20
24
|
from .exceptions import ( # noqa
|
|
21
25
|
BaseKeyError,
|
|
26
|
+
ConflictingKeyError,
|
|
22
27
|
CyclicDependencyError,
|
|
23
|
-
DuplicateKeyError,
|
|
24
28
|
ScopeAlreadyOpenError,
|
|
25
29
|
ScopeError,
|
|
26
30
|
ScopeNotOpenError,
|
|
@@ -35,57 +39,85 @@ from .injector import ( # noqa
|
|
|
35
39
|
from .inspect import ( # noqa
|
|
36
40
|
Kwarg,
|
|
37
41
|
KwargsTarget,
|
|
42
|
+
build_kwargs_target,
|
|
43
|
+
tag,
|
|
38
44
|
)
|
|
39
45
|
|
|
40
46
|
from .keys import ( # noqa
|
|
41
47
|
Key,
|
|
42
48
|
as_key,
|
|
43
|
-
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
from .listeners import ( # noqa
|
|
52
|
+
ProvisionListener,
|
|
53
|
+
ProvisionListenerBinding,
|
|
54
|
+
bind_provision_listener,
|
|
44
55
|
)
|
|
45
56
|
|
|
46
57
|
from .managed import ( # noqa
|
|
58
|
+
create_async_managed_injector,
|
|
47
59
|
create_managed_injector,
|
|
60
|
+
make_async_managed_provider,
|
|
61
|
+
make_managed_provider,
|
|
48
62
|
)
|
|
49
63
|
|
|
50
64
|
from .multis import ( # noqa
|
|
51
65
|
MapBinding,
|
|
66
|
+
MapProvider,
|
|
52
67
|
SetBinding,
|
|
53
|
-
|
|
54
|
-
|
|
68
|
+
SetProvider,
|
|
69
|
+
MapBinder,
|
|
70
|
+
SetBinder,
|
|
71
|
+
|
|
72
|
+
MapBinder as map_binder, # noqa
|
|
73
|
+
SetBinder as set_binder, # noqa
|
|
55
74
|
)
|
|
56
75
|
|
|
57
76
|
|
|
58
77
|
from .overrides import ( # noqa
|
|
78
|
+
Overrides,
|
|
59
79
|
override,
|
|
60
80
|
)
|
|
61
81
|
|
|
62
|
-
from .
|
|
63
|
-
|
|
82
|
+
from .origins import ( # noqa
|
|
83
|
+
HasOrigins,
|
|
84
|
+
Origin,
|
|
85
|
+
Origins,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
from .privates import ( # noqa
|
|
89
|
+
Expose,
|
|
90
|
+
Private,
|
|
64
91
|
private,
|
|
92
|
+
|
|
93
|
+
Expose as expose, # noqa
|
|
65
94
|
)
|
|
66
95
|
|
|
67
96
|
from .providers import ( # noqa
|
|
97
|
+
ConstProvider,
|
|
98
|
+
CtorProvider,
|
|
99
|
+
FnProvider,
|
|
100
|
+
LinkProvider,
|
|
68
101
|
Provider,
|
|
69
|
-
as_provider,
|
|
70
|
-
const,
|
|
71
|
-
ctor,
|
|
72
|
-
fn,
|
|
73
|
-
link,
|
|
74
102
|
)
|
|
75
103
|
|
|
76
104
|
from .scopes import ( # noqa
|
|
77
105
|
ScopeBinding,
|
|
106
|
+
ScopeSeededProvider,
|
|
78
107
|
SeededScope,
|
|
79
108
|
Singleton,
|
|
80
109
|
Thread,
|
|
81
110
|
bind_scope,
|
|
82
111
|
bind_scope_seed,
|
|
83
112
|
enter_seeded_scope,
|
|
84
|
-
in_,
|
|
85
|
-
singleton,
|
|
86
113
|
)
|
|
87
114
|
|
|
88
115
|
from .types import ( # noqa
|
|
89
116
|
Scope,
|
|
117
|
+
Tag,
|
|
90
118
|
Unscoped,
|
|
91
119
|
)
|
|
120
|
+
|
|
121
|
+
from .utils import ( # noqa
|
|
122
|
+
ConstFn,
|
|
123
|
+
)
|
omlish/inject/binder.py
CHANGED
|
@@ -1,12 +1,192 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TODO:
|
|
3
|
+
- multis?
|
|
4
|
+
|
|
5
|
+
class SetBinding(Element, lang.Final):
|
|
6
|
+
class SetProvider(Provider):
|
|
7
|
+
|
|
8
|
+
class MapBinding(Element, lang.Final):
|
|
9
|
+
class MapProvider(Provider):
|
|
10
|
+
"""
|
|
11
|
+
import functools
|
|
12
|
+
import inspect
|
|
13
|
+
import types
|
|
1
14
|
import typing as ta
|
|
2
15
|
|
|
16
|
+
from .. import check
|
|
17
|
+
from .. import dataclasses as dc
|
|
18
|
+
from .. import lang
|
|
19
|
+
from .. import reflect as rfl
|
|
20
|
+
from .bindings import Binding
|
|
21
|
+
from .eagers import Eager
|
|
3
22
|
from .elements import Element
|
|
4
23
|
from .elements import Elements
|
|
5
|
-
from .
|
|
24
|
+
from .keys import Key
|
|
25
|
+
from .keys import as_key
|
|
26
|
+
from .privates import Expose
|
|
27
|
+
from .providers import ConstProvider
|
|
28
|
+
from .providers import CtorProvider
|
|
29
|
+
from .providers import FnProvider
|
|
30
|
+
from .providers import LinkProvider
|
|
31
|
+
from .providers import Provider
|
|
32
|
+
from .scopes import SCOPE_ALIASES
|
|
33
|
+
from .scopes import Singleton
|
|
34
|
+
from .types import Scope
|
|
35
|
+
from .types import Unscoped
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
if ta.TYPE_CHECKING:
|
|
39
|
+
from .impl.inspect import inspect as _inspect
|
|
40
|
+
else:
|
|
41
|
+
_inspect = lang.proxy_import('.impl.inspect', __package__)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
T = ta.TypeVar('T')
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
##
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
_FN_TYPES: tuple[type, ...] = (
|
|
51
|
+
types.FunctionType,
|
|
52
|
+
types.MethodType,
|
|
53
|
+
|
|
54
|
+
classmethod,
|
|
55
|
+
staticmethod,
|
|
56
|
+
|
|
57
|
+
functools.partial,
|
|
58
|
+
functools.partialmethod,
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _is_fn(obj: ta.Any) -> bool:
|
|
63
|
+
return isinstance(obj, _FN_TYPES)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def bind_as_fn(cls: type[T]) -> type[T]:
|
|
67
|
+
check.isinstance(cls, type)
|
|
68
|
+
global _FN_TYPES
|
|
69
|
+
if cls not in _FN_TYPES:
|
|
70
|
+
_FN_TYPES = (*_FN_TYPES, cls)
|
|
71
|
+
return cls
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
##
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
_BANNED_BIND_TYPES = (
|
|
78
|
+
Element,
|
|
79
|
+
Provider,
|
|
80
|
+
Elements,
|
|
81
|
+
Scope,
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def bind(
|
|
86
|
+
obj: ta.Any,
|
|
87
|
+
*,
|
|
88
|
+
tag: ta.Any = None,
|
|
89
|
+
|
|
90
|
+
to_fn: ta.Any = None,
|
|
91
|
+
to_ctor: ta.Any = None,
|
|
92
|
+
to_const: ta.Any = None,
|
|
93
|
+
to_key: ta.Any = None,
|
|
94
|
+
|
|
95
|
+
in_: Scope | None = None,
|
|
96
|
+
singleton: bool = False,
|
|
97
|
+
|
|
98
|
+
eager: bool = False,
|
|
99
|
+
expose: bool = False,
|
|
100
|
+
) -> Element | Elements:
|
|
101
|
+
if obj is None or obj is inspect.Parameter.empty:
|
|
102
|
+
raise TypeError(obj)
|
|
103
|
+
if isinstance(obj, _BANNED_BIND_TYPES):
|
|
104
|
+
raise TypeError(obj)
|
|
105
|
+
|
|
106
|
+
##
|
|
107
|
+
|
|
108
|
+
has_to = (
|
|
109
|
+
to_fn is not None or
|
|
110
|
+
to_ctor is not None or
|
|
111
|
+
to_const is not None or
|
|
112
|
+
to_key is not None
|
|
113
|
+
)
|
|
114
|
+
if isinstance(obj, Key):
|
|
115
|
+
key = obj
|
|
116
|
+
elif isinstance(obj, type):
|
|
117
|
+
if not has_to:
|
|
118
|
+
to_ctor = obj
|
|
119
|
+
key = Key(obj)
|
|
120
|
+
elif isinstance(obj, rfl.TYPES) or rfl.is_type(obj):
|
|
121
|
+
key = Key(obj)
|
|
122
|
+
elif _is_fn(obj) and not has_to:
|
|
123
|
+
sig = _inspect.signature(obj)
|
|
124
|
+
ty = rfl.type_(sig.return_annotation)
|
|
125
|
+
to_fn = obj
|
|
126
|
+
key = Key(ty)
|
|
127
|
+
else:
|
|
128
|
+
if to_const is not None:
|
|
129
|
+
raise TypeError('Cannot bind instance with to_const')
|
|
130
|
+
to_const = obj
|
|
131
|
+
key = Key(type(obj))
|
|
132
|
+
del has_to
|
|
133
|
+
|
|
134
|
+
##
|
|
135
|
+
|
|
136
|
+
if tag is not None:
|
|
137
|
+
if key.tag is not None:
|
|
138
|
+
raise TypeError('Tag already set')
|
|
139
|
+
key = dc.replace(key, tag=tag)
|
|
140
|
+
|
|
141
|
+
##
|
|
142
|
+
|
|
143
|
+
providers: list[Provider] = []
|
|
144
|
+
if to_fn is not None:
|
|
145
|
+
providers.append(FnProvider(to_fn))
|
|
146
|
+
if to_ctor is not None:
|
|
147
|
+
providers.append(CtorProvider(to_ctor))
|
|
148
|
+
if to_const is not None:
|
|
149
|
+
providers.append(ConstProvider(to_const))
|
|
150
|
+
if to_key is not None:
|
|
151
|
+
providers.append(LinkProvider(as_key(to_key)))
|
|
152
|
+
if not providers:
|
|
153
|
+
raise TypeError('Must specify provider')
|
|
154
|
+
if len(providers) > 1:
|
|
155
|
+
raise TypeError('May not specify multiple providers')
|
|
156
|
+
provider, = providers
|
|
157
|
+
|
|
158
|
+
##
|
|
159
|
+
|
|
160
|
+
scopes: list[Scope] = []
|
|
161
|
+
if in_ is not None:
|
|
162
|
+
if isinstance(in_, str):
|
|
163
|
+
scopes.append(SCOPE_ALIASES[in_])
|
|
164
|
+
else:
|
|
165
|
+
scopes.append(check.isinstance(in_, Scope))
|
|
166
|
+
if singleton:
|
|
167
|
+
scopes.append(Singleton())
|
|
168
|
+
if len(scopes) > 1:
|
|
169
|
+
raise TypeError('May not specify multiple scopes')
|
|
170
|
+
scope: Scope
|
|
171
|
+
if not scopes:
|
|
172
|
+
scope = Unscoped()
|
|
173
|
+
else:
|
|
174
|
+
scope, = scopes
|
|
175
|
+
|
|
176
|
+
##
|
|
177
|
+
|
|
178
|
+
binding = Binding(key, provider, scope)
|
|
179
|
+
|
|
180
|
+
##
|
|
6
181
|
|
|
182
|
+
elements: list[Element] = [binding]
|
|
7
183
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
184
|
+
if eager:
|
|
185
|
+
elements.append(Eager(key))
|
|
186
|
+
if expose:
|
|
187
|
+
elements.append(Expose(key))
|
|
11
188
|
|
|
12
|
-
|
|
189
|
+
if len(elements) == 1:
|
|
190
|
+
return elements[0]
|
|
191
|
+
else:
|
|
192
|
+
return Elements(frozenset(elements))
|