omlish 0.0.0.dev373__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 +2 -2
- omlish/collections/__init__.py +0 -4
- omlish/collections/mappings.py +19 -1
- omlish/collections/utils.py +2 -3
- omlish/funcs/builders.py +162 -0
- omlish/funcs/match.py +2 -0
- omlish/lang/__init__.py +8 -1
- omlish/lang/functions.py +0 -32
- omlish/lite/__init__.py +1 -1
- omlish/lite/args.py +36 -0
- omlish/lite/json.py +2 -2
- omlish/testing/unittest/loading.py +9 -9
- omlish/testing/unittest/main.py +26 -21
- omlish/testing/unittest/running.py +28 -27
- omlish/testing/unittest/types.py +1 -1
- omlish/text/minja.py +20 -19
- {omlish-0.0.0.dev373.dist-info → omlish-0.0.0.dev375.dist-info}/METADATA +1 -1
- {omlish-0.0.0.dev373.dist-info → omlish-0.0.0.dev375.dist-info}/RECORD +23 -21
- /omlish/{collections → lang}/errors.py +0 -0
- {omlish-0.0.0.dev373.dist-info → omlish-0.0.0.dev375.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev373.dist-info → omlish-0.0.0.dev375.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev373.dist-info → omlish-0.0.0.dev375.dist-info}/licenses/LICENSE +0 -0
- {omlish-0.0.0.dev373.dist-info → omlish-0.0.0.dev375.dist-info}/top_level.txt +0 -0
omlish/__about__.py
CHANGED
omlish/collections/__init__.py
CHANGED
omlish/collections/mappings.py
CHANGED
@@ -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]) ->
|
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:
|
omlish/collections/utils.py
CHANGED
@@ -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
|
omlish/funcs/builders.py
ADDED
@@ -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
omlish/lang/__init__.py
CHANGED
@@ -173,8 +173,11 @@ 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
|
-
Args,
|
178
181
|
VoidError,
|
179
182
|
as_async,
|
180
183
|
call_with,
|
@@ -359,6 +362,10 @@ from .typing import ( # noqa
|
|
359
362
|
|
360
363
|
##
|
361
364
|
|
365
|
+
from ..lite.args import ( # noqa
|
366
|
+
Args,
|
367
|
+
)
|
368
|
+
|
362
369
|
from ..lite.contextmanagers import ( # noqa
|
363
370
|
AsyncExitStacked,
|
364
371
|
ExitStacked,
|
omlish/lang/functions.py
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
import dataclasses as dc
|
2
1
|
import functools
|
3
2
|
import time
|
4
3
|
import types
|
@@ -210,37 +209,6 @@ def periodically(
|
|
210
209
|
##
|
211
210
|
|
212
211
|
|
213
|
-
@dc.dataclass(init=False)
|
214
|
-
class Args:
|
215
|
-
args: ta.Sequence[ta.Any]
|
216
|
-
kwargs: ta.Mapping[str, ta.Any]
|
217
|
-
|
218
|
-
def __init__(self, *args: ta.Any, **kwargs: ta.Any) -> None:
|
219
|
-
super().__init__()
|
220
|
-
|
221
|
-
self.args = args
|
222
|
-
self.kwargs = kwargs
|
223
|
-
|
224
|
-
def __bool__(self) -> bool:
|
225
|
-
return bool(self.args) or bool(self.kwargs)
|
226
|
-
|
227
|
-
def update(self, *args: ta.Any, **kwargs: ta.Any) -> 'Args':
|
228
|
-
return Args(
|
229
|
-
*self.args,
|
230
|
-
*args,
|
231
|
-
**{
|
232
|
-
**self.kwargs,
|
233
|
-
**kwargs,
|
234
|
-
},
|
235
|
-
)
|
236
|
-
|
237
|
-
def __call__(self, fn: ta.Callable[..., T]) -> T:
|
238
|
-
return fn(*self.args, **self.kwargs)
|
239
|
-
|
240
|
-
|
241
|
-
##
|
242
|
-
|
243
|
-
|
244
212
|
def coalesce(*vs: T | None) -> T:
|
245
213
|
for v in vs:
|
246
214
|
if v is not None:
|
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
|
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/args.py
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
import dataclasses as dc
|
2
|
+
import typing as ta
|
3
|
+
|
4
|
+
|
5
|
+
T = ta.TypeVar('T')
|
6
|
+
|
7
|
+
|
8
|
+
##
|
9
|
+
|
10
|
+
|
11
|
+
@dc.dataclass(init=False)
|
12
|
+
class Args:
|
13
|
+
args: ta.Sequence[ta.Any]
|
14
|
+
kwargs: ta.Mapping[str, ta.Any]
|
15
|
+
|
16
|
+
def __init__(self, *args: ta.Any, **kwargs: ta.Any) -> None:
|
17
|
+
super().__init__()
|
18
|
+
|
19
|
+
self.args = args
|
20
|
+
self.kwargs = kwargs
|
21
|
+
|
22
|
+
def __bool__(self) -> bool:
|
23
|
+
return bool(self.args) or bool(self.kwargs)
|
24
|
+
|
25
|
+
def update(self, *args: ta.Any, **kwargs: ta.Any) -> 'Args':
|
26
|
+
return Args(
|
27
|
+
*self.args,
|
28
|
+
*args,
|
29
|
+
**{
|
30
|
+
**self.kwargs,
|
31
|
+
**kwargs,
|
32
|
+
},
|
33
|
+
)
|
34
|
+
|
35
|
+
def __call__(self, fn: ta.Callable[..., T]) -> T:
|
36
|
+
return fn(*self.args, **self.kwargs)
|
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[...,
|
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[...,
|
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
|
46
|
+
from .types import UnittestTest
|
47
47
|
|
48
48
|
|
49
49
|
##
|
50
50
|
|
51
51
|
|
52
|
-
class
|
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) ->
|
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,
|
93
|
-
return ta.cast(
|
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,
|
106
|
-
return ta.cast(
|
105
|
+
if isinstance(target, UnittestTargetLoader.ModuleTarget):
|
106
|
+
return ta.cast(UnittestTest, loader.loadTestsFromModule(module))
|
107
107
|
|
108
|
-
elif isinstance(target,
|
109
|
-
return ta.cast(
|
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
|
))
|
omlish/testing/unittest/main.py
CHANGED
@@ -2,6 +2,9 @@
|
|
2
2
|
"""
|
3
3
|
https://docs.python.org/3/library/unittest.html#command-line-interface
|
4
4
|
~ https://github.com/python/cpython/tree/f66c75f11d3aeeb614600251fd5d3fe1a34b5ff1/Lib/unittest
|
5
|
+
|
6
|
+
TODO:
|
7
|
+
- giving it filenames doesn't work
|
5
8
|
"""
|
6
9
|
# PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
|
7
10
|
# --------------------------------------------
|
@@ -46,25 +49,14 @@ import sys
|
|
46
49
|
import types
|
47
50
|
import typing as ta
|
48
51
|
|
49
|
-
from .loading import
|
50
|
-
from .running import
|
52
|
+
from .loading import UnittestTargetLoader
|
53
|
+
from .running import UnittestTestRunner
|
51
54
|
|
52
55
|
|
53
56
|
##
|
54
57
|
|
55
58
|
|
56
|
-
|
57
|
-
if obj is None:
|
58
|
-
return {}
|
59
|
-
|
60
|
-
return {
|
61
|
-
a: v
|
62
|
-
for a in attrs
|
63
|
-
if (v := getattr(obj, a, None)) is not None
|
64
|
-
}
|
65
|
-
|
66
|
-
|
67
|
-
class TestRunCli:
|
59
|
+
class UnittestRunCli:
|
68
60
|
def __init__(self) -> None:
|
69
61
|
super().__init__()
|
70
62
|
|
@@ -192,9 +184,22 @@ class TestRunCli:
|
|
192
184
|
|
193
185
|
#
|
194
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
|
+
|
195
200
|
IMPORT_PATH_PAT = re.compile(r'[a-zA-Z_][a-zA-Z0-9_]*(?:\.[a-zA-Z_][a-zA-Z0-9_]*)*')
|
196
201
|
|
197
|
-
def _build_target(self, name: str, args: ParsedArgs) ->
|
202
|
+
def _build_target(self, name: str, args: ParsedArgs) -> UnittestTargetLoader.Target:
|
198
203
|
is_discovery = False
|
199
204
|
if os.path.isdir(name):
|
200
205
|
is_discovery = True
|
@@ -204,12 +209,12 @@ class TestRunCli:
|
|
204
209
|
is_discovery = True
|
205
210
|
|
206
211
|
if not is_discovery:
|
207
|
-
return
|
212
|
+
return UnittestTargetLoader.NamesTarget([name])
|
208
213
|
|
209
214
|
else:
|
210
|
-
return
|
215
|
+
return UnittestTargetLoader.DiscoveryTarget(
|
211
216
|
start=name,
|
212
|
-
**_get_attr_dict(
|
217
|
+
**self._get_attr_dict(
|
213
218
|
args.args,
|
214
219
|
'pattern',
|
215
220
|
'top',
|
@@ -226,7 +231,7 @@ class TestRunCli:
|
|
226
231
|
*,
|
227
232
|
exit: bool = False, # noqa
|
228
233
|
) -> None:
|
229
|
-
loader =
|
234
|
+
loader = UnittestTargetLoader(**self._get_attr_dict(
|
230
235
|
args.args,
|
231
236
|
'test_name_patterns',
|
232
237
|
))
|
@@ -236,7 +241,7 @@ class TestRunCli:
|
|
236
241
|
for target_arg in (args.args.target if args.args is not None else None) or [] # noqa
|
237
242
|
]
|
238
243
|
|
239
|
-
runner =
|
244
|
+
runner = UnittestTestRunner(UnittestTestRunner.Args(**self._get_attr_dict(
|
240
245
|
args.args,
|
241
246
|
'verbosity',
|
242
247
|
'failfast',
|
@@ -263,7 +268,7 @@ class TestRunCli:
|
|
263
268
|
|
264
269
|
|
265
270
|
def _main() -> None:
|
266
|
-
cli =
|
271
|
+
cli = UnittestRunCli()
|
267
272
|
args = cli.parse_args(sys.argv[1:])
|
268
273
|
cli.run(args, exit=True)
|
269
274
|
|
@@ -45,30 +45,13 @@ import typing as ta
|
|
45
45
|
import unittest
|
46
46
|
import warnings
|
47
47
|
|
48
|
-
from .types import
|
48
|
+
from .types import UnittestTest
|
49
49
|
|
50
50
|
|
51
51
|
##
|
52
52
|
|
53
53
|
|
54
|
-
class
|
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
|
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['
|
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
|
-
|
237
|
+
UnittestTestRunner.RunResult.TestAndReason(result.getDescription(t), r)
|
237
238
|
for t, r in l
|
238
239
|
]
|
239
240
|
|
240
|
-
return
|
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:
|
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[
|
261
|
-
return
|
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
|
|
omlish/testing/unittest/types.py
CHANGED
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
|
@@ -49,10 +51,15 @@ class MinjaTemplateParam:
|
|
49
51
|
return cls(name, dfl)
|
50
52
|
|
51
53
|
|
54
|
+
class MinjaTemplateFn(ta.Protocol):
|
55
|
+
def __call__(self, **kwargs: ta.Any) -> str:
|
56
|
+
...
|
57
|
+
|
58
|
+
|
52
59
|
class MinjaTemplate:
|
53
60
|
def __init__(
|
54
61
|
self,
|
55
|
-
fn:
|
62
|
+
fn: MinjaTemplateFn,
|
56
63
|
params: ta.Sequence[MinjaTemplateParam],
|
57
64
|
) -> None:
|
58
65
|
super().__init__()
|
@@ -73,7 +80,7 @@ class MinjaTemplate:
|
|
73
80
|
|
74
81
|
class MinjaTemplateCompiler:
|
75
82
|
"""
|
76
|
-
Compiles a template string into a Python
|
83
|
+
Compiles a template string into a Python fn. The returned fn takes a dictionary 'context' and returns
|
77
84
|
the rendered string.
|
78
85
|
|
79
86
|
Supported syntax:
|
@@ -96,6 +103,7 @@ class MinjaTemplateCompiler:
|
|
96
103
|
fragment_processor: ta.Optional[ta.Callable[[MinjaTemplateFragmentKind, str], str]] = None,
|
97
104
|
strict_strings: bool = False,
|
98
105
|
stringifier: ta.Optional[ta.Callable[[ta.Any], str]] = None,
|
106
|
+
fn_builder: ta.Optional[FnBuilder] = None,
|
99
107
|
) -> None:
|
100
108
|
super().__init__()
|
101
109
|
|
@@ -120,6 +128,10 @@ class MinjaTemplateCompiler:
|
|
120
128
|
stringifier = lambda o: str(o)
|
121
129
|
self._stringifier = stringifier
|
122
130
|
|
131
|
+
if fn_builder is None:
|
132
|
+
fn_builder = SimpleFnBuilder()
|
133
|
+
self._fn_builder = fn_builder
|
134
|
+
|
123
135
|
self._stack: ta.List[ta.Literal['for', 'if']] = []
|
124
136
|
|
125
137
|
@staticmethod
|
@@ -210,11 +222,13 @@ class MinjaTemplateCompiler:
|
|
210
222
|
lines.append(f'def {self._RENDER_FN_NAME}():')
|
211
223
|
else:
|
212
224
|
lines.append(f'def {self._RENDER_FN_NAME}(')
|
225
|
+
lines.append(self._indent('*,'))
|
213
226
|
for p in self._params:
|
214
227
|
if p.default.present:
|
215
228
|
check.not_in(p.name, ns)
|
216
|
-
|
217
|
-
|
229
|
+
dn = f'__minja__default__{p.name}'
|
230
|
+
ns[dn] = p.default.must()
|
231
|
+
lines.append(self._indent(f'{p.name}={dn},'))
|
218
232
|
else:
|
219
233
|
lines.append(self._indent(f'{p.name},'))
|
220
234
|
lines.append('):')
|
@@ -269,19 +283,6 @@ class MinjaTemplateCompiler:
|
|
269
283
|
|
270
284
|
#
|
271
285
|
|
272
|
-
@classmethod
|
273
|
-
def _make_fn(
|
274
|
-
cls,
|
275
|
-
name: str,
|
276
|
-
src: str,
|
277
|
-
ns: ta.Optional[ta.Mapping[str, ta.Any]] = None,
|
278
|
-
) -> ta.Callable:
|
279
|
-
glo: dict = {}
|
280
|
-
if ns:
|
281
|
-
glo.update(ns)
|
282
|
-
exec(src, glo)
|
283
|
-
return glo[name]
|
284
|
-
|
285
286
|
def compile(
|
286
287
|
self,
|
287
288
|
ns: ta.Optional[ta.Mapping[str, ta.Any]] = None,
|
@@ -294,14 +295,14 @@ class MinjaTemplateCompiler:
|
|
294
295
|
raise KeyError(k)
|
295
296
|
ns[k] = v
|
296
297
|
|
297
|
-
render_fn = self.
|
298
|
+
render_fn = self._fn_builder.build_fn(
|
298
299
|
self._RENDER_FN_NAME,
|
299
300
|
rendered.src,
|
300
301
|
ns,
|
301
302
|
)
|
302
303
|
|
303
304
|
return MinjaTemplate(
|
304
|
-
render_fn,
|
305
|
+
ta.cast(MinjaTemplateFn, check.callable(render_fn)),
|
305
306
|
self._params,
|
306
307
|
)
|
307
308
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
omlish/.manifests.json,sha256=aT8yZ-Zh-9wfHl5Ym5ouiWC1i0cy7Q7RlhzavB6VLPI,8587
|
2
|
-
omlish/__about__.py,sha256=
|
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
|
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=
|
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=
|
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=
|
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=
|
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,7 +429,8 @@ 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/
|
432
|
+
omlish/lang/errors.py,sha256=shcS-NCnEUudF8qC_SmO2TQyjivKlS4TDjaz_faqQ0c,44
|
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
|
435
436
|
omlish/lang/iterables.py,sha256=y1SX2Co3VsOeX2wlfFF7K3rwLvF7Dtre7VY6EpfwAwA,3338
|
@@ -462,7 +463,8 @@ 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=
|
466
|
+
omlish/lite/__init__.py,sha256=cyZEpGob7XjU8DohyNxVe5CQRk4CQ5vrHL42OdhQb8w,148
|
467
|
+
omlish/lite/args.py,sha256=_py7azSCqPJwA2P1qY0B91sSiORsvYIK7IBO6hPDYK4,739
|
466
468
|
omlish/lite/cached.py,sha256=O7ozcoDNFm1Hg2wtpHEqYSp_i_nCLNOP6Ueq_Uk-7mU,1300
|
467
469
|
omlish/lite/check.py,sha256=ytCkwZoKfOlJqylL-AGm8C2WfsWJd2q3kFbnZCzX3_M,13844
|
468
470
|
omlish/lite/configs.py,sha256=4-1uVxo-aNV7vMKa7PVNhM610eejG1WepB42-Dw2xQI,914
|
@@ -470,7 +472,7 @@ omlish/lite/contextmanagers.py,sha256=jpMxp5xwooRQJxsQ6J2ll4AJP9O7a5_YrLCGgwUFfD
|
|
470
472
|
omlish/lite/dataclasses.py,sha256=aRSCZz1jN_UI-CWJhN0SJeKxa-79vXNUZ6YOMgG31SE,3610
|
471
473
|
omlish/lite/imports.py,sha256=JDYRFxu-ofHEBfd5VV3b27oKOLhtTpuzte1_Nt7yLgw,1352
|
472
474
|
omlish/lite/inject.py,sha256=xvmLmtD3_2INnkurJQv76_Rkh9usbApEQrXJ4cvuVAk,29019
|
473
|
-
omlish/lite/json.py,sha256=
|
475
|
+
omlish/lite/json.py,sha256=m0Ce9eqUZG23-H7-oOp8n1sf4fzno5vtK4AK_4Vc-Mg,706
|
474
476
|
omlish/lite/logs.py,sha256=CWFG0NKGhqNeEgryF5atN2gkPYbUdTINEw_s1phbINM,51
|
475
477
|
omlish/lite/marshal.py,sha256=dxiDtmSXt4EBpTprMNkPsOYkRs0W9AC3Kby9UGEjuRo,20400
|
476
478
|
omlish/lite/maybes.py,sha256=0p_fzb6yiOjEpvMKaQ53Q6CH1VPW1or7v7Lt1JIKcgM,4359
|
@@ -791,10 +793,10 @@ omlish/testing/pytest/plugins/switches/plugin.py,sha256=RBxjefl9RDJuSmT_W0lTSd9D
|
|
791
793
|
omlish/testing/pytest/plugins/switches/switches.py,sha256=lj8S9RMwUAW7a93ZqqTjoD4dRVkeGts2sl8Cn-H17hc,1890
|
792
794
|
omlish/testing/unittest/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
|
793
795
|
omlish/testing/unittest/__main__.py,sha256=d23loR_cKfTYZwYiqpt_CmKI7dd5WcYFgIYzqMep75E,68
|
794
|
-
omlish/testing/unittest/loading.py,sha256=
|
795
|
-
omlish/testing/unittest/main.py,sha256=
|
796
|
-
omlish/testing/unittest/running.py,sha256=
|
797
|
-
omlish/testing/unittest/types.py,sha256=
|
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
|
798
800
|
omlish/text/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
799
801
|
omlish/text/asdl.py,sha256=AS3irh-sag5pqyH3beJif78PjCbOaFso1NeKq-HXuTs,16867
|
800
802
|
omlish/text/decoding.py,sha256=sQWGckWzRslRHYKpj1SBeoo6AVqXm5HFlWFRARN1QpM,1286
|
@@ -804,7 +806,7 @@ omlish/text/glyphsplit.py,sha256=ZX9mhwTtmUE8rJpuD1jBO1CTc6xzmBCtbfiHmp5vMM8,381
|
|
804
806
|
omlish/text/indent.py,sha256=BWVVaHs_B1ppwHJJIxKCDG3iCutkYy5e1qr59Z_Suzg,1524
|
805
807
|
omlish/text/linecache.py,sha256=hRYlEhD63ZfA6_ZOTkQIcnON-3W56QMAhcG3vEJqj9M,1858
|
806
808
|
omlish/text/mangle.py,sha256=k7mYavVgxJ2ENV2wfjw3c9u3hqH5NeVpjoxYbyaYC0Y,2796
|
807
|
-
omlish/text/minja.py,sha256=
|
809
|
+
omlish/text/minja.py,sha256=7UKNalkWpTG_364OIo7p5ym--uiNPR2RFBW_W8rrO4I,9194
|
808
810
|
omlish/text/parts.py,sha256=MpiCUyfpcL4PLb2Etj8V7Yj4qofhy0xVwBrIL6RfNdg,6646
|
809
811
|
omlish/text/random.py,sha256=8feS5JE_tSjYlMl-lp0j93kCfzBae9AM2cXlRLebXMA,199
|
810
812
|
omlish/text/templating.py,sha256=Nf5BVDgrYBf0WmYwV6SnHPDvl9XVMu8v7MX78pInLTw,3325
|
@@ -888,9 +890,9 @@ omlish/typedvalues/marshal.py,sha256=AtBz7Jq-BfW8vwM7HSxSpR85JAXmxK2T0xDblmm1HI0
|
|
888
890
|
omlish/typedvalues/of_.py,sha256=UXkxSj504WI2UrFlqdZJbu2hyDwBhL7XVrc2qdR02GQ,1309
|
889
891
|
omlish/typedvalues/reflect.py,sha256=PAvKW6T4cW7u--iX80w3HWwZUS3SmIZ2_lQjT65uAyk,1026
|
890
892
|
omlish/typedvalues/values.py,sha256=ym46I-q2QJ_6l4UlERqv3yj87R-kp8nCKMRph0xQ3UA,1307
|
891
|
-
omlish-0.0.0.
|
892
|
-
omlish-0.0.0.
|
893
|
-
omlish-0.0.0.
|
894
|
-
omlish-0.0.0.
|
895
|
-
omlish-0.0.0.
|
896
|
-
omlish-0.0.0.
|
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
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|