omlish 0.0.0.dev178__py3-none-any.whl → 0.0.0.dev180__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/argparse/all.py +3 -3
- omlish/argparse/cli.py +13 -13
- omlish/dataclasses/impl/hashing.py +2 -1
- omlish/http/coro/fdio.py +1 -1
- omlish/http/coro/server.py +2 -2
- omlish/http/handlers.py +1 -1
- omlish/inject/elements.py +8 -9
- omlish/io/fdio/handlers.py +1 -1
- omlish/lite/__init__.py +4 -0
- omlish/lite/inject.py +31 -30
- omlish/{lite/shlex.py → shlex.py} +1 -0
- omlish/sockets/__init__.py +0 -0
- omlish/{lite/socket.py → sockets/addresses.py} +1 -25
- omlish/sockets/handlers.py +30 -0
- omlish/{lite/socketserver.py → sockets/server.py} +3 -2
- omlish/text/minja.py +223 -0
- {omlish-0.0.0.dev178.dist-info → omlish-0.0.0.dev180.dist-info}/METADATA +1 -1
- {omlish-0.0.0.dev178.dist-info → omlish-0.0.0.dev180.dist-info}/RECORD +23 -20
- {omlish-0.0.0.dev178.dist-info → omlish-0.0.0.dev180.dist-info}/LICENSE +0 -0
- {omlish-0.0.0.dev178.dist-info → omlish-0.0.0.dev180.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev178.dist-info → omlish-0.0.0.dev180.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev178.dist-info → omlish-0.0.0.dev180.dist-info}/top_level.txt +0 -0
omlish/__about__.py
CHANGED
omlish/argparse/all.py
CHANGED
@@ -5,9 +5,9 @@ from .cli import ( # noqa
|
|
5
5
|
ArgparseArg as Arg,
|
6
6
|
argparse_arg as arg,
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
ArgparseCmdFn as CmdFn,
|
9
|
+
ArgparseCmd as Cmd,
|
10
|
+
argparse_cmd as cmd,
|
11
11
|
|
12
12
|
ArgparseCli as Cli,
|
13
13
|
)
|
omlish/argparse/cli.py
CHANGED
@@ -21,7 +21,7 @@ from ..lite.reflect import is_optional_alias
|
|
21
21
|
T = ta.TypeVar('T')
|
22
22
|
|
23
23
|
|
24
|
-
|
24
|
+
ArgparseCmdFn = ta.Callable[[], ta.Optional[int]] # ta.TypeAlias
|
25
25
|
|
26
26
|
|
27
27
|
##
|
@@ -47,15 +47,15 @@ def argparse_arg(*args, **kwargs) -> ArgparseArg:
|
|
47
47
|
|
48
48
|
|
49
49
|
@dc.dataclass(eq=False)
|
50
|
-
class
|
50
|
+
class ArgparseCmd:
|
51
51
|
name: str
|
52
|
-
fn:
|
52
|
+
fn: ArgparseCmdFn
|
53
53
|
args: ta.Sequence[ArgparseArg] = () # noqa
|
54
54
|
|
55
55
|
# _: dc.KW_ONLY
|
56
56
|
|
57
57
|
aliases: ta.Optional[ta.Sequence[str]] = None
|
58
|
-
parent: ta.Optional['
|
58
|
+
parent: ta.Optional['ArgparseCmd'] = None
|
59
59
|
accepts_unknown: bool = False
|
60
60
|
|
61
61
|
def __post_init__(self) -> None:
|
@@ -70,7 +70,7 @@ class ArgparseCommand:
|
|
70
70
|
|
71
71
|
check.arg(callable(self.fn))
|
72
72
|
check.arg(all(isinstance(a, ArgparseArg) for a in self.args))
|
73
|
-
check.isinstance(self.parent, (
|
73
|
+
check.isinstance(self.parent, (ArgparseCmd, type(None)))
|
74
74
|
check.isinstance(self.accepts_unknown, bool)
|
75
75
|
|
76
76
|
functools.update_wrapper(self, self.fn)
|
@@ -84,21 +84,21 @@ class ArgparseCommand:
|
|
84
84
|
return self.fn(*args, **kwargs)
|
85
85
|
|
86
86
|
|
87
|
-
def
|
87
|
+
def argparse_cmd(
|
88
88
|
*args: ArgparseArg,
|
89
89
|
name: ta.Optional[str] = None,
|
90
90
|
aliases: ta.Optional[ta.Iterable[str]] = None,
|
91
|
-
parent: ta.Optional[
|
91
|
+
parent: ta.Optional[ArgparseCmd] = None,
|
92
92
|
accepts_unknown: bool = False,
|
93
|
-
) -> ta.Any: # ta.Callable[[
|
93
|
+
) -> ta.Any: # ta.Callable[[ArgparseCmdFn], ArgparseCmd]: # FIXME
|
94
94
|
for arg in args:
|
95
95
|
check.isinstance(arg, ArgparseArg)
|
96
96
|
check.isinstance(name, (str, type(None)))
|
97
|
-
check.isinstance(parent, (
|
97
|
+
check.isinstance(parent, (ArgparseCmd, type(None)))
|
98
98
|
check.not_isinstance(aliases, str)
|
99
99
|
|
100
100
|
def inner(fn):
|
101
|
-
return
|
101
|
+
return ArgparseCmd(
|
102
102
|
(name if name is not None else fn.__name__).replace('_', '-'),
|
103
103
|
fn,
|
104
104
|
args,
|
@@ -153,7 +153,7 @@ class ArgparseCli:
|
|
153
153
|
for bns in [bcls.__dict__ for bcls in reversed(mro)] + [ns]:
|
154
154
|
bseen = set() # type: ignore
|
155
155
|
for k, v in bns.items():
|
156
|
-
if isinstance(v, (
|
156
|
+
if isinstance(v, (ArgparseCmd, ArgparseArg)):
|
157
157
|
check.not_in(v, bseen)
|
158
158
|
bseen.add(v)
|
159
159
|
objs[k] = v
|
@@ -180,7 +180,7 @@ class ArgparseCli:
|
|
180
180
|
subparsers = parser.add_subparsers()
|
181
181
|
|
182
182
|
for att, obj in objs.items():
|
183
|
-
if isinstance(obj,
|
183
|
+
if isinstance(obj, ArgparseCmd):
|
184
184
|
if obj.parent is not None:
|
185
185
|
raise NotImplementedError
|
186
186
|
|
@@ -242,7 +242,7 @@ class ArgparseCli:
|
|
242
242
|
|
243
243
|
#
|
244
244
|
|
245
|
-
def _bind_cli_cmd(self, cmd:
|
245
|
+
def _bind_cli_cmd(self, cmd: ArgparseCmd) -> ta.Callable:
|
246
246
|
return cmd.__get__(self, type(self))
|
247
247
|
|
248
248
|
def prepare_cli_run(self) -> ta.Optional[ta.Callable]:
|
@@ -50,7 +50,8 @@ class HashProcessor(Processor):
|
|
50
50
|
if self._info.params_extras.cache_hash:
|
51
51
|
body = [
|
52
52
|
f'try: return self.{self.CACHED_HASH_ATTR}',
|
53
|
-
f'except AttributeError:
|
53
|
+
f'except AttributeError: pass',
|
54
|
+
f'object.__setattr__(self, {self.CACHED_HASH_ATTR!r}, h := hash({self_tuple}))',
|
54
55
|
f'return h',
|
55
56
|
]
|
56
57
|
else:
|
omlish/http/coro/fdio.py
CHANGED
@@ -7,7 +7,7 @@ from ...io.buffers import IncrementalWriteBuffer
|
|
7
7
|
from ...io.buffers import ReadableListBuffer
|
8
8
|
from ...io.fdio.handlers import SocketFdioHandler
|
9
9
|
from ...lite.check import check
|
10
|
-
from ...
|
10
|
+
from ...sockets.addresses import SocketAddress
|
11
11
|
from ..handlers import HttpHandler
|
12
12
|
from .server import CoroHttpServer
|
13
13
|
|
omlish/http/coro/server.py
CHANGED
@@ -64,8 +64,8 @@ import time
|
|
64
64
|
import typing as ta
|
65
65
|
|
66
66
|
from ...lite.check import check
|
67
|
-
from ...
|
68
|
-
from ...
|
67
|
+
from ...sockets.addresses import SocketAddress
|
68
|
+
from ...sockets.handlers import SocketHandler
|
69
69
|
from ..handlers import HttpHandler
|
70
70
|
from ..handlers import HttpHandlerRequest
|
71
71
|
from ..handlers import UnsupportedMethodHttpHandlerError
|
omlish/http/handlers.py
CHANGED
omlish/inject/elements.py
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
import abc
|
2
2
|
import typing as ta
|
3
3
|
|
4
|
-
from .. import check
|
5
4
|
from .. import dataclasses as dc
|
6
5
|
from .. import lang
|
7
6
|
from .impl.origins import HasOriginsImpl
|
@@ -19,8 +18,8 @@ class ElementGenerator(lang.Abstract, lang.PackageSealed):
|
|
19
18
|
|
20
19
|
@dc.dataclass(frozen=True)
|
21
20
|
class Elements(lang.Final):
|
22
|
-
es:
|
23
|
-
cs:
|
21
|
+
es: ta.Collection[Element] | None = None
|
22
|
+
cs: ta.Collection['Elements'] | None = None
|
24
23
|
|
25
24
|
def __iter__(self) -> ta.Generator[Element, None, None]:
|
26
25
|
if self.es:
|
@@ -38,14 +37,14 @@ Elemental = ta.Union[ # noqa
|
|
38
37
|
|
39
38
|
|
40
39
|
def as_elements(*args: Elemental) -> Elements:
|
41
|
-
es:
|
42
|
-
cs:
|
40
|
+
es: list[Element] = []
|
41
|
+
cs: list[Elements] = []
|
43
42
|
|
44
43
|
def rec(a):
|
45
44
|
if isinstance(a, Element):
|
46
|
-
es.
|
45
|
+
es.append(a)
|
47
46
|
elif isinstance(a, Elements):
|
48
|
-
cs.
|
47
|
+
cs.append(a)
|
49
48
|
elif isinstance(a, ElementGenerator):
|
50
49
|
for n in a:
|
51
50
|
rec(n)
|
@@ -59,6 +58,6 @@ def as_elements(*args: Elemental) -> Elements:
|
|
59
58
|
return next(iter(cs))
|
60
59
|
|
61
60
|
return Elements(
|
62
|
-
|
63
|
-
|
61
|
+
es if es else None,
|
62
|
+
cs if cs else None,
|
64
63
|
)
|
omlish/io/fdio/handlers.py
CHANGED
omlish/lite/__init__.py
CHANGED
omlish/lite/inject.py
CHANGED
@@ -291,30 +291,6 @@ def as_injector_bindings(*args: InjectorBindingOrBindings) -> InjectorBindings:
|
|
291
291
|
##
|
292
292
|
|
293
293
|
|
294
|
-
@dc.dataclass(frozen=True)
|
295
|
-
class OverridesInjectorBindings(InjectorBindings):
|
296
|
-
p: InjectorBindings
|
297
|
-
m: ta.Mapping[InjectorKey, InjectorBinding]
|
298
|
-
|
299
|
-
def bindings(self) -> ta.Iterator[InjectorBinding]:
|
300
|
-
for b in self.p.bindings():
|
301
|
-
yield self.m.get(b.key, b)
|
302
|
-
|
303
|
-
|
304
|
-
def injector_override(p: InjectorBindings, *args: InjectorBindingOrBindings) -> InjectorBindings:
|
305
|
-
m: ta.Dict[InjectorKey, InjectorBinding] = {}
|
306
|
-
|
307
|
-
for b in as_injector_bindings(*args).bindings():
|
308
|
-
if b.key in m:
|
309
|
-
raise DuplicateInjectorKeyError(b.key)
|
310
|
-
m[b.key] = b
|
311
|
-
|
312
|
-
return OverridesInjectorBindings(p, m)
|
313
|
-
|
314
|
-
|
315
|
-
##
|
316
|
-
|
317
|
-
|
318
294
|
def build_injector_provider_map(bs: InjectorBindings) -> ta.Mapping[InjectorKey, InjectorProvider]:
|
319
295
|
pm: ta.Dict[InjectorKey, InjectorProvider] = {}
|
320
296
|
am: ta.Dict[InjectorKey, ta.List[InjectorProvider]] = {}
|
@@ -338,6 +314,31 @@ def build_injector_provider_map(bs: InjectorBindings) -> ta.Mapping[InjectorKey,
|
|
338
314
|
return pm
|
339
315
|
|
340
316
|
|
317
|
+
###
|
318
|
+
# overrides
|
319
|
+
|
320
|
+
|
321
|
+
@dc.dataclass(frozen=True)
|
322
|
+
class OverridesInjectorBindings(InjectorBindings):
|
323
|
+
p: InjectorBindings
|
324
|
+
m: ta.Mapping[InjectorKey, InjectorBinding]
|
325
|
+
|
326
|
+
def bindings(self) -> ta.Iterator[InjectorBinding]:
|
327
|
+
for b in self.p.bindings():
|
328
|
+
yield self.m.get(b.key, b)
|
329
|
+
|
330
|
+
|
331
|
+
def injector_override(p: InjectorBindings, *args: InjectorBindingOrBindings) -> InjectorBindings:
|
332
|
+
m: ta.Dict[InjectorKey, InjectorBinding] = {}
|
333
|
+
|
334
|
+
for b in as_injector_bindings(*args).bindings():
|
335
|
+
if b.key in m:
|
336
|
+
raise DuplicateInjectorKeyError(b.key)
|
337
|
+
m[b.key] = b
|
338
|
+
|
339
|
+
return OverridesInjectorBindings(p, m)
|
340
|
+
|
341
|
+
|
341
342
|
###
|
342
343
|
# scopes
|
343
344
|
|
@@ -362,7 +363,7 @@ class InjectorScope(abc.ABC): # noqa
|
|
362
363
|
@dc.dataclass(frozen=True)
|
363
364
|
class State:
|
364
365
|
seeds: ta.Dict[InjectorKey, ta.Any]
|
365
|
-
|
366
|
+
provisions: ta.Dict[InjectorKey, ta.Any] = dc.field(default_factory=dict)
|
366
367
|
|
367
368
|
def new_state(self, vs: ta.Mapping[InjectorKey, ta.Any]) -> State:
|
368
369
|
vs = dict(vs)
|
@@ -442,11 +443,11 @@ class ScopedInjectorProvider(InjectorProvider):
|
|
442
443
|
def pfn(i: Injector) -> ta.Any:
|
443
444
|
st = i[self.sc].state()
|
444
445
|
try:
|
445
|
-
return st.
|
446
|
+
return st.provisions[self.k]
|
446
447
|
except KeyError:
|
447
448
|
pass
|
448
449
|
v = ufn(i)
|
449
|
-
st.
|
450
|
+
st.provisions[self.k] = v
|
450
451
|
return v
|
451
452
|
|
452
453
|
ufn = self.p.provider_fn()
|
@@ -470,9 +471,7 @@ class _ScopeSeedInjectorProvider(InjectorProvider):
|
|
470
471
|
|
471
472
|
|
472
473
|
def bind_injector_scope(sc: ta.Type[InjectorScope]) -> InjectorBindingOrBindings:
|
473
|
-
return
|
474
|
-
InjectorBinder.bind(sc, singleton=True),
|
475
|
-
)
|
474
|
+
return InjectorBinder.bind(sc, singleton=True)
|
476
475
|
|
477
476
|
|
478
477
|
#
|
@@ -1012,6 +1011,8 @@ class InjectionApi:
|
|
1012
1011
|
def as_bindings(self, *args: InjectorBindingOrBindings) -> InjectorBindings:
|
1013
1012
|
return as_injector_bindings(*args)
|
1014
1013
|
|
1014
|
+
# overrides
|
1015
|
+
|
1015
1016
|
def override(self, p: InjectorBindings, *args: InjectorBindingOrBindings) -> InjectorBindings:
|
1016
1017
|
return injector_override(p, *args)
|
1017
1018
|
|
File without changes
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# ruff: noqa: UP006 UP007
|
2
|
+
# @omlish-lite
|
2
3
|
"""
|
3
4
|
TODO:
|
4
5
|
- SocketClientAddress family / tuple pairs
|
5
6
|
+ codification of https://docs.python.org/3/library/socket.html#socket-families
|
6
7
|
"""
|
7
|
-
import abc
|
8
8
|
import dataclasses as dc
|
9
9
|
import socket
|
10
10
|
import typing as ta
|
@@ -13,9 +13,6 @@ import typing as ta
|
|
13
13
|
SocketAddress = ta.Any
|
14
14
|
|
15
15
|
|
16
|
-
SocketHandlerFactory = ta.Callable[[SocketAddress, ta.BinaryIO, ta.BinaryIO], 'SocketHandler']
|
17
|
-
|
18
|
-
|
19
16
|
##
|
20
17
|
|
21
18
|
|
@@ -54,24 +51,3 @@ def get_best_socket_family(
|
|
54
51
|
)
|
55
52
|
ai = SocketAddressInfo(*next(iter(infos)))
|
56
53
|
return ai.family, ai.sockaddr
|
57
|
-
|
58
|
-
|
59
|
-
##
|
60
|
-
|
61
|
-
|
62
|
-
class SocketHandler(abc.ABC):
|
63
|
-
def __init__(
|
64
|
-
self,
|
65
|
-
client_address: SocketAddress,
|
66
|
-
rfile: ta.BinaryIO,
|
67
|
-
wfile: ta.BinaryIO,
|
68
|
-
) -> None:
|
69
|
-
super().__init__()
|
70
|
-
|
71
|
-
self._client_address = client_address
|
72
|
-
self._rfile = rfile
|
73
|
-
self._wfile = wfile
|
74
|
-
|
75
|
-
@abc.abstractmethod
|
76
|
-
def handle(self) -> None:
|
77
|
-
raise NotImplementedError
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
2
|
+
# @omlish-lite
|
3
|
+
import abc
|
4
|
+
import typing as ta
|
5
|
+
|
6
|
+
from .addresses import SocketAddress
|
7
|
+
|
8
|
+
|
9
|
+
SocketHandlerFactory = ta.Callable[[SocketAddress, ta.BinaryIO, ta.BinaryIO], 'SocketHandler']
|
10
|
+
|
11
|
+
|
12
|
+
##
|
13
|
+
|
14
|
+
|
15
|
+
class SocketHandler(abc.ABC):
|
16
|
+
def __init__(
|
17
|
+
self,
|
18
|
+
client_address: SocketAddress,
|
19
|
+
rfile: ta.BinaryIO,
|
20
|
+
wfile: ta.BinaryIO,
|
21
|
+
) -> None:
|
22
|
+
super().__init__()
|
23
|
+
|
24
|
+
self._client_address = client_address
|
25
|
+
self._rfile = rfile
|
26
|
+
self._wfile = wfile
|
27
|
+
|
28
|
+
@abc.abstractmethod
|
29
|
+
def handle(self) -> None:
|
30
|
+
raise NotImplementedError
|
@@ -1,12 +1,13 @@
|
|
1
1
|
# ruff: noqa: UP006 UP007
|
2
|
+
# @omlish-lite
|
2
3
|
import socket
|
3
4
|
import socketserver
|
4
5
|
import typing as ta
|
5
6
|
|
6
7
|
from omlish.lite.check import check
|
7
8
|
|
8
|
-
from .
|
9
|
-
from .
|
9
|
+
from .addresses import SocketAddress
|
10
|
+
from .handlers import SocketHandlerFactory
|
10
11
|
|
11
12
|
|
12
13
|
##
|
omlish/text/minja.py
ADDED
@@ -0,0 +1,223 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
2
|
+
# @omlish-lite
|
3
|
+
"""
|
4
|
+
TODO:
|
5
|
+
- raw
|
6
|
+
- blocks / inheritance
|
7
|
+
"""
|
8
|
+
import io
|
9
|
+
import re
|
10
|
+
import typing as ta
|
11
|
+
|
12
|
+
from omlish.lite.cached import cached_nullary
|
13
|
+
from omlish.lite.check import check
|
14
|
+
|
15
|
+
|
16
|
+
##
|
17
|
+
|
18
|
+
|
19
|
+
class MinjaTemplate:
|
20
|
+
def __init__(self, fn: ta.Callable) -> None:
|
21
|
+
super().__init__()
|
22
|
+
|
23
|
+
self._fn = fn
|
24
|
+
|
25
|
+
def __call__(self, **kwargs: ta.Any) -> str:
|
26
|
+
return self._fn(**kwargs)
|
27
|
+
|
28
|
+
|
29
|
+
##
|
30
|
+
|
31
|
+
|
32
|
+
class MinjaTemplateCompiler:
|
33
|
+
"""
|
34
|
+
Compiles a template string into a Python function. The returned function takes a dictionary 'context' and returns
|
35
|
+
the rendered string.
|
36
|
+
|
37
|
+
Supported syntax:
|
38
|
+
- Literal text remains literal.
|
39
|
+
- {{ expr }}: Evaluates 'expr' in the given context and writes its str() to output.
|
40
|
+
- {% code %}: Executes the given Python code (e.g. 'for x in items:'), must be terminated appropriately.
|
41
|
+
- {% endfor %} to close for loops.
|
42
|
+
- {% endif %} to close if blocks.
|
43
|
+
- {# comment #}: Ignored completely.
|
44
|
+
"""
|
45
|
+
|
46
|
+
DEFAULT_INDENT: str = ' '
|
47
|
+
|
48
|
+
def __init__(
|
49
|
+
self,
|
50
|
+
src: str,
|
51
|
+
args: ta.Sequence[str],
|
52
|
+
*,
|
53
|
+
indent: str = DEFAULT_INDENT,
|
54
|
+
) -> None:
|
55
|
+
super().__init__()
|
56
|
+
|
57
|
+
self._src = check.isinstance(src, str)
|
58
|
+
self._args = check.not_isinstance(args, str)
|
59
|
+
self._indent_str: str = check.non_empty_str(indent)
|
60
|
+
|
61
|
+
self._stack: ta.List[ta.Literal['for', 'if']] = []
|
62
|
+
self._lines: ta.List[str] = []
|
63
|
+
|
64
|
+
#
|
65
|
+
|
66
|
+
_TAG_PAT = re.compile(
|
67
|
+
r'({{.*?}}|{%.*?%}|{#.*?#})',
|
68
|
+
flags=re.DOTALL,
|
69
|
+
)
|
70
|
+
|
71
|
+
@classmethod
|
72
|
+
def _split_tags(cls, src: str) -> ta.List[ta.Tuple[str, str]]:
|
73
|
+
raw = cls._TAG_PAT.split(src)
|
74
|
+
|
75
|
+
#
|
76
|
+
|
77
|
+
parts: ta.List[ta.Tuple[str, str]] = []
|
78
|
+
for s in raw:
|
79
|
+
if not s:
|
80
|
+
continue
|
81
|
+
|
82
|
+
for g, l, r in [
|
83
|
+
('{', '{{', '}}'),
|
84
|
+
('%', '{%', '%}'),
|
85
|
+
('#', '{#', '#}'),
|
86
|
+
]:
|
87
|
+
if s.startswith(l) and s.endswith(r):
|
88
|
+
parts.append((g, s[len(l):-len(r)]))
|
89
|
+
break
|
90
|
+
else:
|
91
|
+
parts.append(('', s))
|
92
|
+
|
93
|
+
#
|
94
|
+
|
95
|
+
for i, (g, s) in enumerate(parts):
|
96
|
+
if s.startswith('-'):
|
97
|
+
if i > 0:
|
98
|
+
lg, ls = parts[i - 1]
|
99
|
+
parts[i - 1] = (lg, ls.rstrip())
|
100
|
+
s = s[1:].lstrip()
|
101
|
+
|
102
|
+
if s.endswith('-'):
|
103
|
+
if i < len(parts) - 1:
|
104
|
+
rg, rs = parts[i + 1]
|
105
|
+
parts[i + 1] = (rg, rs.lstrip())
|
106
|
+
s = s[:-1].rstrip()
|
107
|
+
|
108
|
+
parts[i] = (g, s)
|
109
|
+
|
110
|
+
#
|
111
|
+
|
112
|
+
parts = [(g, s) for g, s in parts if g or s]
|
113
|
+
|
114
|
+
#
|
115
|
+
|
116
|
+
return parts
|
117
|
+
|
118
|
+
#
|
119
|
+
|
120
|
+
def _indent(self, line: str, ofs: int = 0) -> str:
|
121
|
+
return self._indent_str * (len(self._stack) + 1 + ofs) + line
|
122
|
+
|
123
|
+
#
|
124
|
+
|
125
|
+
_RENDER_FN_NAME = '__render'
|
126
|
+
|
127
|
+
@cached_nullary
|
128
|
+
def render(self) -> ta.Tuple[str, ta.Mapping[str, ta.Any]]:
|
129
|
+
parts = self._split_tags(self._src)
|
130
|
+
|
131
|
+
self._lines.append(f'def {self._RENDER_FN_NAME}({", ".join(self._args)}):')
|
132
|
+
self._lines.append(self._indent('__output = __StringIO()'))
|
133
|
+
|
134
|
+
for g, s in parts:
|
135
|
+
if g == '{':
|
136
|
+
expr = s.strip()
|
137
|
+
self._lines.append(self._indent(f'__output.write(str({expr}))'))
|
138
|
+
|
139
|
+
elif g == '%':
|
140
|
+
stmt = s.strip()
|
141
|
+
|
142
|
+
if stmt.startswith('for '):
|
143
|
+
self._lines.append(self._indent(stmt + ':'))
|
144
|
+
self._stack.append('for')
|
145
|
+
elif stmt.startswith('endfor'):
|
146
|
+
check.equal(self._stack.pop(), 'for')
|
147
|
+
|
148
|
+
elif stmt.startswith('if '):
|
149
|
+
self._lines.append(self._indent(stmt + ':'))
|
150
|
+
self._stack.append('if')
|
151
|
+
elif stmt.startswith('elif '):
|
152
|
+
check.equal(self._stack[-1], 'if')
|
153
|
+
self._lines.append(self._indent(stmt + ':', -1))
|
154
|
+
elif stmt.strip() == 'else':
|
155
|
+
check.equal(self._stack[-1], 'if')
|
156
|
+
self._lines.append(self._indent('else:', -1))
|
157
|
+
elif stmt.startswith('endif'):
|
158
|
+
check.equal(self._stack.pop(), 'if')
|
159
|
+
|
160
|
+
else:
|
161
|
+
self._lines.append(self._indent(stmt))
|
162
|
+
|
163
|
+
elif g == '#':
|
164
|
+
pass
|
165
|
+
|
166
|
+
elif not g:
|
167
|
+
if s:
|
168
|
+
safe_text = s.replace('"""', '\\"""')
|
169
|
+
self._lines.append(self._indent(f'__output.write("""{safe_text}""")'))
|
170
|
+
|
171
|
+
else:
|
172
|
+
raise KeyError(g)
|
173
|
+
|
174
|
+
check.empty(self._stack)
|
175
|
+
|
176
|
+
self._lines.append(self._indent('return __output.getvalue()'))
|
177
|
+
|
178
|
+
ns = {
|
179
|
+
'__StringIO': io.StringIO,
|
180
|
+
}
|
181
|
+
|
182
|
+
return ('\n'.join(self._lines), ns)
|
183
|
+
|
184
|
+
#
|
185
|
+
|
186
|
+
@classmethod
|
187
|
+
def _make_fn(
|
188
|
+
cls,
|
189
|
+
name: str,
|
190
|
+
src: str,
|
191
|
+
ns: ta.Optional[ta.Mapping[str, ta.Any]] = None,
|
192
|
+
) -> ta.Callable:
|
193
|
+
glo: dict = {}
|
194
|
+
if ns:
|
195
|
+
glo.update(ns)
|
196
|
+
exec(src, glo)
|
197
|
+
return glo[name]
|
198
|
+
|
199
|
+
#
|
200
|
+
|
201
|
+
@cached_nullary
|
202
|
+
def compile(self) -> MinjaTemplate:
|
203
|
+
render_src, render_ns = self.render()
|
204
|
+
|
205
|
+
render_fn = self._make_fn(
|
206
|
+
self._RENDER_FN_NAME,
|
207
|
+
render_src,
|
208
|
+
render_ns,
|
209
|
+
)
|
210
|
+
|
211
|
+
return MinjaTemplate(render_fn)
|
212
|
+
|
213
|
+
|
214
|
+
##
|
215
|
+
|
216
|
+
|
217
|
+
def compile_minja_template(src: str, args: ta.Sequence[str] = ()) -> MinjaTemplate:
|
218
|
+
return MinjaTemplateCompiler(src, args).compile()
|
219
|
+
|
220
|
+
|
221
|
+
def render_minja_template(src: str, **kwargs: ta.Any) -> str:
|
222
|
+
tmpl = compile_minja_template(src, list(kwargs))
|
223
|
+
return tmpl(**kwargs)
|
@@ -1,5 +1,5 @@
|
|
1
1
|
omlish/.manifests.json,sha256=lRkBDFxlAbf6lN5upo3WSf-owW8YG1T21dfpbQL-XHM,7598
|
2
|
-
omlish/__about__.py,sha256=
|
2
|
+
omlish/__about__.py,sha256=7vMVy87ffE8iOF0eMquVWoGR2M295AJLJjSOvuDvPAg,3409
|
3
3
|
omlish/__init__.py,sha256=SsyiITTuK0v74XpKV8dqNaCmjOlan1JZKrHQv5rWKPA,253
|
4
4
|
omlish/c3.py,sha256=ubu7lHwss5V4UznbejAI0qXhXahrU01MysuHOZI9C4U,8116
|
5
5
|
omlish/cached.py,sha256=UI-XTFBwA6YXWJJJeBn-WkwBkfzDjLBBaZf4nIJA9y0,510
|
@@ -10,6 +10,7 @@ omlish/dynamic.py,sha256=35C_cCX_Vq2HrHzGk5T-zbrMvmUdiIiwDzDNixczoDo,6541
|
|
10
10
|
omlish/libc.py,sha256=8r7Ejyhttk9ruCfBkxNTrlzir5WPbDE2vmY7VPlceMA,15362
|
11
11
|
omlish/multiprocessing.py,sha256=QZT4C7I-uThCAjaEY3xgUYb-5GagUlnE4etN01LDyU4,5186
|
12
12
|
omlish/runmodule.py,sha256=PWvuAaJ9wQQn6bx9ftEL3_d04DyotNn8dR_twm2pgw0,700
|
13
|
+
omlish/shlex.py,sha256=bsW2XUD8GiMTUTDefJejZ5AyqT1pTgWMPD0BMoF02jE,248
|
13
14
|
omlish/subprocesses.py,sha256=n6pk0nUaTFHzD_A6duyKNJ4ggncU7uNepfh_T90etHE,8671
|
14
15
|
omlish/sync.py,sha256=QJ79kxmIqDP9SeHDoZAf--DpFIhDQe1jACy8H4N0yZI,2928
|
15
16
|
omlish/term.py,sha256=EVHm3lEEIc9hT4f8BPmzbNUwlqZ8nrRpCwyQMN7LBm0,9313
|
@@ -82,8 +83,8 @@ omlish/antlr/_runtime/xpath/XPath.py,sha256=KSL1SH3VAeRDZCe4dAD7xmUdfk-j434ypZKR
|
|
82
83
|
omlish/antlr/_runtime/xpath/XPathLexer.py,sha256=WvGKQjQnu7pX5C4CFKtsCzba2B2W6ie4ivtWLvlgymM,3509
|
83
84
|
omlish/antlr/_runtime/xpath/__init__.py,sha256=lMd_BbXYdlDhZQN_q0TKN978XW5G0pq618F0NaLkpFE,71
|
84
85
|
omlish/argparse/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
85
|
-
omlish/argparse/all.py,sha256=
|
86
|
-
omlish/argparse/cli.py,sha256=
|
86
|
+
omlish/argparse/all.py,sha256=2qhVgFTq3w_tJ_okEnw_D-2k4jlJD7EcM5hNEow6M2M,1030
|
87
|
+
omlish/argparse/cli.py,sha256=Kjq3bzd_E2XwV0T7-cddDdrm68N4AWptTKdJty8vN8g,8217
|
87
88
|
omlish/asyncs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
88
89
|
omlish/asyncs/all.py,sha256=uUz9ziKh4_QrgmdhKFMgq6j7mFbiZd3LiogguDCQsGI,587
|
89
90
|
omlish/asyncs/anyio.py,sha256=gfpx-D8QGmUfhnQxHEaHXcAP8zSMQjcGw4COFTGNnHI,8021
|
@@ -164,7 +165,7 @@ omlish/dataclasses/impl/descriptors.py,sha256=rEYE1Len99agTQCC25hSPMnM19BgPr0ZCh
|
|
164
165
|
omlish/dataclasses/impl/exceptions.py,sha256=-vqxZmfXVflymVuiM553XTlJProse5HEMktTpfdPCIY,1275
|
165
166
|
omlish/dataclasses/impl/fields.py,sha256=4_5qMz9LlOS6U67cDKQ-oorTtSGGxR77I4hw88soM44,6878
|
166
167
|
omlish/dataclasses/impl/frozen.py,sha256=x87DSM8FIMZ3c_BIUE8NooCkExFjPsabeqIueEP5qKs,2988
|
167
|
-
omlish/dataclasses/impl/hashing.py,sha256=
|
168
|
+
omlish/dataclasses/impl/hashing.py,sha256=0Gr6XIRkKy4pr-mdHblIlQCy3mBxycjMqJk3oZDw43s,3215
|
168
169
|
omlish/dataclasses/impl/init.py,sha256=5kYcMDlI6EVeLQ6RCTk1bvYjb-cwg0AYfVE9FPZJlYI,6365
|
169
170
|
omlish/dataclasses/impl/internals.py,sha256=UvZYjrLT1S8ntyxJ_vRPIkPOF00K8HatGAygErgoXTU,2990
|
170
171
|
omlish/dataclasses/impl/main.py,sha256=Ti0PKbFKraKvfmoPuR-G7nLVNzRC8mvEuXhCuC-M2kc,2574
|
@@ -265,7 +266,7 @@ omlish/http/consts.py,sha256=7BJ4D1MdIvqBcepkgCfBFHolgTwbOlqsOEiee_IjxOA,2289
|
|
265
266
|
omlish/http/cookies.py,sha256=uuOYlHR6e2SC3GM41V0aozK10nef9tYg83Scqpn5-HM,6351
|
266
267
|
omlish/http/dates.py,sha256=Otgp8wRxPgNGyzx8LFowu1vC4EKJYARCiAwLFncpfHM,2875
|
267
268
|
omlish/http/encodings.py,sha256=w2WoKajpaZnQH8j-IBvk5ZFL2O2pAU_iBvZnkocaTlw,164
|
268
|
-
omlish/http/handlers.py,sha256=
|
269
|
+
omlish/http/handlers.py,sha256=2bKw7XRM11C0VSx-DStKa6exFKNINKK4jZ3uVUVh5d8,795
|
269
270
|
omlish/http/headers.py,sha256=ZMmjrEiYjzo0YTGyK0YsvjdwUazktGqzVVYorY4fd44,5081
|
270
271
|
omlish/http/json.py,sha256=9XwAsl4966Mxrv-1ytyCqhcE6lbBJw-0_tFZzGszgHE,7440
|
271
272
|
omlish/http/jwt.py,sha256=6Rigk1WrJ059DY4jDIKnxjnChWb7aFdermj2AI2DSvk,4346
|
@@ -276,13 +277,13 @@ omlish/http/sse.py,sha256=MDs9RvxQXoQliImcc6qK1ERajEYM7Q1l8xmr-9ceNBc,2315
|
|
276
277
|
omlish/http/versions.py,sha256=wSiOXPiClVjkVgSU_VmxkoD1SUYGaoPbP0U5Aw-Ufg8,409
|
277
278
|
omlish/http/wsgi.py,sha256=czZsVUX-l2YTlMrUjKN49wRoP4rVpS0qpeBn4O5BoMY,948
|
278
279
|
omlish/http/coro/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
279
|
-
omlish/http/coro/fdio.py,sha256=
|
280
|
-
omlish/http/coro/server.py,sha256
|
280
|
+
omlish/http/coro/fdio.py,sha256=ajj_lekRockGwQEw8m_mi6RO9-o6hnC9ITiwtZe3y-s,4017
|
281
|
+
omlish/http/coro/server.py,sha256=-e-J5pPqPDGrvQkwcukwltOjTbTNatiCx9Rl7FvooTI,18071
|
281
282
|
omlish/inject/__init__.py,sha256=n0RC9UDGsBQQ39cST39-XJqJPq2M0tnnh9yJubW9azo,1891
|
282
283
|
omlish/inject/binder.py,sha256=DAbc8TZi5w8Mna0TUtq0mT4jeDVA7i7SlBtOFrh2swc,4185
|
283
284
|
omlish/inject/bindings.py,sha256=pLXn2U3kvmAS-68IOG-tr77DbiI-wp9hGyy4lhG6_H8,525
|
284
285
|
omlish/inject/eagers.py,sha256=5AkGYuwijG0ihsH9NSaZotggalJ5_xWXhHE9mkn6IBA,329
|
285
|
-
omlish/inject/elements.py,sha256=
|
286
|
+
omlish/inject/elements.py,sha256=npppGgYBQja0oPHkdBDmRhpm3md1mZT1FVcIQ--W2qI,1398
|
286
287
|
omlish/inject/exceptions.py,sha256=_wkN2tF55gQzmMOMKJC_9jYHBZzaBiCDcyqI9Sf2UZs,626
|
287
288
|
omlish/inject/injector.py,sha256=CoCUeMm1Oot4sG4Ti1sKCWrhlvtJ5QAeAI22AFWu2RQ,1066
|
288
289
|
omlish/inject/inspect.py,sha256=tw49r1RJVHrEHmT8WWA3_Bl9Z0L3lEGRqlLhbM5OmAM,592
|
@@ -327,7 +328,7 @@ omlish/io/compress/snappy.py,sha256=JFoH_9l0Tr9AGaQ0jHRiP4TsFnG071l27mprCBcqt4c,
|
|
327
328
|
omlish/io/compress/zlib.py,sha256=BQ0BvX-wEN-0NwktcqFECYHTGwVe-VHCVCNarspGQ8o,2396
|
328
329
|
omlish/io/compress/zstd.py,sha256=wik_HWLq_8fGAJgGyMGq9fhFQovot1aCH4lwMpihQmg,949
|
329
330
|
omlish/io/fdio/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
|
330
|
-
omlish/io/fdio/handlers.py,sha256=
|
331
|
+
omlish/io/fdio/handlers.py,sha256=VDPEff3yXPnCj2jZEkrzuI42bKC8wD8fLmOG97hKrgo,1350
|
331
332
|
omlish/io/fdio/kqueue.py,sha256=YgGBQibkAUYODYDiGl7Enjtx1oQsJXuDsBLBXgqlLQw,3832
|
332
333
|
omlish/io/fdio/manager.py,sha256=q4wWf7nKrNtjx6yPEvrVnFt4UtK_BTvVlquEGw7poEo,1250
|
333
334
|
omlish/io/fdio/pollers.py,sha256=yNadAt3W5wd90PFmd3vD77bq5QwoVb2A6SM2JjZpKRs,5507
|
@@ -374,12 +375,12 @@ omlish/lifecycles/controller.py,sha256=ToYNJKH1Mxr7HyyF1cJrrec8NV_m84jrcvTMX0V5e
|
|
374
375
|
omlish/lifecycles/manager.py,sha256=Au66KaO-fI-SEJALaPUJsCHYW2GE20xextk1wKn2BEU,5445
|
375
376
|
omlish/lifecycles/states.py,sha256=zqMOU2ZU-MDNnWuwauM3_anIAiXM8LoBDElDEraptFg,1292
|
376
377
|
omlish/lifecycles/transitions.py,sha256=qQtFby-h4VzbvgaUqT2NnbNumlcOx9FVVADP9t83xj4,1939
|
377
|
-
omlish/lite/__init__.py,sha256=
|
378
|
+
omlish/lite/__init__.py,sha256=ISLhM4q0LR1XXTCaHdZOZxBRyIsoZqYm4u0bf1BPcVk,148
|
378
379
|
omlish/lite/cached.py,sha256=O7ozcoDNFm1Hg2wtpHEqYSp_i_nCLNOP6Ueq_Uk-7mU,1300
|
379
380
|
omlish/lite/check.py,sha256=0PD-GKtaDqDX6jU5KbzbMvH-vl6jH82xgYfplmfTQkg,12941
|
380
381
|
omlish/lite/contextmanagers.py,sha256=m9JO--p7L7mSl4cycXysH-1AO27weDKjP3DZG61cwwM,1683
|
381
382
|
omlish/lite/dataclasses.py,sha256=M6UD4VwGo0Ky7RNzKWbO0IOy7iBZVCIbTiC6EYbFnX8,1035
|
382
|
-
omlish/lite/inject.py,sha256=
|
383
|
+
omlish/lite/inject.py,sha256=qBUftFeXMiRgANYbNS2e7TePMYyFAcuLgsJiLyMTW5o,28769
|
383
384
|
omlish/lite/json.py,sha256=7-02Ny4fq-6YAu5ynvqoijhuYXWpLmfCI19GUeZnb1c,740
|
384
385
|
omlish/lite/logs.py,sha256=CWFG0NKGhqNeEgryF5atN2gkPYbUdTINEw_s1phbINM,51
|
385
386
|
omlish/lite/marshal.py,sha256=O_v_slgjAAiSGWComdRhqLXdumuIlBDc3SvoG_p00QM,15863
|
@@ -389,9 +390,6 @@ omlish/lite/reflect.py,sha256=pzOY2PPuHH0omdtglkN6DheXDrGopdL3PtTJnejyLFU,2189
|
|
389
390
|
omlish/lite/resources.py,sha256=YNSmX1Ohck1aoWRs55a-o5ChVbFJIQhtbqE-XwF55Oc,326
|
390
391
|
omlish/lite/runtime.py,sha256=XQo408zxTdJdppUZqOWHyeUR50VlCpNIExNGHz4U6O4,459
|
391
392
|
omlish/lite/secrets.py,sha256=3Mz3V2jf__XU9qNHcH56sBSw95L3U2UPL24bjvobG0c,816
|
392
|
-
omlish/lite/shlex.py,sha256=CGAgKv1rgrHPhSmY8ItKkiqHYOvXB9j_uL_6u8p2fqI,233
|
393
|
-
omlish/lite/socket.py,sha256=7OYgkXTcQv0wq7TQuLnl9y6dJA1ZT6Vbc1JH59QlxgY,1792
|
394
|
-
omlish/lite/socketserver.py,sha256=doTXIctu_6c8XneFtzPFVG_Wq6xVmA3p9ymut8IvBoU,1586
|
395
393
|
omlish/lite/strings.py,sha256=nGWaOi9LzTjkc5kPN2IqsVN8PUw8m_2yllTGRUQU5PI,1983
|
396
394
|
omlish/lite/typing.py,sha256=U3-JaEnkDSYxK4tsu_MzUn3RP6qALBe5FXQXpD-licE,1090
|
397
395
|
omlish/logs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -466,6 +464,10 @@ omlish/secrets/pwgen.py,sha256=v-5ztnOTHTAWXLGR-3H6HkMj2nPIZBMbo5xWR3q0rDY,1707
|
|
466
464
|
omlish/secrets/pwhash.py,sha256=Goktn-swmC6PXqfRBnDrH_Lr42vjckT712UyErPjzkw,4102
|
467
465
|
omlish/secrets/secrets.py,sha256=cnDGBoPknVxsCN04_gqcJT_7Ebk3iO3VPkRZ2oMjkMw,7868
|
468
466
|
omlish/secrets/subprocesses.py,sha256=ffjfbgPbEE_Pwb_87vG4yYR2CGZy3I31mHNCo_0JtHw,1212
|
467
|
+
omlish/sockets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
468
|
+
omlish/sockets/addresses.py,sha256=ZQFacDsXo6cKSgEjzN525IcUJPyfubXETzbY-_BBAro,1285
|
469
|
+
omlish/sockets/handlers.py,sha256=9kkNMj1DTJa4xo_3hcBvSkjKc-dy_Ho5he2ubJieJ2A,621
|
470
|
+
omlish/sockets/server.py,sha256=g9CSL0m6Ox10usyysXw4YRFr9H3LlQUH-9GftFCLeFw,1606
|
469
471
|
omlish/specs/__init__.py,sha256=zZwF8yXTEkSstYtORkDhVLK-_hWU8WOJCuBpognb_NY,118
|
470
472
|
omlish/specs/jmespath/LICENSE,sha256=IH-ZZlZkS8XMkf_ubNVD1aYHQ2l_wd0tmHtXrCcYpRU,1113
|
471
473
|
omlish/specs/jmespath/__init__.py,sha256=9tsrquw1kXe1KAhTP3WeL0GlGBiTguQVxsC-lUYTWP4,2087
|
@@ -568,11 +570,12 @@ omlish/text/asdl.py,sha256=AS3irh-sag5pqyH3beJif78PjCbOaFso1NeKq-HXuTs,16867
|
|
568
570
|
omlish/text/delimit.py,sha256=ubPXcXQmtbOVrUsNh5gH1mDq5H-n1y2R4cPL5_DQf68,4928
|
569
571
|
omlish/text/glyphsplit.py,sha256=Ug-dPRO7x-OrNNr8g1y6DotSZ2KH0S-VcOmUobwa4B0,3296
|
570
572
|
omlish/text/indent.py,sha256=6Jj6TFY9unaPa4xPzrnZemJ-fHsV53IamP93XGjSUHs,1274
|
573
|
+
omlish/text/minja.py,sha256=KAmZ2POcLcxwF4DPKxdWa16uWxXmVz1UnJXLSwt4oZo,5761
|
571
574
|
omlish/text/parts.py,sha256=7vPF1aTZdvLVYJ4EwBZVzRSy8XB3YqPd7JwEnNGGAOo,6495
|
572
575
|
omlish/text/random.py,sha256=jNWpqiaKjKyTdMXC-pWAsSC10AAP-cmRRPVhm59ZWLk,194
|
573
|
-
omlish-0.0.0.
|
574
|
-
omlish-0.0.0.
|
575
|
-
omlish-0.0.0.
|
576
|
-
omlish-0.0.0.
|
577
|
-
omlish-0.0.0.
|
578
|
-
omlish-0.0.0.
|
576
|
+
omlish-0.0.0.dev180.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
|
577
|
+
omlish-0.0.0.dev180.dist-info/METADATA,sha256=YTRf_o1wf-jeZft0XvdNUg0MGJYmpJe0Z2x3k3fCObY,4264
|
578
|
+
omlish-0.0.0.dev180.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
579
|
+
omlish-0.0.0.dev180.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
|
580
|
+
omlish-0.0.0.dev180.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
|
581
|
+
omlish-0.0.0.dev180.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|