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 CHANGED
@@ -1,5 +1,5 @@
1
- __version__ = '0.0.0.dev178'
2
- __revision__ = 'fd8b9c2c51797566d0d9a52a8b347895029c82f5'
1
+ __version__ = '0.0.0.dev180'
2
+ __revision__ = '61f5a9f8edf9c1c743e1ce24b9cec06fffcf55a0'
3
3
 
4
4
 
5
5
  #
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
- ArgparseCommandFn as CommandFn,
9
- ArgparseCommand as Command,
10
- argparse_command as command,
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
- ArgparseCommandFn = ta.Callable[[], ta.Optional[int]] # ta.TypeAlias
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 ArgparseCommand:
50
+ class ArgparseCmd:
51
51
  name: str
52
- fn: ArgparseCommandFn
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['ArgparseCommand'] = None
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, (ArgparseCommand, type(None)))
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 argparse_command(
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[ArgparseCommand] = None,
91
+ parent: ta.Optional[ArgparseCmd] = None,
92
92
  accepts_unknown: bool = False,
93
- ) -> ta.Any: # ta.Callable[[ArgparseCommandFn], ArgparseCommand]: # FIXME
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, (ArgparseCommand, type(None)))
97
+ check.isinstance(parent, (ArgparseCmd, type(None)))
98
98
  check.not_isinstance(aliases, str)
99
99
 
100
100
  def inner(fn):
101
- return ArgparseCommand(
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, (ArgparseCommand, ArgparseArg)):
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, ArgparseCommand):
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: ArgparseCommand) -> ta.Callable:
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: object.__setattr__(self, {self.CACHED_HASH_ATTR!r}, h := hash({self_tuple}))',
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 ...lite.socket import SocketAddress
10
+ from ...sockets.addresses import SocketAddress
11
11
  from ..handlers import HttpHandler
12
12
  from .server import CoroHttpServer
13
13
 
@@ -64,8 +64,8 @@ import time
64
64
  import typing as ta
65
65
 
66
66
  from ...lite.check import check
67
- from ...lite.socket import SocketAddress
68
- from ...lite.socket import SocketHandler
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
@@ -4,7 +4,7 @@ import dataclasses as dc
4
4
  import http.server
5
5
  import typing as ta
6
6
 
7
- from ..lite.socket import SocketAddress
7
+ from ..sockets.addresses import SocketAddress
8
8
  from .parsing import HttpHeaders
9
9
 
10
10
 
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: frozenset[Element] | None = dc.xfield(None, coerce=check.of_isinstance((frozenset, None)))
23
- cs: frozenset['Elements'] | None = dc.xfield(None, coerce=check.of_isinstance((frozenset, None)))
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: set[Element] = set()
42
- cs: set[Elements] = set()
40
+ es: list[Element] = []
41
+ cs: list[Elements] = []
43
42
 
44
43
  def rec(a):
45
44
  if isinstance(a, Element):
46
- es.add(a)
45
+ es.append(a)
47
46
  elif isinstance(a, Elements):
48
- cs.add(a)
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
- frozenset(es) if es else None,
63
- frozenset(cs) if cs else None,
61
+ es if es else None,
62
+ cs if cs else None,
64
63
  )
@@ -4,7 +4,7 @@ import socket
4
4
  import typing as ta
5
5
 
6
6
  from ...lite.check import check
7
- from ...lite.socket import SocketAddress
7
+ from ...sockets.addresses import SocketAddress
8
8
 
9
9
 
10
10
  class FdioHandler(abc.ABC):
omlish/lite/__init__.py CHANGED
@@ -1 +1,5 @@
1
1
  # @omlish-lite
2
+ """
3
+ These are the 'core' lite modules. These generally have a 'full' equivalent, in which case non-lite code should prefer
4
+ that.
5
+ """
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
- prvs: ta.Dict[InjectorKey, ta.Any] = dc.field(default_factory=dict)
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.prvs[self.k]
446
+ return st.provisions[self.k]
446
447
  except KeyError:
447
448
  pass
448
449
  v = ufn(i)
449
- st.prvs[self.k] = v
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 as_injector_bindings(
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
 
@@ -1,3 +1,4 @@
1
+ # @omlish-lite
1
2
  import shlex
2
3
 
3
4
 
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 .socket import SocketAddress
9
- from .socket import SocketHandlerFactory
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,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: omlish
3
- Version: 0.0.0.dev178
3
+ Version: 0.0.0.dev180
4
4
  Summary: omlish
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -1,5 +1,5 @@
1
1
  omlish/.manifests.json,sha256=lRkBDFxlAbf6lN5upo3WSf-owW8YG1T21dfpbQL-XHM,7598
2
- omlish/__about__.py,sha256=d7Vqq3YraWwcnd0sR_ExiQePePaN2h_hwFfJ-RBD7IQ,3409
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=EfUSf27vFWqa4Q93AycU5YRsrHt-Nx3pU3uNVapb-EE,1054
86
- omlish/argparse/cli.py,sha256=Nd16RNNABOd9UjfLGtJrDOYkIs5uv1BnoqvJdQ2Ipc8,8273
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=FKnHuXCg9ylrzK2TLGqO5yfRN4HX3F415CSLlVYXtYE,3190
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=yeBBHJmBKvY1C_qdekLxViy_eZSU7WIMvxO-6CSwD5I,789
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=RMwZ0w-kJAp-2DazFMtWd7yFtjoBqQVCfHuibQkVlkA,4011
280
- omlish/http/coro/server.py,sha256=6MjeYygaE4tcq2b8xBIkbNM_e1heDdq98yAwYGFEKdY,18060
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=BzTnkNS-3iAMI47LMC2543u6A8Tfk3aJXn3CO191ez4,1547
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=OOQhiazbhNMwxLwyzf8KUQrBQSuHIm-UqAMpXmmHGFQ,1344
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=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
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=yolrXQPZ903FcZwbSrUXsXNCylZ31W1vesjLelRWGgo,28758
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.dev178.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
574
- omlish-0.0.0.dev178.dist-info/METADATA,sha256=Zltjh6LQhgQnlgh8RPDJgnQHdnTVpzHEP3rMc3OcjJU,4264
575
- omlish-0.0.0.dev178.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
576
- omlish-0.0.0.dev178.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
577
- omlish-0.0.0.dev178.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
578
- omlish-0.0.0.dev178.dist-info/RECORD,,
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,,