omlish 0.0.0.dev374__py3-none-any.whl → 0.0.0.dev375__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.dev374'
2
- __revision__ = '7a173b571acabc80999972c98a5fb486b6be9464'
1
+ __version__ = '0.0.0.dev375'
2
+ __revision__ = '5e3b55f993cef1d0198721ee8b5d9f827c357fe9'
3
3
 
4
4
 
5
5
  #
@@ -37,10 +37,6 @@ from .coerce import ( # noqa
37
37
  seq_or_none,
38
38
  )
39
39
 
40
- from .errors import ( # noqa
41
- DuplicateKeyError,
42
- )
43
-
44
40
  from .frozen import ( # noqa
45
41
  Frozen,
46
42
  FrozenDict,
@@ -66,9 +66,27 @@ class TypeMap(ta.Generic[T]):
66
66
  def get(self, ty: type[T]) -> T | None:
67
67
  return self._dct.get(ty)
68
68
 
69
- def __getitem__(self, ty: type[T]) -> ta.Sequence[T]:
69
+ def __getitem__(self, ty: type[T]) -> T:
70
70
  return self._dct[ty]
71
71
 
72
+ _any_dct: dict[type | tuple[type, ...], tuple[T, ...]]
73
+
74
+ def get_any(self, cls: type | tuple[type, ...]) -> ta.Sequence[T]:
75
+ try:
76
+ any_dct = self._any_dct
77
+ except AttributeError:
78
+ any_dct = {}
79
+ self._any_dct = any_dct
80
+
81
+ try:
82
+ return any_dct[cls]
83
+ except KeyError:
84
+ pass
85
+
86
+ ret = tuple(tv for tv in self if isinstance(tv, cls))
87
+ any_dct[cls] = ret
88
+ return ret
89
+
72
90
 
73
91
  class DynamicTypeMap(ta.Generic[V]):
74
92
  def __init__(self, items: ta.Iterable[V] = (), *, weak: bool = False) -> None:
@@ -1,7 +1,6 @@
1
1
  import typing as ta
2
2
 
3
3
  from .. import lang
4
- from .errors import DuplicateKeyError
5
4
  from .identity import IdentityKeyDict
6
5
  from .identity import IdentitySet
7
6
 
@@ -48,7 +47,7 @@ def unique(
48
47
  k = key(e)
49
48
  if k in seen:
50
49
  if strict:
51
- raise DuplicateKeyError(k, e)
50
+ raise lang.DuplicateKeyError(k, e)
52
51
  else:
53
52
  seen.add(k)
54
53
  ret.append(e)
@@ -88,7 +87,7 @@ def make_map(
88
87
  for k, v in kvs:
89
88
  if k in d:
90
89
  if strict:
91
- raise DuplicateKeyError(k)
90
+ raise lang.DuplicateKeyError(k)
92
91
  else:
93
92
  d[k] = v
94
93
  return d
@@ -0,0 +1,162 @@
1
+ # ruff: noqa: UP006 UP045
2
+ # @omlish-lite
3
+ import abc
4
+ import io
5
+ import os.path
6
+ import sys
7
+ import typing as ta
8
+
9
+ from ..lite.cached import cached_nullary
10
+ from ..lite.check import check
11
+ from ..os.paths import is_path_in_dir
12
+
13
+
14
+ ##
15
+
16
+
17
+ class FnBuilder(abc.ABC):
18
+ @abc.abstractmethod
19
+ def build_fn(
20
+ self,
21
+ name: str,
22
+ src: str,
23
+ ns: ta.Optional[ta.Mapping[str, ta.Any]] = None,
24
+ ) -> ta.Callable:
25
+ ...
26
+
27
+
28
+ #
29
+
30
+
31
+ class SimpleFnBuilder(FnBuilder):
32
+ def build_fn(
33
+ self,
34
+ name: str,
35
+ src: str,
36
+ ns: ta.Optional[ta.Mapping[str, ta.Any]] = None,
37
+ ) -> ta.Callable:
38
+ ns = dict(ns or {})
39
+ exec(src, ns)
40
+ return ns[name]
41
+
42
+
43
+ build_fn = SimpleFnBuilder().build_fn
44
+
45
+
46
+ #
47
+
48
+
49
+ class DebugFnBuilder(FnBuilder):
50
+ def __init__(
51
+ self,
52
+ *,
53
+ mod_name_prefix: ta.Optional[str] = None,
54
+ src_dir: ta.Optional[str] = None,
55
+ ) -> None:
56
+ super().__init__()
57
+
58
+ if mod_name_prefix is None:
59
+ mod_name_prefix = f'_{self.__class__.__name__}_{id(self):x}_'
60
+ self._mod_name_prefix = mod_name_prefix
61
+
62
+ self._given_src_dir = src_dir
63
+
64
+ self._num_fns = 0
65
+ self._mod_names: ta.Set[str] = set()
66
+ self._installed_sys_path = False
67
+
68
+ @cached_nullary
69
+ def _src_dir(self) -> str:
70
+ if self._given_src_dir is not None:
71
+ return self._given_src_dir
72
+ else:
73
+ return __import__('tempfile').mkdtemp(prefix=f'_{self.__class__.__name__}_{os.getpid()}__') # noqa
74
+
75
+ @cached_nullary
76
+ def _install_sys_path(self) -> None:
77
+ if (src_dir := self._src_dir()) not in sys.path:
78
+ self._installed_sys_path = True
79
+ sys.path.append(src_dir)
80
+
81
+ def uninstall_sys_path(self) -> None:
82
+ if self._installed_sys_path:
83
+ while True:
84
+ try:
85
+ sys.path.remove(self._src_dir())
86
+ except ValueError:
87
+ break
88
+ self._installed_sys_path = True
89
+
90
+ def _gen_mod_name(
91
+ self,
92
+ fn_num: int,
93
+ fn_name: str,
94
+ *,
95
+ suffix: ta.Optional[str] = None,
96
+ ) -> str:
97
+ mod_name = f'{self._mod_name_prefix}{fn_num}__{fn_name}{suffix or ""}'
98
+
99
+ check.not_in(mod_name, self._mod_names)
100
+ check.not_in(mod_name, sys.modules)
101
+
102
+ self._mod_names.add(mod_name)
103
+
104
+ return mod_name
105
+
106
+ def _build_mod(
107
+ self,
108
+ mod_name: str,
109
+ mod_src: str,
110
+ ) -> ta.Any:
111
+ self._install_sys_path()
112
+
113
+ src_dir = self._src_dir()
114
+ src_file = os.path.join(src_dir, f'{mod_name}.py')
115
+ check.state(is_path_in_dir(src_dir, src_file))
116
+
117
+ with open(src_file, 'w') as f:
118
+ f.write(mod_src)
119
+
120
+ mod = __import__(mod_name)
121
+
122
+ check.equal(mod.__file__, src_file)
123
+
124
+ return mod
125
+
126
+ def build_fn(
127
+ self,
128
+ name: str,
129
+ src: str,
130
+ ns: ta.Optional[ta.Mapping[str, ta.Any]] = None,
131
+ ) -> ta.Callable:
132
+ fn_num = self._num_fns
133
+ self._num_fns += 1
134
+
135
+ mod_name = self._gen_mod_name(fn_num, name)
136
+
137
+ src_preamble: ta.List[str] = []
138
+
139
+ if ns:
140
+ ns_mod_name = self._gen_mod_name(fn_num, name, suffix='__ns')
141
+ ns_mod = self._build_mod(ns_mod_name, '')
142
+
143
+ for k, v in ns.items():
144
+ setattr(ns_mod, k, v)
145
+
146
+ src_preamble.append(f'from {ns_mod_name} import (')
147
+ for k in sorted(ns):
148
+ src_preamble.append(f' {k},')
149
+ src_preamble.append(')')
150
+
151
+ src_sb = io.StringIO()
152
+ if src_preamble:
153
+ src_sb.write('\n'.join(src_preamble))
154
+ src_sb.write('\n\n')
155
+ src_sb.write(src)
156
+ if not src.endswith('\n'):
157
+ src_sb.write('\n')
158
+
159
+ mod = self._build_mod(mod_name, src_sb.getvalue())
160
+
161
+ fn = mod.__dict__[name]
162
+ return fn
omlish/funcs/match.py CHANGED
@@ -1,4 +1,6 @@
1
1
  """
2
+ Analogous to scala's partial functions ( https://www.scala-lang.org/api/current/scala/PartialFunction.html ).
3
+
2
4
  TODO:
3
5
  - unify MatchFnClass with dispatch.method?
4
6
  - __call__ = mfs.method(); @__call__.register(lambda: ...) def _call_... ?
omlish/lang/__init__.py CHANGED
@@ -173,6 +173,10 @@ from .enums import ( # noqa
173
173
  enum_name_repr,
174
174
  )
175
175
 
176
+ from .errors import ( # noqa
177
+ DuplicateKeyError,
178
+ )
179
+
176
180
  from .functions import ( # noqa
177
181
  VoidError,
178
182
  as_async,
omlish/lite/__init__.py CHANGED
@@ -1,5 +1,5 @@
1
1
  # @omlish-lite
2
2
  """
3
- These are the 'core' lite modules. These generally have a 'full' equivalent, in which case non-lite code should prefer
3
+ These are the 'core' lite modules. These generally have a 'full' equivalent, in which case standard code should prefer
4
4
  that.
5
5
  """
omlish/lite/json.py CHANGED
@@ -12,7 +12,7 @@ JSON_PRETTY_KWARGS: ta.Mapping[str, ta.Any] = dict(
12
12
  indent=JSON_PRETTY_INDENT,
13
13
  )
14
14
 
15
- json_dump_pretty: ta.Callable[..., bytes] = functools.partial(json.dump, **JSON_PRETTY_KWARGS) # type: ignore
15
+ json_dump_pretty: ta.Callable[..., None] = functools.partial(json.dump, **JSON_PRETTY_KWARGS)
16
16
  json_dumps_pretty: ta.Callable[..., str] = functools.partial(json.dumps, **JSON_PRETTY_KWARGS)
17
17
 
18
18
 
@@ -26,5 +26,5 @@ JSON_COMPACT_KWARGS: ta.Mapping[str, ta.Any] = dict(
26
26
  separators=JSON_COMPACT_SEPARATORS,
27
27
  )
28
28
 
29
- json_dump_compact: ta.Callable[..., bytes] = functools.partial(json.dump, **JSON_COMPACT_KWARGS) # type: ignore
29
+ json_dump_compact: ta.Callable[..., None] = functools.partial(json.dump, **JSON_COMPACT_KWARGS)
30
30
  json_dumps_compact: ta.Callable[..., str] = functools.partial(json.dumps, **JSON_COMPACT_KWARGS)
@@ -43,13 +43,13 @@ import types
43
43
  import typing as ta
44
44
  import unittest
45
45
 
46
- from .types import Test
46
+ from .types import UnittestTest
47
47
 
48
48
 
49
49
  ##
50
50
 
51
51
 
52
- class TestTargetLoader:
52
+ class UnittestTargetLoader:
53
53
  def __init__(
54
54
  self,
55
55
  *,
@@ -81,7 +81,7 @@ class TestTargetLoader:
81
81
  pattern: ta.Optional[str] = None
82
82
  top: ta.Optional[str] = None
83
83
 
84
- def load(self, target: Target) -> Test:
84
+ def load(self, target: Target) -> UnittestTest:
85
85
  loader = self._loader
86
86
  if loader is None:
87
87
  loader = unittest.loader.TestLoader()
@@ -89,8 +89,8 @@ class TestTargetLoader:
89
89
  if self._test_name_patterns:
90
90
  loader.testNamePatterns = self._test_name_patterns # type: ignore[assignment]
91
91
 
92
- if isinstance(target, TestTargetLoader.DiscoveryTarget):
93
- return ta.cast(Test, loader.discover(
92
+ if isinstance(target, UnittestTargetLoader.DiscoveryTarget):
93
+ return ta.cast(UnittestTest, loader.discover(
94
94
  target.start, # type: ignore[arg-type]
95
95
  target.pattern, # type: ignore[arg-type]
96
96
  target.top,
@@ -102,11 +102,11 @@ class TestTargetLoader:
102
102
  for part in module.split('.')[1:]:
103
103
  module = getattr(module, part)
104
104
 
105
- if isinstance(target, TestTargetLoader.ModuleTarget):
106
- return ta.cast(Test, loader.loadTestsFromModule(module))
105
+ if isinstance(target, UnittestTargetLoader.ModuleTarget):
106
+ return ta.cast(UnittestTest, loader.loadTestsFromModule(module))
107
107
 
108
- elif isinstance(target, TestTargetLoader.NamesTarget):
109
- return ta.cast(Test, loader.loadTestsFromNames(
108
+ elif isinstance(target, UnittestTargetLoader.NamesTarget):
109
+ return ta.cast(UnittestTest, loader.loadTestsFromNames(
110
110
  target.test_names, # type: ignore[arg-type]
111
111
  module,
112
112
  ))
@@ -49,25 +49,14 @@ import sys
49
49
  import types
50
50
  import typing as ta
51
51
 
52
- from .loading import TestTargetLoader
53
- from .running import TestRunner
52
+ from .loading import UnittestTargetLoader
53
+ from .running import UnittestTestRunner
54
54
 
55
55
 
56
56
  ##
57
57
 
58
58
 
59
- def _get_attr_dict(obj: ta.Optional[ta.Any], *attrs: str) -> ta.Dict[str, ta.Any]:
60
- if obj is None:
61
- return {}
62
-
63
- return {
64
- a: v
65
- for a in attrs
66
- if (v := getattr(obj, a, None)) is not None
67
- }
68
-
69
-
70
- class TestRunCli:
59
+ class UnittestRunCli:
71
60
  def __init__(self) -> None:
72
61
  super().__init__()
73
62
 
@@ -195,9 +184,22 @@ class TestRunCli:
195
184
 
196
185
  #
197
186
 
187
+ @staticmethod
188
+ def _get_attr_dict(obj: ta.Optional[ta.Any], *attrs: str) -> ta.Dict[str, ta.Any]:
189
+ if obj is None:
190
+ return {}
191
+
192
+ return {
193
+ a: v
194
+ for a in attrs
195
+ if (v := getattr(obj, a, None)) is not None
196
+ }
197
+
198
+ #
199
+
198
200
  IMPORT_PATH_PAT = re.compile(r'[a-zA-Z_][a-zA-Z0-9_]*(?:\.[a-zA-Z_][a-zA-Z0-9_]*)*')
199
201
 
200
- def _build_target(self, name: str, args: ParsedArgs) -> TestTargetLoader.Target:
202
+ def _build_target(self, name: str, args: ParsedArgs) -> UnittestTargetLoader.Target:
201
203
  is_discovery = False
202
204
  if os.path.isdir(name):
203
205
  is_discovery = True
@@ -207,12 +209,12 @@ class TestRunCli:
207
209
  is_discovery = True
208
210
 
209
211
  if not is_discovery:
210
- return TestTargetLoader.NamesTarget([name])
212
+ return UnittestTargetLoader.NamesTarget([name])
211
213
 
212
214
  else:
213
- return TestTargetLoader.DiscoveryTarget(
215
+ return UnittestTargetLoader.DiscoveryTarget(
214
216
  start=name,
215
- **_get_attr_dict(
217
+ **self._get_attr_dict(
216
218
  args.args,
217
219
  'pattern',
218
220
  'top',
@@ -229,7 +231,7 @@ class TestRunCli:
229
231
  *,
230
232
  exit: bool = False, # noqa
231
233
  ) -> None:
232
- loader = TestTargetLoader(**_get_attr_dict(
234
+ loader = UnittestTargetLoader(**self._get_attr_dict(
233
235
  args.args,
234
236
  'test_name_patterns',
235
237
  ))
@@ -239,7 +241,7 @@ class TestRunCli:
239
241
  for target_arg in (args.args.target if args.args is not None else None) or [] # noqa
240
242
  ]
241
243
 
242
- runner = TestRunner(TestRunner.Args(**_get_attr_dict(
244
+ runner = UnittestTestRunner(UnittestTestRunner.Args(**self._get_attr_dict(
243
245
  args.args,
244
246
  'verbosity',
245
247
  'failfast',
@@ -266,7 +268,7 @@ class TestRunCli:
266
268
 
267
269
 
268
270
  def _main() -> None:
269
- cli = TestRunCli()
271
+ cli = UnittestRunCli()
270
272
  args = cli.parse_args(sys.argv[1:])
271
273
  cli.run(args, exit=True)
272
274
 
@@ -45,30 +45,13 @@ import typing as ta
45
45
  import unittest
46
46
  import warnings
47
47
 
48
- from .types import Test
48
+ from .types import UnittestTest
49
49
 
50
50
 
51
51
  ##
52
52
 
53
53
 
54
- class _WritelnDecorator:
55
- def __init__(self, stream):
56
- super().__init__()
57
-
58
- self.stream = stream
59
-
60
- def __getattr__(self, attr):
61
- if attr in ('stream', '__getstate__'):
62
- raise AttributeError(attr)
63
- return getattr(self.stream, attr)
64
-
65
- def writeln(self, arg=None):
66
- if arg:
67
- self.write(arg)
68
- self.write('\n') # text-mode streams translate to \r\n if needed
69
-
70
-
71
- class TestRunner:
54
+ class UnittestTestRunner:
72
55
  """
73
56
  A test runner class that displays results in textual form.
74
57
 
@@ -98,7 +81,25 @@ class TestRunner:
98
81
 
99
82
  if stream is None:
100
83
  stream = sys.stderr
101
- self._stream = _WritelnDecorator(stream)
84
+ self._stream = UnittestTestRunner._WritelnDecorator(stream)
85
+
86
+ #
87
+
88
+ class _WritelnDecorator:
89
+ def __init__(self, stream):
90
+ super().__init__()
91
+
92
+ self.stream = stream
93
+
94
+ def __getattr__(self, attr):
95
+ if attr in ('stream', '__getstate__'):
96
+ raise AttributeError(attr)
97
+ return getattr(self.stream, attr)
98
+
99
+ def writeln(self, arg=None):
100
+ if arg:
101
+ self.write(arg)
102
+ self.write('\n') # text-mode streams translate to \r\n if needed
102
103
 
103
104
  #
104
105
 
@@ -179,7 +180,7 @@ class TestRunner:
179
180
 
180
181
  time_taken = stop_time - start_time
181
182
 
182
- return TestRunner._InternalRunTestResult(
183
+ return UnittestTestRunner._InternalRunTestResult(
183
184
  result,
184
185
  time_taken,
185
186
  )
@@ -206,7 +207,7 @@ class TestRunner:
206
207
  unexpected_successes: ta.Sequence[str]
207
208
 
208
209
  @classmethod
209
- def merge(cls, results: ta.Iterable['TestRunner.RunResult']) -> 'TestRunner.RunResult':
210
+ def merge(cls, results: ta.Iterable['UnittestTestRunner.RunResult']) -> 'UnittestTestRunner.RunResult':
210
211
  def reduce_attr(fn, a):
211
212
  return fn(getattr(r, a) for r in results)
212
213
 
@@ -233,11 +234,11 @@ class TestRunner:
233
234
 
234
235
  def as_test_and_reasons(l):
235
236
  return [
236
- TestRunner.RunResult.TestAndReason(result.getDescription(t), r)
237
+ UnittestTestRunner.RunResult.TestAndReason(result.getDescription(t), r)
237
238
  for t, r in l
238
239
  ]
239
240
 
240
- return TestRunner.RunResult(
241
+ return UnittestTestRunner.RunResult(
241
242
  raw_results=[result],
242
243
  time_taken=internal_result.time_taken,
243
244
 
@@ -254,11 +255,11 @@ class TestRunner:
254
255
 
255
256
  #
256
257
 
257
- def run(self, test: Test) -> RunResult:
258
+ def run(self, test: UnittestTest) -> RunResult:
258
259
  return self._build_run_result(self._internal_run_test(test))
259
260
 
260
- def run_many(self, tests: ta.Iterable[Test]) -> RunResult:
261
- return TestRunner.RunResult.merge([self.run(t) for t in tests])
261
+ def run_many(self, tests: ta.Iterable[UnittestTest]) -> RunResult:
262
+ return UnittestTestRunner.RunResult.merge([self.run(t) for t in tests])
262
263
 
263
264
  #
264
265
 
@@ -2,4 +2,4 @@ import typing as ta
2
2
  import unittest
3
3
 
4
4
 
5
- Test = ta.Callable[[unittest.TestResult], None] # ta.TypeAlias
5
+ UnittestTest = ta.Callable[[unittest.TestResult], None] # ta.TypeAlias
omlish/text/minja.py CHANGED
@@ -10,6 +10,8 @@ import io
10
10
  import re
11
11
  import typing as ta
12
12
 
13
+ from ..funcs.builders import FnBuilder
14
+ from ..funcs.builders import SimpleFnBuilder
13
15
  from ..lite.cached import cached_nullary
14
16
  from ..lite.check import check
15
17
  from ..lite.maybes import Maybe
@@ -76,19 +78,9 @@ class MinjaTemplate:
76
78
  ##
77
79
 
78
80
 
79
- class MinjaFunctionBuilder(ta.Protocol):
80
- def __call__(
81
- self,
82
- name: str,
83
- src: str,
84
- ns: ta.Optional[ta.Mapping[str, ta.Any]] = None,
85
- ) -> ta.Callable:
86
- ...
87
-
88
-
89
81
  class MinjaTemplateCompiler:
90
82
  """
91
- Compiles a template string into a Python function. The returned function takes a dictionary 'context' and returns
83
+ Compiles a template string into a Python fn. The returned fn takes a dictionary 'context' and returns
92
84
  the rendered string.
93
85
 
94
86
  Supported syntax:
@@ -111,7 +103,7 @@ class MinjaTemplateCompiler:
111
103
  fragment_processor: ta.Optional[ta.Callable[[MinjaTemplateFragmentKind, str], str]] = None,
112
104
  strict_strings: bool = False,
113
105
  stringifier: ta.Optional[ta.Callable[[ta.Any], str]] = None,
114
- function_builder: ta.Optional[MinjaFunctionBuilder] = None,
106
+ fn_builder: ta.Optional[FnBuilder] = None,
115
107
  ) -> None:
116
108
  super().__init__()
117
109
 
@@ -136,9 +128,9 @@ class MinjaTemplateCompiler:
136
128
  stringifier = lambda o: str(o)
137
129
  self._stringifier = stringifier
138
130
 
139
- if function_builder is None:
140
- function_builder = self._build_function
141
- self._function_builder = function_builder
131
+ if fn_builder is None:
132
+ fn_builder = SimpleFnBuilder()
133
+ self._fn_builder = fn_builder
142
134
 
143
135
  self._stack: ta.List[ta.Literal['for', 'if']] = []
144
136
 
@@ -148,18 +140,6 @@ class MinjaTemplateCompiler:
148
140
  raise TypeError(o)
149
141
  return o
150
142
 
151
- @staticmethod
152
- def _build_function(
153
- name: str,
154
- src: str,
155
- ns: ta.Optional[ta.Mapping[str, ta.Any]] = None,
156
- ) -> ta.Callable:
157
- glo: dict = {}
158
- if ns:
159
- glo.update(ns)
160
- exec(src, glo)
161
- return glo[name]
162
-
163
143
  #
164
144
 
165
145
  _TAG_PAT = re.compile(
@@ -315,7 +295,7 @@ class MinjaTemplateCompiler:
315
295
  raise KeyError(k)
316
296
  ns[k] = v
317
297
 
318
- render_fn = self._function_builder(
298
+ render_fn = self._fn_builder.build_fn(
319
299
  self._RENDER_FN_NAME,
320
300
  rendered.src,
321
301
  ns,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: omlish
3
- Version: 0.0.0.dev374
3
+ Version: 0.0.0.dev375
4
4
  Summary: omlish
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -1,5 +1,5 @@
1
1
  omlish/.manifests.json,sha256=aT8yZ-Zh-9wfHl5Ym5ouiWC1i0cy7Q7RlhzavB6VLPI,8587
2
- omlish/__about__.py,sha256=_i_tQ9A48__MEZO6apOfvz5EyxB8GlOe28oLORkGJKk,3478
2
+ omlish/__about__.py,sha256=KWPKJkqc48_109D1coX6sQoDWUirvqJQFHZpuq1yU-8,3478
3
3
  omlish/__init__.py,sha256=SsyiITTuK0v74XpKV8dqNaCmjOlan1JZKrHQv5rWKPA,253
4
4
  omlish/c3.py,sha256=rer-TPOFDU6fYq_AWio_AmA-ckZ8JDY5shIzQ_yXfzA,8414
5
5
  omlish/cached.py,sha256=MLap_p0rdGoDIMVhXVHm1tsbcWobJF0OanoodV03Ju8,542
@@ -76,20 +76,19 @@ omlish/codecs/funcs.py,sha256=or0Jogczuzk7csDTRl-HURMEjl8LXXqxxXYK45xcM5w,855
76
76
  omlish/codecs/registry.py,sha256=2FnO5YP7ui1LzkguwESY0MP3WIdwgPTIJTM_4RyTOEg,3896
77
77
  omlish/codecs/standard.py,sha256=eiZ4u9ep0XrA4Z_D1zJI0vmWyuN8HLrX4Se_r_Cq_ZM,60
78
78
  omlish/codecs/text.py,sha256=MgAzXapiHie-hhLBmcho67WXfWbmhlHz4tNPcHXnWUk,5711
79
- omlish/collections/__init__.py,sha256=AKf3dEpZar2KTrSaRF0VQ3CRjqUBZObY3zNwYL7lbmY,2690
79
+ omlish/collections/__init__.py,sha256=-CcIq7e8OkQakexxpJOXf2q6LdVqzo7B-quPtwur_BQ,2634
80
80
  omlish/collections/abc.py,sha256=p9zhL5oNV5WPyWmMn34fWfkuxPQAjOtL7WQA-Xsyhwk,2628
81
81
  omlish/collections/bimap.py,sha256=3szDCscPJlFRtkpyVQNWneg4s50mr6Rd0jdTzVEIcnE,1661
82
82
  omlish/collections/coerce.py,sha256=tAls15v_7p5bUN33R7Zbko87KW5toWHl9fRialCqyNY,7030
83
- omlish/collections/errors.py,sha256=shcS-NCnEUudF8qC_SmO2TQyjivKlS4TDjaz_faqQ0c,44
84
83
  omlish/collections/frozen.py,sha256=LMbAHYDENIQk1hvjCTvpnx66m1TalrHa4CSn8n_tsXQ,4142
85
84
  omlish/collections/hasheq.py,sha256=uHypfZlHhicQPvx9OOlpT9MSLwfc_mFil-WaxF9dTOo,3732
86
85
  omlish/collections/identity.py,sha256=S_W508EkU-AW0TZ7cv1wWUc6EG54vww4XbcfGjDFTgg,4793
87
- omlish/collections/mappings.py,sha256=iXb7oq1rCQak0KgzblgrzWCJLrkfJAYHFvl9lprOVUI,2804
86
+ omlish/collections/mappings.py,sha256=lAzKP9RONLjFH7emIDoY-6jukuD-Sa7fdxzP7u6qrqU,3261
88
87
  omlish/collections/multimaps.py,sha256=8Sqi1iVxUObnL47s8b1esa2TERoiEyyY4RBWF1VjDiw,3820
89
88
  omlish/collections/ordered.py,sha256=XV_ufr3QycjQ3nIy9L3BufdBosWD-3wb5xVZEHpZocQ,2467
90
89
  omlish/collections/ranked.py,sha256=McB8C2UQfUvrbmxGTpBz1-EZuyCLkBFtktzncMdt8_Y,2287
91
90
  omlish/collections/unmodifiable.py,sha256=0ZkA_0paWlkgaU6OupFdSV0yFP--7XoI3lqhs3Ci6ME,4951
92
- omlish/collections/utils.py,sha256=1LED_KLXsEb39Byhql7BD5ObHoSkFn2OyUdnHsKXKNo,4091
91
+ omlish/collections/utils.py,sha256=JYBYoConWxApqJLOjXR6GuQI76G0KQDjg6kkXrTofUw,4063
93
92
  omlish/collections/cache/__init__.py,sha256=D1gO71VcwxFTZP9gAc9isHfg_TEdalwhsJcgGLvS9hg,233
94
93
  omlish/collections/cache/descriptor.py,sha256=5SOsKNxnhisJY22l7tujMOI6MGGr6TERzgsfjvGXOyA,5013
95
94
  omlish/collections/cache/impl.py,sha256=Y18OcAsNL6dIWuk89UlZBpqq0iBU-P4VDio6eis43Us,14760
@@ -305,8 +304,9 @@ omlish/formats/toml/codec.py,sha256=5HFGWEPd9IFxPlRMRheX8FEDlRIzLe1moHEOj2_PFKU,
305
304
  omlish/formats/toml/parser.py,sha256=O2M0penQV3t8NAsq_conJjvTsXI8iivUFuBg2a5J3dU,30643
306
305
  omlish/formats/toml/writer.py,sha256=kLLQNEA_Kzd3ue7UXPQ_torOKoaLT82W16Bt99sID-w,3231
307
306
  omlish/funcs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
307
+ omlish/funcs/builders.py,sha256=mJkgvJxM98x5pbMQzRY95tRUsbAfy_ivHtt4fDKfzsM,3984
308
308
  omlish/funcs/genmachine.py,sha256=D9dChaliNBIjYE6lJP5ctcVQUCffNBhceyaaLvBJ7ns,2578
309
- omlish/funcs/match.py,sha256=CTk4aljIAB9DnDpK-v0yfFLjprWjo3hxVr7nThajOZM,6088
309
+ omlish/funcs/match.py,sha256=EPeKojvecnJuDEWaXEYuef0Sx1J6Y0uTL01h4Z8ldxc,6199
310
310
  omlish/funcs/pairs.py,sha256=VCkZjDmJGtR76BsejsHNfb4TcpHCtkkmak-zWDFchAo,3904
311
311
  omlish/funcs/pipes.py,sha256=E7Sz8Aj8ke_vCs5AMNwg1I36kRdHVGTnzxVQaDyn43U,2490
312
312
  omlish/graphs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -419,7 +419,7 @@ omlish/iterators/iterators.py,sha256=RxW35yQ5ed8vBQ22IqpDXFx-i5JiLQdp7-pkMZXhJJ8
419
419
  omlish/iterators/recipes.py,sha256=wOwOZg-zWG9Zc3wcAxJFSe2rtavVBYwZOfG09qYEx_4,472
420
420
  omlish/iterators/tools.py,sha256=M16LXrJhMdsz5ea2qH0vws30ZvhQuQSCVFSLpRf_gTg,2096
421
421
  omlish/iterators/unique.py,sha256=Nw0pSaNEcHAkve0ugfLPvJcirDOn9ECyC5wIL8JlJKI,1395
422
- omlish/lang/__init__.py,sha256=HBfW_xYymqMI480poCq-_7TB5ZxG3HJ7OmZ8XywJlhw,6563
422
+ omlish/lang/__init__.py,sha256=1XbAE88POrWtIHreNk47HAcl6Ch15uTH4cJFo2L7wFM,6619
423
423
  omlish/lang/attrs.py,sha256=zFiVuGVOq88x45464T_LxDa-ZEq_RD9zJLq2zeVEBDc,5105
424
424
  omlish/lang/casing.py,sha256=cFUlbDdXLhwnWwcYx4qnM5c4zGX7hIRUfcjiZbxUD28,4636
425
425
  omlish/lang/clsdct.py,sha256=HAGIvBSbCefzRjXriwYSBLO7QHKRv2UsE78jixOb-fA,1828
@@ -429,6 +429,7 @@ omlish/lang/contextmanagers.py,sha256=7mbTG7yIwM2whQBuhja5Tt0C4kfefBUW4Y_AIn5j8i
429
429
  omlish/lang/datetimes.py,sha256=01tg21QOx-PWDlm-CSFTalym3vpqF0EKzeinmtcVNoU,379
430
430
  omlish/lang/descriptors.py,sha256=zBtgO9LjdSTGHNUgiIqswh78WOVoGH6KzS0NbgB1Wls,6572
431
431
  omlish/lang/enums.py,sha256=F9tflHfaAoV2MpyuhZzpfX9-H55M3zNa9hCszsngEo8,111
432
+ omlish/lang/errors.py,sha256=shcS-NCnEUudF8qC_SmO2TQyjivKlS4TDjaz_faqQ0c,44
432
433
  omlish/lang/functions.py,sha256=aLdxhmqG0Pj9tBgsKdoCu_q15r82WIkNqDDSPQU19L8,5689
433
434
  omlish/lang/generators.py,sha256=a4D5HU_mySs2T2z3xCmE_s3t4QJkj0YRrK4-hhpGd0A,5197
434
435
  omlish/lang/imports.py,sha256=y9W9Y-d_cQ35QCLuSIPoa6vnEqSErFCz8b-34IH128U,10552
@@ -462,7 +463,7 @@ omlish/lifecycles/controller.py,sha256=U_4mfp3n0zxH3RgFrcAi6yODuLIR5RF-uwB2tEBdX
462
463
  omlish/lifecycles/manager.py,sha256=92s1IH_gDP25PM5tFuPMP2hD_6s5fPi_VzZiDS5549g,5449
463
464
  omlish/lifecycles/states.py,sha256=6gTdY3hn7-1sJ60lA3GeMx5RVKvXtFBBXE4KEjoO1Hs,1297
464
465
  omlish/lifecycles/transitions.py,sha256=3IFdWGtAeoy3XRlIyW7yCKV4e4Iof9ytkqklGMRFYQs,1944
465
- omlish/lite/__init__.py,sha256=ISLhM4q0LR1XXTCaHdZOZxBRyIsoZqYm4u0bf1BPcVk,148
466
+ omlish/lite/__init__.py,sha256=cyZEpGob7XjU8DohyNxVe5CQRk4CQ5vrHL42OdhQb8w,148
466
467
  omlish/lite/args.py,sha256=_py7azSCqPJwA2P1qY0B91sSiORsvYIK7IBO6hPDYK4,739
467
468
  omlish/lite/cached.py,sha256=O7ozcoDNFm1Hg2wtpHEqYSp_i_nCLNOP6Ueq_Uk-7mU,1300
468
469
  omlish/lite/check.py,sha256=ytCkwZoKfOlJqylL-AGm8C2WfsWJd2q3kFbnZCzX3_M,13844
@@ -471,7 +472,7 @@ omlish/lite/contextmanagers.py,sha256=jpMxp5xwooRQJxsQ6J2ll4AJP9O7a5_YrLCGgwUFfD
471
472
  omlish/lite/dataclasses.py,sha256=aRSCZz1jN_UI-CWJhN0SJeKxa-79vXNUZ6YOMgG31SE,3610
472
473
  omlish/lite/imports.py,sha256=JDYRFxu-ofHEBfd5VV3b27oKOLhtTpuzte1_Nt7yLgw,1352
473
474
  omlish/lite/inject.py,sha256=xvmLmtD3_2INnkurJQv76_Rkh9usbApEQrXJ4cvuVAk,29019
474
- omlish/lite/json.py,sha256=7-02Ny4fq-6YAu5ynvqoijhuYXWpLmfCI19GUeZnb1c,740
475
+ omlish/lite/json.py,sha256=m0Ce9eqUZG23-H7-oOp8n1sf4fzno5vtK4AK_4Vc-Mg,706
475
476
  omlish/lite/logs.py,sha256=CWFG0NKGhqNeEgryF5atN2gkPYbUdTINEw_s1phbINM,51
476
477
  omlish/lite/marshal.py,sha256=dxiDtmSXt4EBpTprMNkPsOYkRs0W9AC3Kby9UGEjuRo,20400
477
478
  omlish/lite/maybes.py,sha256=0p_fzb6yiOjEpvMKaQ53Q6CH1VPW1or7v7Lt1JIKcgM,4359
@@ -792,10 +793,10 @@ omlish/testing/pytest/plugins/switches/plugin.py,sha256=RBxjefl9RDJuSmT_W0lTSd9D
792
793
  omlish/testing/pytest/plugins/switches/switches.py,sha256=lj8S9RMwUAW7a93ZqqTjoD4dRVkeGts2sl8Cn-H17hc,1890
793
794
  omlish/testing/unittest/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
794
795
  omlish/testing/unittest/__main__.py,sha256=d23loR_cKfTYZwYiqpt_CmKI7dd5WcYFgIYzqMep75E,68
795
- omlish/testing/unittest/loading.py,sha256=DT6vIZwXBkbEXocaxhrbWj8SqsoP7pyxD5K3bZlAE34,4764
796
- omlish/testing/unittest/main.py,sha256=QYVLFzDlkzgyKt7P3V7wG9DoKekrOJHWYeFpI9nX2Vo,8451
797
- omlish/testing/unittest/running.py,sha256=sifL1gjhn1VR965T9fdZy8NbJpVtpEQety8ngh5Fw7A,11821
798
- omlish/testing/unittest/types.py,sha256=RvQwU9l2amH2mKv3W3QyPBFg0eXkQ8wWnIJeRXeDdi0,102
796
+ omlish/testing/unittest/loading.py,sha256=JBiCO0iv0moal2fXILic6iojLxsahMNqinIU-jMWbXg,4820
797
+ omlish/testing/unittest/main.py,sha256=R6Kevx8LyUjI2DSaE0IdhPwrO5AOXRNCJ8mYBNXJiUI,8574
798
+ omlish/testing/unittest/running.py,sha256=QBaj1ZNpMPMbPeFDmqRwuA9TMKE6O3b8Ck9QbUfuKWI,11974
799
+ omlish/testing/unittest/types.py,sha256=56ACNtKt-w_cx7Olsy-m1FYvcUHWsjou9ftXB6CWzeY,110
799
800
  omlish/text/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
800
801
  omlish/text/asdl.py,sha256=AS3irh-sag5pqyH3beJif78PjCbOaFso1NeKq-HXuTs,16867
801
802
  omlish/text/decoding.py,sha256=sQWGckWzRslRHYKpj1SBeoo6AVqXm5HFlWFRARN1QpM,1286
@@ -805,7 +806,7 @@ omlish/text/glyphsplit.py,sha256=ZX9mhwTtmUE8rJpuD1jBO1CTc6xzmBCtbfiHmp5vMM8,381
805
806
  omlish/text/indent.py,sha256=BWVVaHs_B1ppwHJJIxKCDG3iCutkYy5e1qr59Z_Suzg,1524
806
807
  omlish/text/linecache.py,sha256=hRYlEhD63ZfA6_ZOTkQIcnON-3W56QMAhcG3vEJqj9M,1858
807
808
  omlish/text/mangle.py,sha256=k7mYavVgxJ2ENV2wfjw3c9u3hqH5NeVpjoxYbyaYC0Y,2796
808
- omlish/text/minja.py,sha256=J5EqqMXovBeXrmjnYbhhbF2G-CbfRX31o2Od4-571MA,9667
809
+ omlish/text/minja.py,sha256=7UKNalkWpTG_364OIo7p5ym--uiNPR2RFBW_W8rrO4I,9194
809
810
  omlish/text/parts.py,sha256=MpiCUyfpcL4PLb2Etj8V7Yj4qofhy0xVwBrIL6RfNdg,6646
810
811
  omlish/text/random.py,sha256=8feS5JE_tSjYlMl-lp0j93kCfzBae9AM2cXlRLebXMA,199
811
812
  omlish/text/templating.py,sha256=Nf5BVDgrYBf0WmYwV6SnHPDvl9XVMu8v7MX78pInLTw,3325
@@ -889,9 +890,9 @@ omlish/typedvalues/marshal.py,sha256=AtBz7Jq-BfW8vwM7HSxSpR85JAXmxK2T0xDblmm1HI0
889
890
  omlish/typedvalues/of_.py,sha256=UXkxSj504WI2UrFlqdZJbu2hyDwBhL7XVrc2qdR02GQ,1309
890
891
  omlish/typedvalues/reflect.py,sha256=PAvKW6T4cW7u--iX80w3HWwZUS3SmIZ2_lQjT65uAyk,1026
891
892
  omlish/typedvalues/values.py,sha256=ym46I-q2QJ_6l4UlERqv3yj87R-kp8nCKMRph0xQ3UA,1307
892
- omlish-0.0.0.dev374.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
893
- omlish-0.0.0.dev374.dist-info/METADATA,sha256=CeT0SThiC6g7bnfBZYK1i5VyICnv96WDnWJvzSrwBdA,4416
894
- omlish-0.0.0.dev374.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
895
- omlish-0.0.0.dev374.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
896
- omlish-0.0.0.dev374.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
897
- omlish-0.0.0.dev374.dist-info/RECORD,,
893
+ omlish-0.0.0.dev375.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
894
+ omlish-0.0.0.dev375.dist-info/METADATA,sha256=IhVfzMkNMySdjER4EgktRUN72cnUv-EMyJ5Y3sCZ2Vk,4416
895
+ omlish-0.0.0.dev375.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
896
+ omlish-0.0.0.dev375.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
897
+ omlish-0.0.0.dev375.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
898
+ omlish-0.0.0.dev375.dist-info/RECORD,,
File without changes