omlish 0.0.0.dev404__py3-none-any.whl → 0.0.0.dev405__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 +3 -3
- omlish/codecs/registry.py +1 -4
- omlish/collections/identity.py +3 -0
- omlish/lite/contextmanagers.py +10 -7
- omlish/manifests/globals.py +46 -11
- omlish/manifests/loading.py +257 -144
- {omlish-0.0.0.dev404.dist-info → omlish-0.0.0.dev405.dist-info}/METADATA +3 -3
- {omlish-0.0.0.dev404.dist-info → omlish-0.0.0.dev405.dist-info}/RECORD +12 -12
- {omlish-0.0.0.dev404.dist-info → omlish-0.0.0.dev405.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev404.dist-info → omlish-0.0.0.dev405.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev404.dist-info → omlish-0.0.0.dev405.dist-info}/licenses/LICENSE +0 -0
- {omlish-0.0.0.dev404.dist-info → omlish-0.0.0.dev405.dist-info}/top_level.txt +0 -0
omlish/__about__.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
__version__ = '0.0.0.
|
2
|
-
__revision__ = '
|
1
|
+
__version__ = '0.0.0.dev405'
|
2
|
+
__revision__ = '2845f7bb7c8df0a75acb7e7dece1fc712a54aa05'
|
3
3
|
|
4
4
|
|
5
5
|
#
|
@@ -65,7 +65,7 @@ class Project(ProjectBase):
|
|
65
65
|
|
66
66
|
'formats': [
|
67
67
|
'orjson ~= 3.11',
|
68
|
-
'ujson ~= 5.
|
68
|
+
'ujson ~= 5.11',
|
69
69
|
|
70
70
|
'pyyaml ~= 6.0',
|
71
71
|
|
omlish/codecs/registry.py
CHANGED
@@ -106,10 +106,7 @@ def _install_standard_codecs(registry: CodecRegistry) -> None:
|
|
106
106
|
|
107
107
|
@cached.function
|
108
108
|
def _build_manifest_lazy_loaded_codecs() -> ta.Sequence[LazyLoadedCodec]:
|
109
|
-
|
110
|
-
pkgs = {__package__.split('.')[0], *ldr.discover_packages()} # FIXME
|
111
|
-
mns = ldr.load(*pkgs, only=[LazyLoadedCodec])
|
112
|
-
return [m.value() for m in mns]
|
109
|
+
return manifest_globals.GlobalManifestLoader.load_values_of(LazyLoadedCodec)
|
113
110
|
|
114
111
|
|
115
112
|
def _install_manifest_lazy_loaded_codecs(registry: CodecRegistry) -> None:
|
omlish/collections/identity.py
CHANGED
@@ -102,6 +102,9 @@ class IdentityWeakKeyDictionary(ta.MutableMapping[K, V]):
|
|
102
102
|
|
103
103
|
See also:
|
104
104
|
https://github.com/python-trio/trio/blob/efd785a20721707b52a6e2289a65e25722b30c96/src/trio/_core/_ki.py#L81
|
105
|
+
|
106
|
+
TODO:
|
107
|
+
- audit for freethreaded
|
105
108
|
"""
|
106
109
|
|
107
110
|
def __init__(self, *args: ta.Any, **kwargs: ta.Any) -> None:
|
omlish/lite/contextmanagers.py
CHANGED
@@ -4,8 +4,6 @@ import functools
|
|
4
4
|
import sys
|
5
5
|
import typing as ta
|
6
6
|
|
7
|
-
from .check import check
|
8
|
-
|
9
7
|
|
10
8
|
T = ta.TypeVar('T')
|
11
9
|
ExitStackedT = ta.TypeVar('ExitStackedT', bound='ExitStacked')
|
@@ -50,7 +48,8 @@ class ExitStacked:
|
|
50
48
|
"""
|
51
49
|
|
52
50
|
with self._exit_stacked_init_wrapper():
|
53
|
-
|
51
|
+
if self._exit_stack is not None:
|
52
|
+
raise RuntimeError
|
54
53
|
es = self._exit_stack = contextlib.ExitStack()
|
55
54
|
es.__enter__()
|
56
55
|
try:
|
@@ -78,7 +77,8 @@ class ExitStacked:
|
|
78
77
|
pass
|
79
78
|
|
80
79
|
def _enter_context(self, cm: ta.ContextManager[T]) -> T:
|
81
|
-
es
|
80
|
+
if (es := self._exit_stack) is None:
|
81
|
+
raise RuntimeError
|
82
82
|
return es.enter_context(cm)
|
83
83
|
|
84
84
|
|
@@ -107,7 +107,8 @@ class AsyncExitStacked:
|
|
107
107
|
@ta.final
|
108
108
|
async def __aenter__(self: AsyncExitStackedT) -> AsyncExitStackedT:
|
109
109
|
async with self._async_exit_stacked_init_wrapper():
|
110
|
-
|
110
|
+
if self._exit_stack is not None:
|
111
|
+
raise RuntimeError
|
111
112
|
es = self._exit_stack = contextlib.AsyncExitStack()
|
112
113
|
await es.__aenter__()
|
113
114
|
try:
|
@@ -135,11 +136,13 @@ class AsyncExitStacked:
|
|
135
136
|
pass
|
136
137
|
|
137
138
|
def _enter_context(self, cm: ta.ContextManager[T]) -> T:
|
138
|
-
es
|
139
|
+
if (es := self._exit_stack) is None:
|
140
|
+
raise RuntimeError
|
139
141
|
return es.enter_context(cm)
|
140
142
|
|
141
143
|
async def _enter_async_context(self, cm: ta.AsyncContextManager[T]) -> T:
|
142
|
-
es
|
144
|
+
if (es := self._exit_stack) is None:
|
145
|
+
raise RuntimeError
|
143
146
|
return await es.enter_async_context(cm)
|
144
147
|
|
145
148
|
|
omlish/manifests/globals.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
# ruff: noqa: UP045
|
1
|
+
# ruff: noqa: UP006 UP045
|
2
2
|
# @omlish-lite
|
3
|
+
import os
|
3
4
|
import threading
|
4
5
|
import typing as ta
|
5
6
|
|
@@ -7,6 +8,9 @@ from ..lite.marshal import unmarshal_obj
|
|
7
8
|
from .loading import ManifestLoader
|
8
9
|
|
9
10
|
|
11
|
+
T = ta.TypeVar('T')
|
12
|
+
|
13
|
+
|
10
14
|
##
|
11
15
|
|
12
16
|
|
@@ -28,17 +32,20 @@ class GlobalManifestLoader:
|
|
28
32
|
if (inst := cls._instance) is None:
|
29
33
|
with cls._lock:
|
30
34
|
if (inst := cls._instance) is None:
|
31
|
-
inst = cls._instance = ManifestLoader(
|
35
|
+
inst = cls._instance = ManifestLoader(cls.default_config())
|
32
36
|
|
33
37
|
return inst
|
34
38
|
|
35
39
|
@classmethod
|
36
|
-
def initialize(cls,
|
40
|
+
def initialize(cls, config: ta.Optional[ManifestLoader.Config] = None) -> ManifestLoader:
|
37
41
|
with cls._lock:
|
38
42
|
if cls._instance is not None:
|
39
|
-
raise
|
43
|
+
raise RuntimeError(f'{cls.__name__} already initialized')
|
44
|
+
|
45
|
+
if config is None:
|
46
|
+
config = cls.default_config()
|
40
47
|
|
41
|
-
inst = cls._instance = ManifestLoader(
|
48
|
+
inst = cls._instance = ManifestLoader(config)
|
42
49
|
|
43
50
|
return inst
|
44
51
|
|
@@ -49,8 +56,11 @@ class GlobalManifestLoader:
|
|
49
56
|
return unmarshal_obj(kwargs, obj_cls)
|
50
57
|
|
51
58
|
@classmethod
|
52
|
-
def
|
53
|
-
return
|
59
|
+
def default_config(cls) -> ManifestLoader.Config:
|
60
|
+
return ManifestLoader.Config(
|
61
|
+
discover_packages=True,
|
62
|
+
discover_packages_fallback_scan_root_dirs=[os.getcwd()],
|
63
|
+
|
54
64
|
value_instantiator=cls.default_value_instantiator,
|
55
65
|
)
|
56
66
|
|
@@ -59,10 +69,35 @@ class GlobalManifestLoader:
|
|
59
69
|
@classmethod
|
60
70
|
def load(
|
61
71
|
cls,
|
62
|
-
|
63
|
-
|
72
|
+
*,
|
73
|
+
packages: ta.Optional[ta.Collection[str]] = None,
|
74
|
+
classes: ta.Optional[ta.Collection[type]] = None,
|
64
75
|
) -> ta.Sequence[ManifestLoader.LoadedManifest]:
|
65
76
|
return cls.instance().load(
|
66
|
-
|
67
|
-
|
77
|
+
packages=packages,
|
78
|
+
classes=classes,
|
79
|
+
)
|
80
|
+
|
81
|
+
@classmethod
|
82
|
+
def load_values(
|
83
|
+
cls,
|
84
|
+
*,
|
85
|
+
packages: ta.Optional[ta.Collection[str]] = None,
|
86
|
+
classes: ta.Optional[ta.Collection[type]] = None,
|
87
|
+
) -> ta.Sequence[ta.Any]:
|
88
|
+
return cls.instance().load_values(
|
89
|
+
packages=packages,
|
90
|
+
classes=classes,
|
91
|
+
)
|
92
|
+
|
93
|
+
@classmethod
|
94
|
+
def load_values_of(
|
95
|
+
cls,
|
96
|
+
clz: ta.Type[T],
|
97
|
+
*,
|
98
|
+
packages: ta.Optional[ta.Collection[str]] = None,
|
99
|
+
) -> ta.Sequence[T]:
|
100
|
+
return cls.instance().load_values_of(
|
101
|
+
clz,
|
102
|
+
packages=packages,
|
68
103
|
)
|
omlish/manifests/loading.py
CHANGED
@@ -4,16 +4,13 @@
|
|
4
4
|
Should be kept somewhat lightweight - used in cli entrypoints.
|
5
5
|
|
6
6
|
TODO:
|
7
|
-
- persisted caching support - {pkg_name: manifests}
|
8
7
|
- real relative cls names - shouldn't need parent package names
|
9
|
-
- *require* loaded class names - special All sentinel for explicit all
|
10
|
-
- ! late instantiation !
|
11
8
|
- TypeMap style weak cache of issubclass queries
|
12
9
|
- wait.. lazily load the class for virtual subclass queries? xor support virtual bases?
|
10
|
+
- weakref class dict keys?
|
13
11
|
"""
|
14
12
|
import dataclasses as dc
|
15
13
|
import importlib.machinery
|
16
|
-
import importlib.resources
|
17
14
|
import importlib.util
|
18
15
|
import json
|
19
16
|
import os.path
|
@@ -23,6 +20,9 @@ import typing as ta
|
|
23
20
|
from .types import Manifest
|
24
21
|
|
25
22
|
|
23
|
+
T = ta.TypeVar('T')
|
24
|
+
|
25
|
+
|
26
26
|
##
|
27
27
|
|
28
28
|
|
@@ -38,6 +38,12 @@ class ManifestLoader:
|
|
38
38
|
self._package = package
|
39
39
|
self._manifest = manifest
|
40
40
|
|
41
|
+
[(cls_key, value_dct)] = self._manifest.value.items() # noqa
|
42
|
+
self._cls_key = cls_key
|
43
|
+
|
44
|
+
def __repr__(self) -> str:
|
45
|
+
return f'{self.__class__.__name__}@{id(self):x}(package={self._package!r}, class_key={self._cls_key!r})'
|
46
|
+
|
41
47
|
@property
|
42
48
|
def package(self) -> 'ManifestLoader.LoadedPackage':
|
43
49
|
return self._package
|
@@ -52,8 +58,7 @@ class ManifestLoader:
|
|
52
58
|
|
53
59
|
@property
|
54
60
|
def class_key(self) -> str:
|
55
|
-
|
56
|
-
return cls_key
|
61
|
+
return self._cls_key
|
57
62
|
|
58
63
|
_value: ta.Any
|
59
64
|
|
@@ -80,6 +85,9 @@ class ManifestLoader:
|
|
80
85
|
|
81
86
|
_manifests: ta.Sequence['ManifestLoader.LoadedManifest']
|
82
87
|
|
88
|
+
def __repr__(self) -> str:
|
89
|
+
return f'{self.__class__.__name__}(name={self._name!r})'
|
90
|
+
|
83
91
|
@property
|
84
92
|
def loader(self) -> 'ManifestLoader':
|
85
93
|
return self._loader
|
@@ -92,54 +100,199 @@ class ManifestLoader:
|
|
92
100
|
def manifests(self) -> ta.Sequence['ManifestLoader.LoadedManifest']:
|
93
101
|
return self._manifests
|
94
102
|
|
103
|
+
_manifests_by_class_key: ta.Mapping[str, ta.Sequence['ManifestLoader.LoadedManifest']]
|
104
|
+
|
105
|
+
@property
|
106
|
+
def manifests_by_class_key(self) -> ta.Mapping[str, ta.Sequence['ManifestLoader.LoadedManifest']]:
|
107
|
+
try:
|
108
|
+
return self._manifests_by_class_key
|
109
|
+
except AttributeError:
|
110
|
+
pass
|
111
|
+
|
112
|
+
dct: dict = {}
|
113
|
+
for m in self._manifests:
|
114
|
+
try:
|
115
|
+
lst = dct[m.class_key]
|
116
|
+
except KeyError:
|
117
|
+
lst = dct[m.class_key] = []
|
118
|
+
lst.append(m)
|
119
|
+
self._manifests_by_class_key = dct
|
120
|
+
return dct
|
121
|
+
|
122
|
+
##
|
123
|
+
|
124
|
+
@dc.dataclass(frozen=True)
|
125
|
+
class Config:
|
126
|
+
package_scan_root_dirs: ta.Optional[ta.Collection[str]] = None
|
127
|
+
|
128
|
+
discover_packages: ta.Optional[bool] = None
|
129
|
+
discover_packages_fallback_scan_root_dirs: ta.Optional[ta.Collection[str]] = None
|
130
|
+
|
131
|
+
module_remap: ta.Optional[ta.Mapping[str, str]] = None
|
132
|
+
|
133
|
+
value_instantiator: ta.Optional[ta.Callable[..., ta.Any]] = None
|
134
|
+
|
135
|
+
def __post_init__(self) -> None:
|
136
|
+
if isinstance(self.package_scan_root_dirs, str):
|
137
|
+
raise TypeError(self.package_scan_root_dirs)
|
138
|
+
if isinstance(self.discover_packages_fallback_scan_root_dirs, bool):
|
139
|
+
raise TypeError(self.discover_packages_fallback_scan_root_dirs)
|
140
|
+
|
141
|
+
@classmethod
|
142
|
+
def merge(cls, *configs: 'ManifestLoader.Config') -> 'ManifestLoader.Config':
|
143
|
+
kw: dict = {}
|
144
|
+
for c in configs:
|
145
|
+
for k, v in dc.asdict(c).items():
|
146
|
+
if v is None:
|
147
|
+
continue
|
148
|
+
elif k in ('package_scan_root_dirs', 'discover_packages_fallback_scan_root_dirs'): # noqa
|
149
|
+
kw[k] = [*kw.get(k, []), *v]
|
150
|
+
elif k == 'module_remap':
|
151
|
+
kw[k] = {**kw.get(k, {}), **v}
|
152
|
+
else:
|
153
|
+
kw[k] = v
|
154
|
+
return cls(**kw)
|
155
|
+
|
156
|
+
def __or__(self, other: 'ManifestLoader.Config') -> 'ManifestLoader.Config':
|
157
|
+
return ManifestLoader.Config.merge(self, other)
|
158
|
+
|
95
159
|
def __init__(
|
96
160
|
self,
|
97
|
-
|
98
|
-
module_remap: ta.Optional[ta.Mapping[str, str]] = None,
|
99
|
-
value_instantiator: ta.Optional[ta.Callable[..., ta.Any]] = None,
|
161
|
+
config: Config,
|
100
162
|
) -> None:
|
101
163
|
super().__init__()
|
102
164
|
|
103
|
-
self.
|
104
|
-
self._module_remap = module_remap or {}
|
165
|
+
self._config = config
|
105
166
|
|
106
167
|
self._lock = threading.RLock()
|
107
168
|
|
108
|
-
self.
|
169
|
+
self._module_remap = config.module_remap or {}
|
170
|
+
self._module_reverse_remap = {v: k for k, v in (self._module_remap or {}).items()}
|
109
171
|
|
110
172
|
self._loaded_classes: ta.Dict[str, type] = {}
|
111
173
|
self._loaded_packages: ta.Dict[str, ta.Optional[ManifestLoader.LoadedPackage]] = {}
|
112
174
|
|
113
175
|
self._scanned_package_root_dirs: ta.Dict[str, ta.Sequence[str]] = {}
|
114
176
|
|
115
|
-
|
177
|
+
@property
|
178
|
+
def config(self) -> Config:
|
179
|
+
return self._config
|
116
180
|
|
117
181
|
@classmethod
|
118
|
-
def
|
182
|
+
def config_from_entry_point(
|
119
183
|
cls,
|
120
184
|
globals: ta.Mapping[str, ta.Any], # noqa
|
121
|
-
|
122
|
-
module_remap: ta.Optional[ta.Mapping[str, str]] = None,
|
123
|
-
**kwargs: ta.Any,
|
124
|
-
) -> ta.Dict[str, ta.Any]:
|
185
|
+
) -> Config:
|
125
186
|
rm: ta.Dict[str, str] = {}
|
126
187
|
|
127
|
-
if module_remap:
|
128
|
-
rm.update(module_remap)
|
129
|
-
|
130
188
|
if '__name__' in globals and '__spec__' in globals:
|
131
189
|
name: str = globals['__name__']
|
132
190
|
spec: importlib.machinery.ModuleSpec = globals['__spec__']
|
133
191
|
if '__main__' not in rm and name == '__main__':
|
134
192
|
rm[spec.name] = '__main__'
|
135
193
|
|
136
|
-
return
|
194
|
+
return ManifestLoader.Config(module_remap=rm)
|
137
195
|
|
138
|
-
|
196
|
+
##
|
197
|
+
|
198
|
+
ENTRY_POINT_GROUP: ta.ClassVar[str] = 'omlish.manifests'
|
199
|
+
|
200
|
+
_discovered_packages: ta.ClassVar[ta.Optional[ta.Sequence[str]]] = None
|
201
|
+
|
202
|
+
@classmethod
|
203
|
+
def _discover_packages_uncached(cls) -> ta.Sequence[str]:
|
204
|
+
from importlib import metadata as importlib_metadata # noqa
|
205
|
+
return [
|
206
|
+
ep.value
|
207
|
+
for ep in importlib_metadata.entry_points(group=cls.ENTRY_POINT_GROUP)
|
208
|
+
]
|
209
|
+
|
210
|
+
@classmethod
|
211
|
+
def discover_packages(cls) -> ta.Sequence[str]:
|
212
|
+
if (x := cls._discovered_packages) is not None:
|
213
|
+
return x
|
214
|
+
|
215
|
+
x = cls._discover_packages_uncached()
|
216
|
+
cls._discovered_packages = x
|
217
|
+
return x
|
218
|
+
|
219
|
+
##
|
220
|
+
|
221
|
+
def _scan_package_root_dir_uncached(
|
222
|
+
self,
|
223
|
+
root_dir: str,
|
224
|
+
) -> ta.Sequence[str]:
|
225
|
+
pkgs: ta.List[str] = []
|
226
|
+
|
227
|
+
for n in os.listdir(root_dir):
|
228
|
+
if (
|
229
|
+
os.path.isdir(p := os.path.join(root_dir, n)) and
|
230
|
+
os.path.exists(os.path.join(p, '__init__.py'))
|
231
|
+
):
|
232
|
+
pkgs.append(n)
|
233
|
+
|
234
|
+
return pkgs
|
235
|
+
|
236
|
+
def _scan_package_root_dir_locked(
|
237
|
+
self,
|
238
|
+
root_dir: str,
|
239
|
+
) -> ta.Sequence[str]:
|
240
|
+
try:
|
241
|
+
return self._scanned_package_root_dirs[root_dir]
|
242
|
+
except KeyError:
|
243
|
+
pass
|
244
|
+
|
245
|
+
ret = self._scan_package_root_dir_uncached(root_dir)
|
246
|
+
self._scanned_package_root_dirs[root_dir] = ret
|
247
|
+
return ret
|
248
|
+
|
249
|
+
def _scan_package_root_dir(
|
250
|
+
self,
|
251
|
+
root_dir: str,
|
252
|
+
) -> ta.Sequence[str]:
|
253
|
+
with self._lock:
|
254
|
+
return self._scan_package_root_dir_locked(root_dir)
|
255
|
+
|
256
|
+
##
|
257
|
+
|
258
|
+
_detected_packages: ta.Set[str]
|
259
|
+
|
260
|
+
def _do_initialize(self) -> None:
|
261
|
+
self._detected_packages = set()
|
262
|
+
|
263
|
+
for r in self._config.package_scan_root_dirs or []:
|
264
|
+
self._detected_packages.update(self._scan_package_root_dir_locked(r))
|
265
|
+
|
266
|
+
if self._config.discover_packages:
|
267
|
+
self._detected_packages.update(dps := self.discover_packages())
|
268
|
+
if not dps:
|
269
|
+
for r in self._config.discover_packages_fallback_scan_root_dirs or []:
|
270
|
+
self._detected_packages.update(self._scan_package_root_dir_locked(r))
|
271
|
+
|
272
|
+
_has_initialized = False
|
273
|
+
|
274
|
+
def _initialize_locked(self) -> None:
|
275
|
+
if not self._has_initialized:
|
276
|
+
self._do_initialize()
|
277
|
+
self._has_initialized = True
|
278
|
+
|
279
|
+
def has_initialized(self) -> bool:
|
280
|
+
with self._lock:
|
281
|
+
return self._has_initialized
|
282
|
+
|
283
|
+
def initialize(self) -> None:
|
284
|
+
if not self._has_initialized:
|
285
|
+
with self._lock:
|
286
|
+
self._initialize_locked()
|
287
|
+
|
288
|
+
##
|
289
|
+
|
290
|
+
class ClassKeyError(Exception):
|
291
|
+
pass
|
139
292
|
|
140
293
|
def _load_class_uncached(self, key: str) -> type:
|
141
294
|
if not key.startswith('$'):
|
142
|
-
raise
|
295
|
+
raise ManifestLoader.ClassKeyError(key)
|
143
296
|
|
144
297
|
parts = key[1:].split('.')
|
145
298
|
pos = next(i for i, p in enumerate(parts) if p[0].isupper())
|
@@ -172,7 +325,14 @@ class ManifestLoader:
|
|
172
325
|
with self._lock:
|
173
326
|
return self._load_class_locked(key)
|
174
327
|
|
175
|
-
|
328
|
+
def get_class_key(self, cls: type) -> str:
|
329
|
+
if not (isinstance(cls, type) and dc.is_dataclass(cls)):
|
330
|
+
raise TypeError(cls)
|
331
|
+
mod_name = cls.__module__
|
332
|
+
mod_name = self._module_reverse_remap.get(mod_name, mod_name)
|
333
|
+
return f'${mod_name}.{cls.__qualname__}'
|
334
|
+
|
335
|
+
##
|
176
336
|
|
177
337
|
def _deserialize_raw_manifests(self, obj: ta.Any, pkg_name: str) -> ta.Sequence[Manifest]:
|
178
338
|
if not isinstance(obj, (list, tuple)):
|
@@ -186,7 +346,7 @@ class ManifestLoader:
|
|
186
346
|
|
187
347
|
[(key, value_dct)] = m.value.items()
|
188
348
|
if not key.startswith('$'):
|
189
|
-
raise
|
349
|
+
raise ManifestLoader.ClassKeyError(key)
|
190
350
|
if key.startswith('$.'):
|
191
351
|
key = f'${pkg_name}{key[1:]}'
|
192
352
|
m = dc.replace(m, value={key: value_dct})
|
@@ -214,11 +374,14 @@ class ManifestLoader:
|
|
214
374
|
with open(file_path, encoding='utf-8') as f:
|
215
375
|
return f.read()
|
216
376
|
|
217
|
-
|
377
|
+
from importlib import resources as importlib_resources # noqa
|
378
|
+
t = importlib_resources.files(pkg_name).joinpath(file_name)
|
218
379
|
if not t.is_file():
|
219
380
|
return None
|
220
381
|
return t.read_text('utf-8')
|
221
382
|
|
383
|
+
#
|
384
|
+
|
222
385
|
MANIFESTS_FILE_NAME: ta.ClassVar[str] = '.manifests.json'
|
223
386
|
|
224
387
|
def _load_package_uncached(self, pkg_name: str) -> ta.Optional[LoadedPackage]:
|
@@ -258,11 +421,11 @@ class ManifestLoader:
|
|
258
421
|
with self._lock:
|
259
422
|
return self._load_package_locked(pkg_name)
|
260
423
|
|
261
|
-
|
424
|
+
##
|
262
425
|
|
263
426
|
def _instantiate_value(self, cls: type, **kwargs: ta.Any) -> ta.Any:
|
264
|
-
if self.
|
265
|
-
return self.
|
427
|
+
if self._config.value_instantiator is not None:
|
428
|
+
return self._config.value_instantiator(cls, **kwargs)
|
266
429
|
else:
|
267
430
|
return cls(**kwargs)
|
268
431
|
|
@@ -272,139 +435,89 @@ class ManifestLoader:
|
|
272
435
|
value = self._instantiate_value(cls, **value_dct)
|
273
436
|
return value
|
274
437
|
|
275
|
-
|
276
|
-
|
277
|
-
# FIXME:
|
278
|
-
# class LOAD_ALL: # noqa
|
279
|
-
# def __new__(cls, *args, **kwargs): # noqa
|
280
|
-
# raise TypeError
|
281
|
-
#
|
282
|
-
# def __init_subclass__(cls, **kwargs): # noqa
|
283
|
-
# raise TypeError
|
438
|
+
##
|
284
439
|
|
285
|
-
def
|
440
|
+
def _load_initialized(
|
286
441
|
self,
|
287
|
-
|
288
|
-
|
442
|
+
*,
|
443
|
+
packages: ta.Optional[ta.Collection[str]] = None,
|
444
|
+
classes: ta.Optional[ta.Collection[type]] = None,
|
289
445
|
) -> ta.Sequence[LoadedManifest]:
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
else:
|
300
|
-
only_keys = None
|
446
|
+
if isinstance(packages, str):
|
447
|
+
raise TypeError(packages)
|
448
|
+
|
449
|
+
class_keys: ta.Optional[ta.Set[str]] = None
|
450
|
+
if classes is not None:
|
451
|
+
class_keys = {self.get_class_key(cls) for cls in classes}
|
452
|
+
|
453
|
+
if packages is None:
|
454
|
+
packages = self._detected_packages
|
301
455
|
|
302
456
|
lst: ta.List[ManifestLoader.LoadedManifest] = []
|
303
|
-
for pn in
|
304
|
-
lp
|
305
|
-
if lp is None:
|
457
|
+
for pn in packages:
|
458
|
+
if (lp := self._load_package_locked(pn)) is None:
|
306
459
|
continue
|
307
460
|
|
308
|
-
|
309
|
-
|
310
|
-
|
461
|
+
if class_keys is not None:
|
462
|
+
for ck in class_keys:
|
463
|
+
lst.extend(lp.manifests_by_class_key.get(ck, []))
|
311
464
|
|
312
|
-
|
465
|
+
else:
|
466
|
+
lst.extend(lp.manifests)
|
313
467
|
|
314
468
|
return lst
|
315
469
|
|
470
|
+
def _load_locked(
|
471
|
+
self,
|
472
|
+
*,
|
473
|
+
packages: ta.Optional[ta.Collection[str]] = None,
|
474
|
+
classes: ta.Optional[ta.Collection[type]] = None,
|
475
|
+
) -> ta.Sequence[LoadedManifest]:
|
476
|
+
self._initialize_locked()
|
477
|
+
return self._load_initialized(
|
478
|
+
packages=packages,
|
479
|
+
classes=classes,
|
480
|
+
)
|
481
|
+
|
316
482
|
def load(
|
317
483
|
self,
|
318
|
-
|
319
|
-
|
484
|
+
*,
|
485
|
+
packages: ta.Optional[ta.Collection[str]] = None,
|
486
|
+
classes: ta.Optional[ta.Collection[type]] = None,
|
320
487
|
) -> ta.Sequence[LoadedManifest]:
|
488
|
+
if isinstance(packages, str):
|
489
|
+
raise TypeError(packages)
|
490
|
+
|
321
491
|
with self._lock:
|
322
|
-
return self.
|
323
|
-
|
324
|
-
|
492
|
+
return self._load_locked(
|
493
|
+
packages=packages,
|
494
|
+
classes=classes,
|
325
495
|
)
|
326
496
|
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
@classmethod
|
334
|
-
def _discover_packages_uncached(cls) -> ta.Sequence[str]:
|
335
|
-
# This is a fat dep so do it late.
|
336
|
-
from importlib import metadata as importlib_metadata # noqa
|
337
|
-
|
497
|
+
def load_values(
|
498
|
+
self,
|
499
|
+
*,
|
500
|
+
packages: ta.Optional[ta.Collection[str]] = None,
|
501
|
+
classes: ta.Optional[ta.Collection[type]] = None,
|
502
|
+
) -> ta.Sequence[ta.Any]:
|
338
503
|
return [
|
339
|
-
|
340
|
-
for
|
504
|
+
lm.value()
|
505
|
+
for lm in self.load(
|
506
|
+
packages=packages,
|
507
|
+
classes=classes,
|
508
|
+
)
|
341
509
|
]
|
342
510
|
|
343
|
-
|
344
|
-
def discover_packages(cls) -> ta.Sequence[str]:
|
345
|
-
if (x := cls._discovered_packages) is not None:
|
346
|
-
return x
|
347
|
-
|
348
|
-
x = cls._discover_packages_uncached()
|
349
|
-
cls._discovered_packages = x
|
350
|
-
return x
|
351
|
-
|
352
|
-
##
|
353
|
-
|
354
|
-
def _scan_package_root_dir_uncached(
|
355
|
-
self,
|
356
|
-
root_dir: str,
|
357
|
-
) -> ta.Sequence[str]:
|
358
|
-
pkgs: ta.List[str] = []
|
359
|
-
|
360
|
-
for n in os.listdir(root_dir):
|
361
|
-
if (
|
362
|
-
os.path.isdir(p := os.path.join(root_dir, n)) and
|
363
|
-
os.path.exists(os.path.join(p, '__init__.py'))
|
364
|
-
):
|
365
|
-
pkgs.append(n)
|
366
|
-
|
367
|
-
return pkgs
|
368
|
-
|
369
|
-
def _scan_package_root_dir_locked(
|
370
|
-
self,
|
371
|
-
root_dir: str,
|
372
|
-
) -> ta.Sequence[str]:
|
373
|
-
try:
|
374
|
-
return self._scanned_package_root_dirs[root_dir]
|
375
|
-
except KeyError:
|
376
|
-
pass
|
377
|
-
|
378
|
-
ret = self._scan_package_root_dir_uncached(root_dir)
|
379
|
-
self._scanned_package_root_dirs[root_dir] = ret
|
380
|
-
return ret
|
381
|
-
|
382
|
-
def _scan_package_root_dir(
|
383
|
-
self,
|
384
|
-
root_dir: str,
|
385
|
-
) -> ta.Sequence[str]:
|
386
|
-
with self._lock:
|
387
|
-
return self._scan_package_root_dir_locked(root_dir)
|
388
|
-
|
389
|
-
def scan_or_discover_packages(
|
511
|
+
def load_values_of(
|
390
512
|
self,
|
513
|
+
cls: ta.Type[T],
|
391
514
|
*,
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
for r in specified_root_dirs:
|
402
|
-
pkgs.extend(self._scan_package_root_dir(r))
|
403
|
-
|
404
|
-
else:
|
405
|
-
pkgs.extend(self.discover_packages())
|
406
|
-
|
407
|
-
if not pkgs and fallback_root_dir is not None:
|
408
|
-
pkgs.extend(self._scan_package_root_dir(fallback_root_dir))
|
409
|
-
|
410
|
-
return pkgs
|
515
|
+
packages: ta.Optional[ta.Collection[str]] = None,
|
516
|
+
) -> ta.Sequence[T]:
|
517
|
+
return [
|
518
|
+
ta.cast(T, lm.value())
|
519
|
+
for lm in self.load(
|
520
|
+
packages=packages,
|
521
|
+
classes=[cls],
|
522
|
+
)
|
523
|
+
]
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: omlish
|
3
|
-
Version: 0.0.0.
|
3
|
+
Version: 0.0.0.dev405
|
4
4
|
Summary: omlish
|
5
5
|
Author: wrmsr
|
6
6
|
License-Expression: BSD-3-Clause
|
@@ -28,7 +28,7 @@ Requires-Dist: asttokens~=3.0; extra == "all"
|
|
28
28
|
Requires-Dist: executing~=2.2; extra == "all"
|
29
29
|
Requires-Dist: psutil~=7.0; extra == "all"
|
30
30
|
Requires-Dist: orjson~=3.11; extra == "all"
|
31
|
-
Requires-Dist: ujson~=5.
|
31
|
+
Requires-Dist: ujson~=5.11; extra == "all"
|
32
32
|
Requires-Dist: pyyaml~=6.0; extra == "all"
|
33
33
|
Requires-Dist: cbor2~=5.7; extra == "all"
|
34
34
|
Requires-Dist: cloudpickle~=3.1; extra == "all"
|
@@ -71,7 +71,7 @@ Requires-Dist: executing~=2.2; extra == "diag"
|
|
71
71
|
Requires-Dist: psutil~=7.0; extra == "diag"
|
72
72
|
Provides-Extra: formats
|
73
73
|
Requires-Dist: orjson~=3.11; extra == "formats"
|
74
|
-
Requires-Dist: ujson~=5.
|
74
|
+
Requires-Dist: ujson~=5.11; extra == "formats"
|
75
75
|
Requires-Dist: pyyaml~=6.0; extra == "formats"
|
76
76
|
Requires-Dist: cbor2~=5.7; extra == "formats"
|
77
77
|
Requires-Dist: cloudpickle~=3.1; extra == "formats"
|
@@ -1,5 +1,5 @@
|
|
1
1
|
omlish/.manifests.json,sha256=ftpXGlXqsqDmBh0eWXtndZBLj8Y6QVhS5g5lKgEAf3U,8587
|
2
|
-
omlish/__about__.py,sha256=
|
2
|
+
omlish/__about__.py,sha256=Zu2-AzTYNiCm8KVyeTpwqEU8oCTBUlyG8PBMsAwgeQI,3601
|
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
|
@@ -73,7 +73,7 @@ omlish/codecs/base.py,sha256=IVnJlduvhiH1imul4DPhl2gHBWS76774AV5h86dX0ls,2214
|
|
73
73
|
omlish/codecs/bytes.py,sha256=3DxyQQCvFcP3mQ5G93f_mygXEb-7I8buM8EyzUcx2Is,2155
|
74
74
|
omlish/codecs/chain.py,sha256=nbkL2nz0ZqT2lxYwSXktHh1YFTQ4Iii1Hp-fWjis6rc,532
|
75
75
|
omlish/codecs/funcs.py,sha256=or0Jogczuzk7csDTRl-HURMEjl8LXXqxxXYK45xcM5w,855
|
76
|
-
omlish/codecs/registry.py,sha256=
|
76
|
+
omlish/codecs/registry.py,sha256=PDfo0UtVZ96SILe5w4piPpWR-cjh1NiixKeSS7LgQKk,4003
|
77
77
|
omlish/codecs/standard.py,sha256=eiZ4u9ep0XrA4Z_D1zJI0vmWyuN8HLrX4Se_r_Cq_ZM,60
|
78
78
|
omlish/codecs/text.py,sha256=uHhV8jBgH0iZgcrV0nl4-0a_9ofln4iFH4OXoVm2CW4,5709
|
79
79
|
omlish/collections/__init__.py,sha256=BIc806ri5Eq-kR03Ya2YfYTRI0g1rn_0haQPUqxXqys,2816
|
@@ -82,7 +82,7 @@ omlish/collections/bimap.py,sha256=3szDCscPJlFRtkpyVQNWneg4s50mr6Rd0jdTzVEIcnE,1
|
|
82
82
|
omlish/collections/coerce.py,sha256=tAls15v_7p5bUN33R7Zbko87KW5toWHl9fRialCqyNY,7030
|
83
83
|
omlish/collections/frozen.py,sha256=LMbAHYDENIQk1hvjCTvpnx66m1TalrHa4CSn8n_tsXQ,4142
|
84
84
|
omlish/collections/hasheq.py,sha256=uHypfZlHhicQPvx9OOlpT9MSLwfc_mFil-WaxF9dTOo,3732
|
85
|
-
omlish/collections/identity.py,sha256=
|
85
|
+
omlish/collections/identity.py,sha256=00UAYIjCRhyj73Es0jVNvOloXjRxHcjRxGQeWo75OEo,4834
|
86
86
|
omlish/collections/mappings.py,sha256=lAzKP9RONLjFH7emIDoY-6jukuD-Sa7fdxzP7u6qrqU,3261
|
87
87
|
omlish/collections/multimaps.py,sha256=8Sqi1iVxUObnL47s8b1esa2TERoiEyyY4RBWF1VjDiw,3820
|
88
88
|
omlish/collections/ordered.py,sha256=XV_ufr3QycjQ3nIy9L3BufdBosWD-3wb5xVZEHpZocQ,2467
|
@@ -481,7 +481,7 @@ omlish/lite/args.py,sha256=ILJXAiN3KjIoJwY42aKpYPngUdxHIy9ssVIExFVz3fE,978
|
|
481
481
|
omlish/lite/cached.py,sha256=O7ozcoDNFm1Hg2wtpHEqYSp_i_nCLNOP6Ueq_Uk-7mU,1300
|
482
482
|
omlish/lite/check.py,sha256=ytCkwZoKfOlJqylL-AGm8C2WfsWJd2q3kFbnZCzX3_M,13844
|
483
483
|
omlish/lite/configs.py,sha256=4-1uVxo-aNV7vMKa7PVNhM610eejG1WepB42-Dw2xQI,914
|
484
|
-
omlish/lite/contextmanagers.py,sha256=
|
484
|
+
omlish/lite/contextmanagers.py,sha256=QEqVxUtmr9aJJ_03A-YC4vVUy8jkiIDCYIGIOlXvn8U,5827
|
485
485
|
omlish/lite/dataclasses.py,sha256=aRSCZz1jN_UI-CWJhN0SJeKxa-79vXNUZ6YOMgG31SE,3610
|
486
486
|
omlish/lite/imports.py,sha256=GyEDKL-WuHtdOKIL-cc8aFd0-bHwZFDEjAB52ItabX0,1341
|
487
487
|
omlish/lite/inject.py,sha256=xvmLmtD3_2INnkurJQv76_Rkh9usbApEQrXJ4cvuVAk,29019
|
@@ -518,8 +518,8 @@ omlish/logs/timing.py,sha256=qsQ3DB6swts1pxrFlmLWQzhH-3nzDrq1MUu7PxjjUyU,1519
|
|
518
518
|
omlish/logs/utils.py,sha256=OkFWf1exmWImmT7BaSiIC7c0Fk9tAis-PRqo8H4ny3c,398
|
519
519
|
omlish/manifests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
520
520
|
omlish/manifests/base.py,sha256=Z5afzBJgI0tyTS8mPbYY4pYvoZu_xtdhRBOtZ3IIwzA,929
|
521
|
-
omlish/manifests/globals.py,sha256=
|
522
|
-
omlish/manifests/loading.py,sha256=
|
521
|
+
omlish/manifests/globals.py,sha256=kVqQ-fT4kc7xWzLHoI731GviitFPv2v2yqw-p7t7Exs,2628
|
522
|
+
omlish/manifests/loading.py,sha256=tnAxvyJRAncyKihaBH8oqcJmHKaunPXm1Y1OpAi3iQc,15870
|
523
523
|
omlish/manifests/static.py,sha256=7YwOVh_Ek9_aTrWsWNO8kWS10_j4K7yv3TpXZSHsvDY,501
|
524
524
|
omlish/manifests/types.py,sha256=5hQuY-WZ9VMqHZXr-9Dayg380JsnX2vJzXyw6vC6UDs,317
|
525
525
|
omlish/marshal/.dataclasses.json,sha256=wXWUy_IR8AolAa2RQnqn_mo2QnmVcvUJmayIykdVl0I,22
|
@@ -908,9 +908,9 @@ omlish/typedvalues/marshal.py,sha256=AtBz7Jq-BfW8vwM7HSxSpR85JAXmxK2T0xDblmm1HI0
|
|
908
908
|
omlish/typedvalues/of_.py,sha256=UXkxSj504WI2UrFlqdZJbu2hyDwBhL7XVrc2qdR02GQ,1309
|
909
909
|
omlish/typedvalues/reflect.py,sha256=PAvKW6T4cW7u--iX80w3HWwZUS3SmIZ2_lQjT65uAyk,1026
|
910
910
|
omlish/typedvalues/values.py,sha256=ym46I-q2QJ_6l4UlERqv3yj87R-kp8nCKMRph0xQ3UA,1307
|
911
|
-
omlish-0.0.0.
|
912
|
-
omlish-0.0.0.
|
913
|
-
omlish-0.0.0.
|
914
|
-
omlish-0.0.0.
|
915
|
-
omlish-0.0.0.
|
916
|
-
omlish-0.0.0.
|
911
|
+
omlish-0.0.0.dev405.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
|
912
|
+
omlish-0.0.0.dev405.dist-info/METADATA,sha256=y4Y668MaUQry-Qf4i3hWdu6-nugPJgTmu-hknnshYZI,18881
|
913
|
+
omlish-0.0.0.dev405.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
914
|
+
omlish-0.0.0.dev405.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
|
915
|
+
omlish-0.0.0.dev405.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
|
916
|
+
omlish-0.0.0.dev405.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|