omlish 0.0.0.dev432__py3-none-any.whl → 0.0.0.dev433__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.
@@ -1,11 +1,10 @@
1
- import builtins
2
1
  import contextlib
3
2
  import functools
4
3
  import importlib.util
5
- import types
6
4
  import typing as ta
7
5
 
8
6
  from ..lazyglobals import LazyGlobals
7
+ from .capture import ImportCapture
9
8
 
10
9
 
11
10
  ##
@@ -17,7 +16,7 @@ class _ProxyInit:
17
16
  package: str
18
17
 
19
18
  class _Import(ta.NamedTuple):
20
- pkg: str
19
+ spec: str
21
20
  attr: str | None
22
21
 
23
22
  def __init__(
@@ -31,7 +30,7 @@ class _ProxyInit:
31
30
  self._name_package = name_package
32
31
 
33
32
  self._imps_by_attr: dict[str, _ProxyInit._Import] = {}
34
- self._mods_by_pkgs: dict[str, ta.Any] = {}
33
+ self._mods_by_spec: dict[str, ta.Any] = {}
35
34
 
36
35
  @property
37
36
  def name_package(self) -> NamePackage:
@@ -63,14 +62,14 @@ class _ProxyInit:
63
62
  val: ta.Any
64
63
 
65
64
  if imp.attr is None:
66
- val = self._import_module(imp.pkg)
65
+ val = self._import_module(imp.spec)
67
66
 
68
67
  else:
69
68
  try:
70
- mod = self._mods_by_pkgs[imp.pkg]
69
+ mod = self._mods_by_spec[imp.spec]
71
70
  except KeyError:
72
- mod = self._import_module(imp.pkg)
73
- self._mods_by_pkgs[imp.pkg] = mod
71
+ mod = self._import_module(imp.spec)
72
+ self._mods_by_spec[imp.spec] = mod
74
73
 
75
74
  val = getattr(mod, imp.attr)
76
75
 
@@ -79,7 +78,7 @@ class _ProxyInit:
79
78
 
80
79
  def proxy_init(
81
80
  init_globals: ta.MutableMapping[str, ta.Any],
82
- package: str,
81
+ spec: str,
83
82
  attrs: ta.Iterable[str | tuple[str | None, str | None] | None] | None = None,
84
83
  ) -> None:
85
84
  if isinstance(attrs, str):
@@ -88,7 +87,7 @@ def proxy_init(
88
87
  if attrs is None:
89
88
  attrs = [None]
90
89
 
91
- whole_attr = package.split('.')[-1]
90
+ whole_attr = spec.split('.')[-1]
92
91
  al: list[tuple[str | None, str]] = []
93
92
  for attr in attrs:
94
93
  if attr is None:
@@ -131,506 +130,12 @@ def proxy_init(
131
130
  if pi.name_package != init_name_package:
132
131
  raise Exception(f'Wrong init name: {pi.name_package=} != {init_name_package=}')
133
132
 
134
- pi.add(package, al)
133
+ pi.add(spec, al)
135
134
 
136
135
 
137
136
  ##
138
137
 
139
138
 
140
- class AutoProxyInitError(Exception):
141
- pass
142
-
143
-
144
- class AutoProxyInitErrors:
145
- def __new__(cls, *args, **kwargs): # noqa
146
- raise TypeError
147
-
148
- class HookError(AutoProxyInitError):
149
- pass
150
-
151
- class AttrError(AutoProxyInitError):
152
- def __init__(self, module: str | None, name: str) -> None:
153
- super().__init__()
154
-
155
- self.module = module
156
- self.name = name
157
-
158
- def __repr__(self) -> str:
159
- return f'{self.__class__.__qualname__}(module={self.module!r}, name={self.name!r})'
160
-
161
- class ImportError(AutoProxyInitError): # noqa
162
- def __init__(self, module: str, from_list: ta.Sequence[str] | None) -> None:
163
- super().__init__()
164
-
165
- self.module = module
166
- self.from_list = from_list
167
-
168
- def __repr__(self) -> str:
169
- return f'{self.__class__.__qualname__}(module={self.module!r}, from_list={self.from_list!r})'
170
-
171
- class ImportStarForbiddenError(ImportError):
172
- pass
173
-
174
- class UnproxiedImportForbiddenError(ImportError):
175
- pass
176
-
177
- class UnreferencedImportsError(AutoProxyInitError):
178
- def __init__(self, unreferenced: ta.Mapping[str, ta.Sequence[str | None]]) -> None:
179
- super().__init__()
180
-
181
- self.unreferenced = unreferenced
182
-
183
- def __repr__(self) -> str:
184
- return f'{self.__class__.__qualname__}(unreferenced={self.unreferenced!r})'
185
-
186
- class CaptureInProgressError(AutoProxyInitError):
187
- pass
188
-
189
-
190
- class _AutoProxyInitCapture:
191
- class ModuleSpec(ta.NamedTuple):
192
- name: str
193
- level: int
194
-
195
- def __str__(self) -> str:
196
- return f'{"." * self.level}{self.name}'
197
-
198
- def __repr__(self) -> str:
199
- return repr(str(self))
200
-
201
- def __init__(self) -> None:
202
- super().__init__()
203
-
204
- self._modules_by_spec: dict[_AutoProxyInitCapture.ModuleSpec, _AutoProxyInitCapture._Module] = {}
205
- self._modules_by_module_obj: dict[types.ModuleType, _AutoProxyInitCapture._Module] = {}
206
-
207
- self._attrs: dict[_AutoProxyInitCapture._ModuleAttr, tuple[_AutoProxyInitCapture._Module, str]] = {}
208
-
209
- #
210
-
211
- class _ModuleAttr:
212
- def __init__(
213
- self,
214
- module: '_AutoProxyInitCapture._Module',
215
- name: str,
216
- ) -> None:
217
- super().__init__()
218
-
219
- self.__module = module
220
- self.__name = name
221
-
222
- def __repr__(self) -> str:
223
- return f'<{self.__class__.__name__}: {f"{self.__module.spec}:{self.__name}"!r}>'
224
-
225
- class _Module:
226
- def __init__(
227
- self,
228
- spec: '_AutoProxyInitCapture.ModuleSpec',
229
- *,
230
- getattr_handler: ta.Callable[['_AutoProxyInitCapture._Module', str], ta.Any] | None = None,
231
- ) -> None:
232
- super().__init__()
233
-
234
- self.spec = spec
235
-
236
- self.module_obj = types.ModuleType(f'<{self.__class__.__qualname__}: {spec!r}>')
237
- if getattr_handler is not None:
238
- self.module_obj.__getattr__ = functools.partial(getattr_handler, self) # type: ignore[method-assign] # noqa
239
- self.initial_module_dict = dict(self.module_obj.__dict__)
240
-
241
- self.contents: dict[str, _AutoProxyInitCapture._ModuleAttr | types.ModuleType] = {}
242
- self.imported_whole = False
243
-
244
- def __repr__(self) -> str:
245
- return f'{self.__class__.__name__}({self.spec!r})'
246
-
247
- def _get_or_make_module(self, spec: ModuleSpec) -> _Module:
248
- try:
249
- return self._modules_by_spec[spec]
250
- except KeyError:
251
- pass
252
-
253
- module = self._Module(
254
- spec,
255
- getattr_handler=self._handle_module_getattr,
256
- )
257
- self._modules_by_spec[spec] = module
258
- self._modules_by_module_obj[module.module_obj] = module
259
- return module
260
-
261
- def _handle_module_getattr(self, module: _Module, attr: str) -> ta.Any:
262
- if attr in module.contents:
263
- raise AutoProxyInitErrors.AttrError(str(module.spec), attr)
264
-
265
- v: _AutoProxyInitCapture._ModuleAttr | types.ModuleType
266
- if not module.spec.name:
267
- if not module.spec.level:
268
- raise AutoProxyInitError
269
- cs = _AutoProxyInitCapture.ModuleSpec(attr, module.spec.level)
270
- cm = self._get_or_make_module(cs)
271
- cm.imported_whole = True
272
- v = cm.module_obj
273
-
274
- else:
275
- ma = _AutoProxyInitCapture._ModuleAttr(module, attr)
276
- self._attrs[ma] = (module, attr)
277
- v = ma
278
-
279
- module.contents[attr] = v
280
- setattr(module.module_obj, attr, v)
281
- return v
282
-
283
- def _handle_import(
284
- self,
285
- module: _Module,
286
- *,
287
- from_list: ta.Sequence[str] | None,
288
- ) -> None:
289
- if from_list is None:
290
- if module.spec.level or not module.spec.name:
291
- raise AutoProxyInitError
292
-
293
- module.imported_whole = True
294
-
295
- else:
296
- for attr in from_list:
297
- if attr == '*':
298
- raise AutoProxyInitErrors.ImportStarForbiddenError(str(module.spec), from_list)
299
-
300
- x = getattr(module.module_obj, attr)
301
-
302
- bad = False
303
- if x is not module.contents.get(attr):
304
- bad = True
305
- if isinstance(x, _AutoProxyInitCapture._ModuleAttr):
306
- if self._attrs[x] != (module, attr):
307
- bad = True
308
- elif isinstance(x, types.ModuleType):
309
- if x not in self._modules_by_module_obj:
310
- bad = True
311
- else:
312
- bad = True
313
- if bad:
314
- raise AutoProxyInitErrors.AttrError(str(module.spec), attr)
315
-
316
- #
317
-
318
- _MOD_SELF_ATTR: ta.ClassVar[str] = '__auto_proxy_init_capture__'
319
-
320
- def _intercept_import(
321
- self,
322
- name: str,
323
- *,
324
- globals: ta.Mapping[str, ta.Any] | None = None, # noqa
325
- from_list: ta.Sequence[str] | None = None,
326
- level: int = 0,
327
- ) -> types.ModuleType | None:
328
- if not (
329
- globals is not None and
330
- globals.get(self._MOD_SELF_ATTR) is self
331
- ):
332
- return None
333
-
334
- spec = _AutoProxyInitCapture.ModuleSpec(name, level)
335
- module = self._get_or_make_module(spec)
336
-
337
- self._handle_import(
338
- module,
339
- from_list=from_list,
340
- )
341
-
342
- return module.module_obj
343
-
344
- @contextlib.contextmanager
345
- def hook_context(
346
- self,
347
- init_globals: ta.MutableMapping[str, ta.Any], # noqa
348
- *,
349
- forbid_unproxied_imports: bool = False,
350
- ) -> ta.Iterator[None]:
351
- if self._MOD_SELF_ATTR in init_globals:
352
- raise AutoProxyInitErrors.HookError
353
-
354
- old_import = builtins.__import__
355
-
356
- def new_import(
357
- name,
358
- globals=None, # noqa
359
- locals=None, # noqa
360
- fromlist=None,
361
- level=0,
362
- ):
363
- if (im := self._intercept_import(
364
- name,
365
- globals=globals,
366
- from_list=fromlist,
367
- level=level,
368
- )) is not None:
369
- return im
370
-
371
- if forbid_unproxied_imports:
372
- raise AutoProxyInitErrors.UnproxiedImportForbiddenError(
373
- str(_AutoProxyInitCapture.ModuleSpec(name, level)),
374
- fromlist,
375
- )
376
-
377
- return old_import(
378
- name,
379
- globals=globals,
380
- locals=locals,
381
- fromlist=fromlist,
382
- level=level,
383
- )
384
-
385
- #
386
-
387
- init_globals[self._MOD_SELF_ATTR] = self
388
- builtins.__import__ = new_import
389
-
390
- try:
391
- yield
392
-
393
- finally:
394
- if not (
395
- init_globals[self._MOD_SELF_ATTR] is self and
396
- builtins.__import__ is new_import
397
- ):
398
- raise AutoProxyInitErrors.HookError
399
-
400
- del init_globals[self._MOD_SELF_ATTR]
401
- builtins.__import__ = old_import
402
-
403
- #
404
-
405
- def verify_state(
406
- self,
407
- init_globals: ta.MutableMapping[str, ta.Any], # noqa
408
- ) -> None:
409
- for m in self._modules_by_spec.values():
410
- for a, o in m.module_obj.__dict__.items():
411
- try:
412
- i = m.initial_module_dict[a]
413
-
414
- except KeyError:
415
- if o is not m.contents[a]:
416
- raise AutoProxyInitErrors.AttrError(str(m.spec), a) from None
417
-
418
- else:
419
- if o != i:
420
- raise AutoProxyInitErrors.AttrError(str(m.spec), a)
421
-
422
- #
423
-
424
- def build_proxy_inits(
425
- self,
426
- init_globals: ta.MutableMapping[str, ta.Any], # noqa
427
- *,
428
- collect_unreferenced: bool = False,
429
- ) -> 'AutoProxyInit.CapturedProxyInits':
430
- dct: dict[_AutoProxyInitCapture._Module, list[tuple[str | None, str]]] = {}
431
-
432
- rem_whole_mods: set[_AutoProxyInitCapture._Module] = set()
433
- rem_mod_attrs: set[_AutoProxyInitCapture._ModuleAttr] = set()
434
- if collect_unreferenced:
435
- rem_whole_mods.update([m for m in self._modules_by_spec.values() if m.imported_whole])
436
- rem_mod_attrs.update(self._attrs)
437
-
438
- for attr, obj in init_globals.items():
439
- if isinstance(obj, _AutoProxyInitCapture._ModuleAttr):
440
- try:
441
- m, a = self._attrs[obj]
442
- except KeyError:
443
- raise AutoProxyInitErrors.AttrError(None, attr) from None
444
- dct.setdefault(m, []).append((a, attr))
445
- rem_mod_attrs.discard(obj)
446
-
447
- elif isinstance(obj, _AutoProxyInitCapture._Module):
448
- raise AutoProxyInitErrors.AttrError(None, attr) from None
449
-
450
- elif isinstance(obj, types.ModuleType):
451
- try:
452
- m = self._modules_by_module_obj[obj]
453
- except KeyError:
454
- continue
455
- if not m.imported_whole:
456
- raise RuntimeError(f'AutoProxyInit module {m.spec!r} not imported_whole')
457
- dct.setdefault(m, []).append((None, attr))
458
- rem_whole_mods.discard(m)
459
-
460
- lst: list[AutoProxyInit.ProxyInit] = []
461
- for m, ts in dct.items():
462
- if not m.spec.name:
463
- if not m.spec.level:
464
- raise AutoProxyInitError
465
- for imp_attr, as_attr in ts:
466
- if not imp_attr:
467
- raise RuntimeError
468
- lst.append(AutoProxyInit.ProxyInit(
469
- '.' * m.spec.level + imp_attr,
470
- [(None, as_attr)],
471
- ))
472
-
473
- else:
474
- lst.append(AutoProxyInit.ProxyInit(
475
- str(m.spec),
476
- ts,
477
- ))
478
-
479
- unreferenced: dict[str, list[str | None]] | None = None
480
- if collect_unreferenced and (rem_whole_mods or rem_mod_attrs):
481
- unreferenced = {}
482
- for m in rem_whole_mods:
483
- unreferenced.setdefault(str(m.spec), []).append(None)
484
- for ma in rem_mod_attrs:
485
- m, a = self._attrs[ma]
486
- unreferenced.setdefault(str(m.spec), []).append(a)
487
-
488
- return AutoProxyInit.CapturedProxyInits(
489
- lst,
490
- unreferenced,
491
- )
492
-
493
-
494
- class AutoProxyInit:
495
- class ProxyInit(ta.NamedTuple):
496
- package: str
497
- attrs: ta.Sequence[tuple[str | None, str]]
498
-
499
- class CapturedProxyInits(ta.NamedTuple):
500
- proxy_inits: ta.Sequence['AutoProxyInit.ProxyInit']
501
- unreferenced: ta.Mapping[str, ta.Sequence[str | None]] | None
502
-
503
- @property
504
- def attrs(self) -> ta.Iterator[str]:
505
- for pi in self.proxy_inits:
506
- for _, a in pi.attrs:
507
- yield a
508
-
509
- #
510
-
511
- def __init__(
512
- self,
513
- init_globals: ta.MutableMapping[str, ta.Any],
514
- *,
515
- disable: bool = False,
516
- eager: bool = False,
517
- ) -> None:
518
- super().__init__()
519
-
520
- self._init_globals = init_globals
521
-
522
- self._disable = disable
523
- self._eager = eager
524
-
525
- @property
526
- def disable(self) -> bool:
527
- return self._disable
528
-
529
- @property
530
- def eager(self) -> bool:
531
- return self._eager
532
-
533
- #
534
-
535
- class _Result(ta.NamedTuple):
536
- captured: 'AutoProxyInit.CapturedProxyInits'
537
-
538
- _result_: _Result | None = None
539
-
540
- @property
541
- def _result(self) -> _Result:
542
- if (rs := self._result_) is None:
543
- raise AutoProxyInitErrors.CaptureInProgressError
544
- return rs
545
-
546
- @property
547
- def is_complete(self) -> bool:
548
- return self._result_ is not None
549
-
550
- @property
551
- def captured(self) -> CapturedProxyInits:
552
- return self._result.captured
553
-
554
- #
555
-
556
- @contextlib.contextmanager
557
- def _capture(
558
- self,
559
- *,
560
- unreferenced_callback: ta.Callable[[ta.Mapping[str, ta.Sequence[str | None]]], None] | None = None,
561
- raise_unreferenced: bool = False,
562
- ) -> ta.Iterator[None]:
563
- if self._result_ is not None:
564
- raise AutoProxyInitError('capture already complete')
565
-
566
- if self._disable:
567
- self._result_ = AutoProxyInit._Result(
568
- AutoProxyInit.CapturedProxyInits(
569
- [],
570
- None,
571
- ),
572
- )
573
- yield
574
- return
575
-
576
- cap = _AutoProxyInitCapture()
577
-
578
- with cap.hook_context(self._init_globals):
579
- yield
580
-
581
- cap.verify_state(self._init_globals)
582
-
583
- blt = cap.build_proxy_inits(
584
- self._init_globals,
585
- collect_unreferenced=unreferenced_callback is not None or raise_unreferenced,
586
- )
587
-
588
- if blt.unreferenced:
589
- if unreferenced_callback:
590
- unreferenced_callback(blt.unreferenced)
591
- if raise_unreferenced:
592
- raise AutoProxyInitErrors.UnreferencedImportsError(blt.unreferenced)
593
-
594
- for pi in blt.proxy_inits:
595
- for _, a in pi.attrs:
596
- del self._init_globals[a]
597
-
598
- proxy_init(
599
- self._init_globals,
600
- pi.package,
601
- pi.attrs,
602
- )
603
-
604
- if self._eager:
605
- lg = LazyGlobals.install(self._init_globals)
606
-
607
- for a in blt.attrs:
608
- lg.get(a)
609
-
610
- self._result_ = AutoProxyInit._Result(
611
- blt,
612
- )
613
-
614
- #
615
-
616
- def update_exports(self) -> None:
617
- cap = self._result.captured
618
-
619
- try:
620
- al: ta.Any = self._init_globals['__all__']
621
- except KeyError:
622
- al = self._init_globals['__all__'] = [k for k in self._init_globals if not k.startswith('_')]
623
- else:
624
- if not isinstance(al, ta.MutableSequence):
625
- al = self._init_globals['__all__'] = list(al)
626
-
627
- al_s = set(al)
628
- for a in cap.attrs:
629
- if a not in al_s:
630
- al.append(a)
631
- al_s.add(a)
632
-
633
-
634
139
  @contextlib.contextmanager
635
140
  def auto_proxy_init(
636
141
  init_globals: ta.MutableMapping[str, ta.Any],
@@ -642,25 +147,30 @@ def auto_proxy_init(
642
147
  raise_unreferenced: bool = False,
643
148
 
644
149
  update_exports: bool = False,
645
- ) -> ta.Iterator[AutoProxyInit]:
646
- """
647
- This is a bit extreme, but worth it. For simplicity, it currently relies on temporarily patching
648
- `__builtins__.__import__` for the duration of its context manager, but it can be switched to use any number of other
649
- import hooks (like `sys.meta_path`). It does not rely on any permanent modification to import machinery, only for
650
- the duration of its capture.
651
- """
652
-
653
- inst = AutoProxyInit(
150
+ ) -> ta.Iterator[ImportCapture]:
151
+ inst = ImportCapture(
654
152
  init_globals,
655
153
  disable=disable,
656
- eager=eager,
657
154
  )
658
155
 
659
- with inst._capture( # noqa
660
- unreferenced_callback=unreferenced_callback,
661
- raise_unreferenced=raise_unreferenced,
156
+ with inst.capture(
157
+ unreferenced_callback=unreferenced_callback,
158
+ raise_unreferenced=raise_unreferenced,
662
159
  ):
663
160
  yield inst
664
161
 
162
+ for pi in inst.captured.imports:
163
+ proxy_init(
164
+ init_globals,
165
+ pi.spec,
166
+ pi.attrs,
167
+ )
168
+
169
+ if eager:
170
+ lg = LazyGlobals.install(init_globals)
171
+
172
+ for a in inst.captured.attrs:
173
+ lg.get(a)
174
+
665
175
  if update_exports:
666
176
  inst.update_exports()
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.lazy import proxy_import
6
+ from .imports.proxy import proxy_import
7
7
 
8
8
 
9
9
  if ta.TYPE_CHECKING:
omlish/logs/contexts.py CHANGED
@@ -93,16 +93,17 @@ class CaptureLoggingContextImpl(CaptureLoggingContext):
93
93
  stack_offset: int = 0,
94
94
  stack_info: bool = False,
95
95
  ) -> None:
96
- # TODO: Name, Msg, Extra
97
-
98
96
  if time_ns is None:
99
97
  time_ns = time.time_ns()
100
98
 
99
+ # Done early to not trample on sys.exc_info()
100
+ exc = LoggingContextInfos.Exc.build(exc_info)
101
+
101
102
  self._infos: ta.Dict[ta.Type[LoggingContextInfo], LoggingContextInfo] = {}
102
103
  self._set_info(
103
104
  LoggingContextInfos.Level.build(level),
105
+ exc,
104
106
  LoggingContextInfos.Time.build(time_ns),
105
- LoggingContextInfos.Exc.build(exc_info),
106
107
  )
107
108
 
108
109
  if caller is not CaptureLoggingContextImpl.NOT_SET: