Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/websockets/imports.py: 71%
42 statements
« prev ^ index » next coverage.py v7.3.1, created at 2023-09-25 06:20 +0000
« prev ^ index » next coverage.py v7.3.1, created at 2023-09-25 06:20 +0000
1from __future__ import annotations
3import warnings
4from typing import Any, Dict, Iterable, Optional
7__all__ = ["lazy_import"]
10def import_name(name: str, source: str, namespace: Dict[str, Any]) -> Any:
11 """
12 Import ``name`` from ``source`` in ``namespace``.
14 There are two use cases:
16 - ``name`` is an object defined in ``source``;
17 - ``name`` is a submodule of ``source``.
19 Neither :func:`__import__` nor :func:`~importlib.import_module` does
20 exactly this. :func:`__import__` is closer to the intended behavior.
22 """
23 level = 0
24 while source[level] == ".":
25 level += 1
26 assert level < len(source), "importing from parent isn't supported"
27 module = __import__(source[level:], namespace, None, [name], level)
28 return getattr(module, name)
31def lazy_import(
32 namespace: Dict[str, Any],
33 aliases: Optional[Dict[str, str]] = None,
34 deprecated_aliases: Optional[Dict[str, str]] = None,
35) -> None:
36 """
37 Provide lazy, module-level imports.
39 Typical use::
41 __getattr__, __dir__ = lazy_import(
42 globals(),
43 aliases={
44 "<name>": "<source module>",
45 ...
46 },
47 deprecated_aliases={
48 ...,
49 }
50 )
52 This function defines ``__getattr__`` and ``__dir__`` per :pep:`562`.
54 """
55 if aliases is None:
56 aliases = {}
57 if deprecated_aliases is None:
58 deprecated_aliases = {}
60 namespace_set = set(namespace)
61 aliases_set = set(aliases)
62 deprecated_aliases_set = set(deprecated_aliases)
64 assert not namespace_set & aliases_set, "namespace conflict"
65 assert not namespace_set & deprecated_aliases_set, "namespace conflict"
66 assert not aliases_set & deprecated_aliases_set, "namespace conflict"
68 package = namespace["__name__"]
70 def __getattr__(name: str) -> Any:
71 assert aliases is not None # mypy cannot figure this out
72 try:
73 source = aliases[name]
74 except KeyError:
75 pass
76 else:
77 return import_name(name, source, namespace)
79 assert deprecated_aliases is not None # mypy cannot figure this out
80 try:
81 source = deprecated_aliases[name]
82 except KeyError:
83 pass
84 else:
85 warnings.warn(
86 f"{package}.{name} is deprecated",
87 DeprecationWarning,
88 stacklevel=2,
89 )
90 return import_name(name, source, namespace)
92 raise AttributeError(f"module {package!r} has no attribute {name!r}")
94 namespace["__getattr__"] = __getattr__
96 def __dir__() -> Iterable[str]:
97 return sorted(namespace_set | aliases_set | deprecated_aliases_set)
99 namespace["__dir__"] = __dir__