omlish 0.0.0.dev398__py3-none-any.whl → 0.0.0.dev400__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.
Files changed (37) hide show
  1. omlish/__about__.py +2 -2
  2. omlish/bootstrap/__init__.py +2 -2
  3. omlish/collections/__init__.py +135 -149
  4. omlish/configs/formats.py +6 -2
  5. omlish/diag/lsof.py +4 -3
  6. omlish/funcs/builders.py +2 -1
  7. omlish/lang/__init__.py +26 -5
  8. omlish/lang/imports/__init__.py +0 -0
  9. omlish/lang/imports/conditional.py +33 -0
  10. omlish/lang/imports/lazy.py +66 -0
  11. omlish/lang/imports/proxyinit.py +445 -0
  12. omlish/lang/imports/resolution.py +86 -0
  13. omlish/lang/imports/traversal.py +104 -0
  14. omlish/lang/lazyglobals.py +59 -0
  15. omlish/lang/resources.py +1 -1
  16. omlish/lite/imports.py +1 -1
  17. omlish/lite/reprs.py +2 -1
  18. omlish/manifests/base.py +2 -1
  19. omlish/manifests/loading.py +1 -1
  20. omlish/marshal/__init__.py +2 -2
  21. omlish/os/pidfiles/pinning.py +2 -1
  22. omlish/secrets/all.py +2 -2
  23. omlish/secrets/secrets.py +1 -1
  24. omlish/specs/jsonrpc/__init__.py +2 -2
  25. omlish/specs/jsonschema/__init__.py +2 -2
  26. omlish/specs/openapi/__init__.py +2 -2
  27. omlish/sql/api/__init__.py +2 -2
  28. omlish/sql/queries/__init__.py +3 -9
  29. omlish/sql/tabledefs/__init__.py +2 -2
  30. omlish/typedvalues/__init__.py +2 -2
  31. {omlish-0.0.0.dev398.dist-info → omlish-0.0.0.dev400.dist-info}/METADATA +1 -1
  32. {omlish-0.0.0.dev398.dist-info → omlish-0.0.0.dev400.dist-info}/RECORD +36 -30
  33. omlish/lang/imports.py +0 -418
  34. {omlish-0.0.0.dev398.dist-info → omlish-0.0.0.dev400.dist-info}/WHEEL +0 -0
  35. {omlish-0.0.0.dev398.dist-info → omlish-0.0.0.dev400.dist-info}/entry_points.txt +0 -0
  36. {omlish-0.0.0.dev398.dist-info → omlish-0.0.0.dev400.dist-info}/licenses/LICENSE +0 -0
  37. {omlish-0.0.0.dev398.dist-info → omlish-0.0.0.dev400.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,445 @@
1
+ """
2
+ TODO:
3
+ - auto_proxy_init can capture `import as` by scanning globals for sentinels
4
+ - replaces _AutoProxyInitCapture._attrs dict outright
5
+ - should raise on unbound or shadowed import - was probably imported for side-effects but will never get
6
+ proxy imported
7
+ """
8
+ import builtins
9
+ import contextlib
10
+ import functools
11
+ import importlib.util
12
+ import types
13
+ import typing as ta
14
+
15
+ from ..lazyglobals import LazyGlobals
16
+
17
+
18
+ ##
19
+
20
+
21
+ class NamePackage(ta.NamedTuple):
22
+ name: str
23
+ package: str
24
+
25
+
26
+ class _ProxyInit:
27
+ class _Import(ta.NamedTuple):
28
+ pkg: str
29
+ attr: str | None
30
+
31
+ def __init__(
32
+ self,
33
+ lazy_globals: LazyGlobals,
34
+ name_package: NamePackage,
35
+ ) -> None:
36
+ super().__init__()
37
+
38
+ self._lazy_globals = lazy_globals
39
+ self._name_package = name_package
40
+
41
+ self._imps_by_attr: dict[str, _ProxyInit._Import] = {}
42
+ self._mods_by_pkgs: dict[str, ta.Any] = {}
43
+
44
+ @property
45
+ def name_package(self) -> NamePackage:
46
+ return self._name_package
47
+
48
+ def add(
49
+ self,
50
+ package: str,
51
+ attrs: ta.Iterable[str | tuple[str, str]] | None = None,
52
+ ) -> None:
53
+ if isinstance(attrs, str):
54
+ raise TypeError(attrs)
55
+
56
+ if attrs is None:
57
+ whole_attr = package.split('.')[-1]
58
+
59
+ self._imps_by_attr[whole_attr] = self._Import(package, None)
60
+ self._lazy_globals.set_fn(whole_attr, functools.partial(self.get, whole_attr))
61
+
62
+ else:
63
+ for attr in attrs:
64
+ if isinstance(attr, tuple):
65
+ imp_attr, attr = attr
66
+ else:
67
+ imp_attr = attr
68
+
69
+ self._imps_by_attr[attr] = self._Import(package, imp_attr)
70
+ self._lazy_globals.set_fn(attr, functools.partial(self.get, attr))
71
+
72
+ def _import_module(self, name: str) -> ta.Any:
73
+ return importlib.import_module(name, package=self._name_package.package)
74
+
75
+ def get(self, attr: str) -> ta.Any:
76
+ try:
77
+ imp = self._imps_by_attr[attr]
78
+ except KeyError:
79
+ raise AttributeError(attr) # noqa
80
+
81
+ val: ta.Any
82
+
83
+ if imp.attr is None:
84
+ val = self._import_module(imp.pkg)
85
+
86
+ else:
87
+ try:
88
+ mod = self._mods_by_pkgs[imp.pkg]
89
+ except KeyError:
90
+ mod = self._import_module(imp.pkg)
91
+ self._mods_by_pkgs[imp.pkg] = mod
92
+
93
+ val = getattr(mod, imp.attr)
94
+
95
+ return val
96
+
97
+
98
+ def proxy_init(
99
+ init_globals: ta.MutableMapping[str, ta.Any],
100
+ package: str,
101
+ attrs: ta.Iterable[str | tuple[str, str]] | None = None,
102
+ ) -> None:
103
+ if isinstance(attrs, str):
104
+ raise TypeError(attrs)
105
+
106
+ init_name_package = NamePackage(
107
+ init_globals['__name__'],
108
+ init_globals['__package__'],
109
+ )
110
+
111
+ pi: _ProxyInit
112
+ try:
113
+ pi = init_globals['__proxy_init__']
114
+
115
+ except KeyError:
116
+ pi = _ProxyInit(
117
+ LazyGlobals.install(init_globals),
118
+ init_name_package,
119
+ )
120
+ init_globals['__proxy_init__'] = pi
121
+
122
+ else:
123
+ if pi.name_package != init_name_package:
124
+ raise Exception(f'Wrong init name: {pi.name_package=} != {init_name_package=}')
125
+
126
+ pi.add(package, attrs)
127
+
128
+
129
+ ##
130
+
131
+
132
+ class AutoProxyInitError(Exception):
133
+ pass
134
+
135
+
136
+ class AutoProxyInitErrors:
137
+ def __new__(cls, *args, **kwargs): # noqa
138
+ raise TypeError
139
+
140
+ class HookError(AutoProxyInitError):
141
+ pass
142
+
143
+ class AttrError(AutoProxyInitError):
144
+ def __init__(self, module: str | None, name: str) -> None:
145
+ super().__init__()
146
+
147
+ self.module = module
148
+ self.name = name
149
+
150
+ def __repr__(self) -> str:
151
+ return f'{self.__class__.__qualname__}(module={self.module!r}, name={self.name!r})'
152
+
153
+ class ImportError(AutoProxyInitError): # noqa
154
+ def __init__(self, module: str, from_list: ta.Sequence[str] | None) -> None:
155
+ super().__init__()
156
+
157
+ self.module = module
158
+ self.from_list = from_list
159
+
160
+ def __repr__(self) -> str:
161
+ return f'{self.__class__.__qualname__}(module={self.module!r}, from_list={self.from_list!r})'
162
+
163
+ class ImportStarForbiddenError(ImportError):
164
+ pass
165
+
166
+ class UnproxiedImportForbiddenError(ImportError):
167
+ pass
168
+
169
+
170
+ class _AutoProxyInitCapture:
171
+ class ModuleSpec(ta.NamedTuple):
172
+ name: str
173
+ level: int
174
+
175
+ def __str__(self) -> str:
176
+ return f'{"." * self.level}{self.name}'
177
+
178
+ def __repr__(self) -> str:
179
+ return repr(str(self))
180
+
181
+ class _ModuleAttr:
182
+ def __init__(self, module: '_AutoProxyInitCapture._Module', name: str) -> None:
183
+ super().__init__()
184
+
185
+ self.__module = module
186
+ self.__name = name
187
+
188
+ def __repr__(self) -> str:
189
+ return f'<{self.__class__.__name__}: {f"{self.__module.spec}:{self.__name}"!r}>'
190
+
191
+ class _Module:
192
+ def __init__(self, spec: '_AutoProxyInitCapture.ModuleSpec') -> None:
193
+ super().__init__()
194
+
195
+ self.spec = spec
196
+
197
+ self.module = types.ModuleType(f'<{self.__class__.__qualname__}: {spec!r}>')
198
+
199
+ self.attrs: dict[str, _AutoProxyInitCapture._ModuleAttr] = {}
200
+ self.imported_whole = False
201
+
202
+ def __repr__(self) -> str:
203
+ return f'{self.__class__.__name__}({self.spec!r})'
204
+
205
+ def __init__(self) -> None:
206
+ super().__init__()
207
+
208
+ self._modules: dict[_AutoProxyInitCapture.ModuleSpec, _AutoProxyInitCapture._Module] = {}
209
+ self._attrs: dict[str, _AutoProxyInitCapture._ModuleAttr | _AutoProxyInitCapture._Module] = {}
210
+
211
+ def _handle_import(
212
+ self,
213
+ module: _Module,
214
+ *,
215
+ from_list: ta.Sequence[str] | None,
216
+ ) -> None:
217
+ if from_list is None:
218
+ if module.spec.level or not module.spec.name:
219
+ raise AutoProxyInitError
220
+
221
+ attr = module.spec.name
222
+
223
+ try:
224
+ xma: ta.Any = self._attrs[attr]
225
+ except KeyError:
226
+ pass
227
+
228
+ else:
229
+ if (
230
+ xma is not self._attrs.get(attr) or
231
+ not module.imported_whole
232
+ ):
233
+ raise AutoProxyInitErrors.AttrError(str(module.spec), attr)
234
+
235
+ return
236
+
237
+ self._attrs[attr] = module
238
+ module.imported_whole = True
239
+
240
+ else:
241
+ for attr in from_list:
242
+ if attr == '*':
243
+ raise AutoProxyInitErrors.ImportStarForbiddenError(str(module.spec), from_list)
244
+
245
+ try:
246
+ xma = getattr(module.module, attr)
247
+ except AttributeError:
248
+ pass
249
+
250
+ else:
251
+ if (
252
+ xma is not module.attrs.get(attr) or
253
+ xma is not self._attrs.get(attr)
254
+ ):
255
+ raise AutoProxyInitErrors.AttrError(str(module.spec), attr)
256
+
257
+ continue
258
+
259
+ if attr in self._attrs:
260
+ raise AutoProxyInitErrors.AttrError(str(module.spec), attr)
261
+
262
+ ma = _AutoProxyInitCapture._ModuleAttr(module, attr)
263
+ self._attrs[attr] = ma
264
+ module.attrs[attr] = ma
265
+ setattr(module.module, attr, ma)
266
+
267
+ _MOD_SELF_ATTR: ta.ClassVar[str] = '__auto_proxy_init_capture__'
268
+
269
+ def _intercept_import(
270
+ self,
271
+ name: str,
272
+ *,
273
+ globals: ta.Mapping[str, ta.Any] | None = None, # noqa
274
+ from_list: ta.Sequence[str] | None = None,
275
+ level: int = 0,
276
+ ) -> types.ModuleType | None:
277
+ if not (
278
+ globals is not None and
279
+ globals.get(self._MOD_SELF_ATTR) is self
280
+ ):
281
+ return None
282
+
283
+ spec = _AutoProxyInitCapture.ModuleSpec(name, level)
284
+ try:
285
+ module = self._modules[spec]
286
+ except KeyError:
287
+ module = self._Module(spec)
288
+ self._modules[spec] = module
289
+
290
+ self._handle_import(
291
+ module,
292
+ from_list=from_list,
293
+ )
294
+
295
+ return module.module
296
+
297
+ @contextlib.contextmanager
298
+ def hook_context(
299
+ self,
300
+ init_globals: ta.MutableMapping[str, ta.Any], # noqa
301
+ *,
302
+ forbid_unproxied_imports: bool = False,
303
+ ) -> ta.Iterator[None]:
304
+ if self._MOD_SELF_ATTR in init_globals:
305
+ raise AutoProxyInitErrors.HookError
306
+
307
+ old_import = builtins.__import__
308
+
309
+ def new_import(
310
+ name,
311
+ globals=None, # noqa
312
+ locals=None, # noqa
313
+ fromlist=None,
314
+ level=0,
315
+ ):
316
+ if (im := self._intercept_import(
317
+ name,
318
+ globals=globals,
319
+ from_list=fromlist,
320
+ level=level,
321
+ )) is not None:
322
+ return im
323
+
324
+ if forbid_unproxied_imports:
325
+ raise AutoProxyInitErrors.UnproxiedImportForbiddenError(
326
+ str(_AutoProxyInitCapture.ModuleSpec(name, level)),
327
+ fromlist,
328
+ )
329
+
330
+ return old_import(
331
+ name,
332
+ globals=globals,
333
+ locals=locals,
334
+ fromlist=fromlist,
335
+ level=level,
336
+ )
337
+
338
+ #
339
+
340
+ init_globals[self._MOD_SELF_ATTR] = self
341
+ builtins.__import__ = new_import
342
+
343
+ try:
344
+ yield
345
+
346
+ finally:
347
+ if not (
348
+ init_globals[self._MOD_SELF_ATTR] is self and
349
+ builtins.__import__ is new_import
350
+ ):
351
+ raise AutoProxyInitErrors.HookError
352
+
353
+ del init_globals[self._MOD_SELF_ATTR]
354
+ builtins.__import__ = old_import
355
+
356
+ def verify_globals(
357
+ self,
358
+ init_globals: ta.MutableMapping[str, ta.Any], # noqa
359
+ ) -> None:
360
+ for attr, obj in self._attrs.items():
361
+ try:
362
+ xo = init_globals[attr]
363
+ except KeyError:
364
+ raise AutoProxyInitErrors.AttrError(None, attr) from None
365
+
366
+ if isinstance(obj, _AutoProxyInitCapture._ModuleAttr):
367
+ if xo is not obj:
368
+ raise AutoProxyInitErrors.AttrError(None, attr) from None
369
+
370
+ elif isinstance(obj, _AutoProxyInitCapture._Module):
371
+ if xo is not obj.module:
372
+ raise AutoProxyInitErrors.AttrError(None, attr) from None
373
+
374
+ else:
375
+ raise TypeError(obj)
376
+
377
+ @property
378
+ def all_attrs(self) -> ta.AbstractSet[str]:
379
+ return self._attrs.keys()
380
+
381
+ class ProxyInit(ta.NamedTuple):
382
+ package: str
383
+ attrs: ta.Sequence[str] | None
384
+
385
+ def build_proxy_inits(self) -> list[ProxyInit]:
386
+ lst: list[_AutoProxyInitCapture.ProxyInit] = []
387
+
388
+ for module in self._modules.values():
389
+ if module.imported_whole:
390
+ lst.append(_AutoProxyInitCapture.ProxyInit(str(module.spec), None))
391
+
392
+ if module.attrs:
393
+ if not module.spec.name:
394
+ for attr in module.attrs:
395
+ if not module.spec.level:
396
+ raise AutoProxyInitError
397
+
398
+ lst.append(_AutoProxyInitCapture.ProxyInit('.' * module.spec.level + attr, None))
399
+
400
+ else:
401
+ lst.append(_AutoProxyInitCapture.ProxyInit(str(module.spec), list(module.attrs)))
402
+
403
+ return lst
404
+
405
+
406
+ @contextlib.contextmanager
407
+ def auto_proxy_init(
408
+ init_globals: ta.MutableMapping[str, ta.Any],
409
+ *,
410
+ disable: bool = False,
411
+ eager: bool = False,
412
+ ) -> ta.Iterator[None]:
413
+ """
414
+ This is a bit extreme - use sparingly. It relies on an interpreter-global import lock, but much of the ecosystem
415
+ implicitly does anyway. It further relies on temporarily patching `__builtins__.__import__`, but could be switched
416
+ to use any number of other import hooks.
417
+ """
418
+
419
+ if disable:
420
+ yield
421
+ return
422
+
423
+ cap = _AutoProxyInitCapture()
424
+
425
+ with cap.hook_context(init_globals):
426
+ yield
427
+
428
+ cap.verify_globals(init_globals)
429
+
430
+ pis = cap.build_proxy_inits()
431
+
432
+ for attr in cap.all_attrs:
433
+ del init_globals[attr]
434
+
435
+ for pi in pis:
436
+ proxy_init(
437
+ init_globals,
438
+ pi.package,
439
+ pi.attrs,
440
+ )
441
+
442
+ if eager:
443
+ lg = LazyGlobals.install(init_globals)
444
+ for attr in cap.all_attrs:
445
+ lg.get(attr)
@@ -0,0 +1,86 @@
1
+ """
2
+ TODO:
3
+ - use importlib.util.resolve_name
4
+ """
5
+ import importlib.util
6
+ import sys
7
+ import types
8
+ import typing as ta
9
+
10
+
11
+ ##
12
+
13
+
14
+ def can_import(name: str, package: str | None = None) -> bool:
15
+ try:
16
+ spec = importlib.util.find_spec(name, package)
17
+ except ImportError:
18
+ return False
19
+ else:
20
+ return spec is not None
21
+
22
+
23
+ ##
24
+
25
+
26
+ def try_import(spec: str) -> types.ModuleType | None:
27
+ s = spec.lstrip('.')
28
+ l = len(spec) - len(s)
29
+ try:
30
+ return __import__(s, globals(), level=l)
31
+ except ImportError:
32
+ return None
33
+
34
+
35
+ ##
36
+
37
+
38
+ def resolve_import_name(name: str, package: str | None = None) -> str:
39
+ # FIXME: importlib.util.resolve_name
40
+ level = 0
41
+
42
+ if name.startswith('.'):
43
+ if not package:
44
+ raise TypeError("the 'package' argument is required to perform a relative import for {name!r}")
45
+ for character in name:
46
+ if character != '.':
47
+ break
48
+ level += 1
49
+
50
+ name = name[level:]
51
+
52
+ if not isinstance(name, str):
53
+ raise TypeError(f'module name must be str, not {type(name)}')
54
+ if level < 0:
55
+ raise ValueError('level must be >= 0')
56
+ if level > 0:
57
+ if not isinstance(package, str):
58
+ raise TypeError('__package__ not set to a string')
59
+ elif not package:
60
+ raise ImportError('attempted relative import with no known parent package')
61
+ if not name and level == 0:
62
+ raise ValueError('Empty module name')
63
+
64
+ if level > 0:
65
+ bits = package.rsplit('.', level - 1) # type: ignore
66
+ if len(bits) < level:
67
+ raise ImportError('attempted relative import beyond top-level package')
68
+ base = bits[0]
69
+ name = f'{base}.{name}' if name else base
70
+
71
+ return name
72
+
73
+
74
+ ##
75
+
76
+
77
+ def get_real_module_name(globals: ta.Mapping[str, ta.Any]) -> str: # noqa
78
+ module = sys.modules[globals['__name__']]
79
+
80
+ if module.__spec__ and module.__spec__.name:
81
+ return module.__spec__.name
82
+
83
+ if module.__package__:
84
+ return module.__package__
85
+
86
+ raise RuntimeError("Can't determine real module name")
@@ -0,0 +1,104 @@
1
+ """
2
+ TODO:
3
+ - overhaul this - use pkgutil.walk_packages unless called needs non-importing (which this currently doesn't do anyway),
4
+ and support namespace packages if they do.
5
+ """
6
+ import contextlib
7
+ import sys
8
+ import typing as ta
9
+
10
+
11
+ ##
12
+
13
+
14
+ SPECIAL_IMPORTABLE: ta.AbstractSet[str] = frozenset([
15
+ '__init__.py',
16
+ '__main__.py',
17
+ ])
18
+
19
+
20
+ def yield_importable(
21
+ package_root: str,
22
+ *,
23
+ recursive: bool = False,
24
+ filter: ta.Callable[[str], bool] | None = None, # noqa
25
+ include_special: bool = False,
26
+ raise_on_failure: bool = False,
27
+ ) -> ta.Iterator[str]:
28
+ import importlib.resources
29
+
30
+ def rec(cur):
31
+ if cur.split('.')[-1] == '__pycache__':
32
+ return
33
+
34
+ try:
35
+ module = sys.modules[cur]
36
+ except KeyError:
37
+ module = importlib.import_module(cur)
38
+
39
+ # FIXME: pyox
40
+ if getattr(module, '__file__', None) is None:
41
+ return
42
+
43
+ for file in importlib.resources.files(cur).iterdir():
44
+ if file.is_file() and file.name.endswith('.py'):
45
+ if not (include_special or file.name not in SPECIAL_IMPORTABLE):
46
+ continue
47
+
48
+ name = cur + '.' + file.name[:-3]
49
+ if filter is not None and not filter(name):
50
+ continue
51
+
52
+ yield name
53
+
54
+ elif recursive and file.is_dir():
55
+ name = cur + '.' + file.name
56
+
57
+ if filter is not None and not filter(name):
58
+ continue
59
+
60
+ if raise_on_failure:
61
+ yield from rec(name)
62
+
63
+ else:
64
+ with contextlib.suppress(ImportError, NotImplementedError):
65
+ yield from rec(name)
66
+
67
+ yield from rec(package_root)
68
+
69
+
70
+ def yield_import_all(
71
+ package_root: str,
72
+ *,
73
+ globals: dict[str, ta.Any] | None = None, # noqa
74
+ locals: dict[str, ta.Any] | None = None, # noqa
75
+ recursive: bool = False,
76
+ filter: ta.Callable[[str], bool] | None = None, # noqa
77
+ include_special: bool = False,
78
+ raise_on_failure: bool = False,
79
+ ) -> ta.Iterator[str]:
80
+ for import_path in yield_importable(
81
+ package_root,
82
+ recursive=recursive,
83
+ filter=filter,
84
+ include_special=include_special,
85
+ raise_on_failure=raise_on_failure,
86
+ ):
87
+ __import__(import_path, globals=globals, locals=locals)
88
+ yield import_path
89
+
90
+
91
+ def import_all(
92
+ package_root: str,
93
+ *,
94
+ recursive: bool = False,
95
+ filter: ta.Callable[[str], bool] | None = None, # noqa
96
+ include_special: bool = False,
97
+ ) -> None:
98
+ for _ in yield_import_all(
99
+ package_root,
100
+ recursive=recursive,
101
+ filter=filter,
102
+ include_special=include_special,
103
+ ):
104
+ pass
@@ -0,0 +1,59 @@
1
+ import typing as ta
2
+
3
+
4
+ ##
5
+
6
+
7
+ class LazyGlobals:
8
+ def __init__(
9
+ self,
10
+ *,
11
+ globals: ta.MutableMapping[str, ta.Any] | None = None, # noqa
12
+ update_globals: bool = False,
13
+ ) -> None:
14
+ super().__init__()
15
+
16
+ self._globals = globals
17
+ self._update_globals = update_globals
18
+
19
+ self._attr_fns: dict[str, ta.Callable[[], ta.Any]] = {}
20
+
21
+ @classmethod
22
+ def install(cls, globals: ta.MutableMapping[str, ta.Any]) -> 'LazyGlobals': # noqa
23
+ try:
24
+ xga = globals['__getattr__']
25
+ except KeyError:
26
+ pass
27
+ else:
28
+ if not isinstance(xga, cls):
29
+ raise RuntimeError(f'Module already has __getattr__ hook: {xga}') # noqa
30
+ return xga
31
+
32
+ lm = cls(
33
+ globals=globals,
34
+ update_globals=True,
35
+ )
36
+
37
+ globals['__getattr__'] = lm
38
+
39
+ return lm
40
+
41
+ def set_fn(self, attr: str, fn: ta.Callable[[], ta.Any]) -> 'LazyGlobals':
42
+ self._attr_fns[attr] = fn
43
+ return self
44
+
45
+ def get(self, attr: str) -> ta.Any:
46
+ try:
47
+ fn = self._attr_fns[attr]
48
+ except KeyError:
49
+ raise AttributeError(attr) from None
50
+
51
+ val = fn()
52
+
53
+ if self._update_globals and self._globals is not None:
54
+ self._globals[attr] = val
55
+
56
+ return val
57
+
58
+ def __call__(self, attr: str) -> ta.Any:
59
+ return self.get(attr)
omlish/lang/resources.py CHANGED
@@ -3,7 +3,7 @@ import functools
3
3
  import os.path
4
4
  import typing as ta
5
5
 
6
- from .imports import proxy_import
6
+ from .imports.lazy import proxy_import
7
7
 
8
8
 
9
9
  if ta.TYPE_CHECKING:
omlish/lite/imports.py CHANGED
@@ -28,7 +28,7 @@ def import_module_attr(dotted_path: str) -> ta.Any:
28
28
 
29
29
 
30
30
  def import_attr(dotted_path: str) -> ta.Any:
31
- importlib = __import__('importlib')
31
+ import importlib # noqa
32
32
  parts = dotted_path.split('.')
33
33
  mod: ta.Any = None
34
34
  mod_pos = 0