1
- import importlib
2
1
import sys
3
2
import warnings
4
3
from typing import Any , Dict , Iterable , Optional
7
6
__all__ = ["lazy_import" ]
8
7
9
8
9
+ def import_name (name : str , source : str , namespace : Dict [str , Any ]) -> Any :
10
+ """
11
+ Import <name> from <source> in <namespace>.
12
+
13
+ There are two cases:
14
+
15
+ - <name> is an object defined in <source>
16
+ - <name> is a submodule of source
17
+
18
+ Neither __import__ nor importlib.import_module does exactly this.
19
+ __import__ is closer to the intended behavior.
20
+
21
+ """
22
+ level = 0
23
+ while source [level ] == "." :
24
+ level += 1
25
+ assert level < len (source ), "importing from parent isn't supported"
26
+ module = __import__ (source [level :], namespace , None , [name ], level )
27
+ return getattr (module , name )
28
+
29
+
10
30
def lazy_import (
11
31
namespace : Dict [str , Any ],
12
32
aliases : Optional [Dict [str , str ]] = None ,
@@ -58,8 +78,7 @@ def __getattr__(name: str) -> Any:
58
78
except KeyError :
59
79
pass
60
80
else :
61
- module = importlib .import_module (source , package )
62
- return getattr (module , name )
81
+ return import_name (name , source , namespace )
63
82
64
83
assert deprecated_aliases is not None # mypy cannot figure this out
65
84
try :
@@ -72,8 +91,7 @@ def __getattr__(name: str) -> Any:
72
91
DeprecationWarning ,
73
92
stacklevel = 2 ,
74
93
)
75
- module = importlib .import_module (source , package )
76
- return getattr (module , name )
94
+ return import_name (name , source , namespace )
77
95
78
96
raise AttributeError (f"module { package !r} has no attribute { name !r} " )
79
97
@@ -87,9 +105,7 @@ def __dir__() -> Iterable[str]:
87
105
else : # pragma: no cover
88
106
89
107
for name , source in aliases .items ():
90
- module = importlib .import_module (source , package )
91
- namespace [name ] = getattr (module , name )
108
+ namespace [name ] = import_name (name , source , namespace )
92
109
93
110
for name , source in deprecated_aliases .items ():
94
- module = importlib .import_module (source , package )
95
- namespace [name ] = getattr (module , name )
111
+ namespace [name ] = import_name (name , source , namespace )
0 commit comments