0
# Lazy Import Handling
1
2
Import Tracker provides sophisticated lazy import error handling that defers `ModuleNotFoundError` exceptions until the missing module is actually used. This enables graceful handling of optional dependencies and prevents crashes during import of packages with complex hierarchical wild imports.
3
4
## Capabilities
5
6
### Lazy Import Error Context Manager
7
8
Enables lazy import errors either globally or within a specific context. When enabled, import failures are deferred until the module is actually accessed.
9
10
```python { .api }
11
def lazy_import_errors(
12
*,
13
get_extras_modules: Optional[Callable[[], Set[str]]] = None,
14
make_error_message: Optional[Callable[[str], str]] = None,
15
):
16
"""
17
Enable lazy import errors that defer ModuleNotFoundError until module usage.
18
19
Parameters:
20
- get_extras_modules: Optional[Callable[[], Set[str]]] - Function returning set of extras module names
21
- make_error_message: Optional[Callable[[str], str]] - Custom error message generator function
22
23
Returns:
24
Context manager object that can be used with 'with' statement or called directly
25
26
Note: get_extras_modules and make_error_message are mutually exclusive
27
"""
28
```
29
30
**Usage Examples:**
31
32
```python
33
import import_tracker
34
35
# Global lazy import errors
36
import_tracker.lazy_import_errors()
37
import some_optional_package # Won't crash if missing
38
39
# Context manager approach
40
with import_tracker.lazy_import_errors():
41
import optional_module
42
import another_optional_module
43
44
# Access triggers the error
45
try:
46
optional_module.some_function() # ModuleNotFoundError raised here
47
except ModuleNotFoundError as e:
48
print(f"Optional dependency missing: {e}")
49
50
# Custom error messages for extras
51
def get_my_extras():
52
return {"mylib.viz", "mylib.ml", "mylib.web"}
53
54
with import_tracker.lazy_import_errors(get_extras_modules=get_my_extras):
55
import mylib.viz # Error includes pip install command if missing
56
```
57
58
### Custom Error Messages
59
60
Customize error messages for missing modules, particularly useful for indicating which extras need to be installed:
61
62
```python
63
# Using get_extras_modules for automatic pip install messages
64
def get_extras_modules():
65
return {"mypackage.plotting", "mypackage.database"}
66
67
import_tracker.lazy_import_errors(get_extras_modules=get_extras_modules)
68
69
# When mypackage.plotting is missing, error message will be:
70
# "No module named 'matplotlib'. To install the missing dependencies,
71
# run `pip install mypackage[mypackage.plotting]`"
72
73
# Custom error message function
74
def custom_error_message(missing_module):
75
return f"Module {missing_module} is not available. Install it with: pip install {missing_module}"
76
77
import_tracker.lazy_import_errors(make_error_message=custom_error_message)
78
```
79
80
### Lazy Module Wrapper
81
82
Provides a module wrapper that defers the actual import until an attribute is accessed, useful for expensive imports.
83
84
```python { .api }
85
class LazyModule(ModuleType):
86
"""
87
A module subclass that wraps another module with lazy importing.
88
89
The wrapped module is not imported until an attribute is accessed.
90
"""
91
92
def __init__(self, name: str, package: Optional[str] = None):
93
"""
94
Initialize lazy module wrapper.
95
96
Parameters:
97
- name: str - Name of module to import lazily
98
- package: Optional[str] - Parent package name for relative imports
99
"""
100
101
def __getattr__(self, name: str) -> any:
102
"""
103
Trigger lazy import when attribute is accessed.
104
105
Parameters:
106
- name: str - Attribute name being accessed
107
108
Returns:
109
Attribute from the lazily imported module
110
"""
111
```
112
113
**Usage Example:**
114
115
```python
116
import import_tracker
117
118
# Create lazy module - no import happens yet
119
numpy = import_tracker.LazyModule("numpy")
120
pandas = import_tracker.LazyModule("pandas")
121
122
# Import only happens when attribute is accessed
123
array = numpy.array([1, 2, 3]) # numpy imported here
124
df = pandas.DataFrame({"x": [1, 2, 3]}) # pandas imported here
125
126
# Relative import with package
127
submodule = import_tracker.LazyModule(".utils", package="mypackage")
128
result = submodule.helper_function() # mypackage.utils imported here
129
```
130
131
## Advanced Usage Patterns
132
133
### Selective Lazy Imports
134
135
Apply lazy import handling only to specific modules while requiring others to exist:
136
137
```python
138
import import_tracker
139
140
# Core dependencies must exist
141
from mylib import core, utils
142
143
# Optional dependencies can be missing
144
with import_tracker.lazy_import_errors():
145
from mylib import plotting, advanced_analytics
146
147
# Use with error handling
148
def create_plot(data):
149
try:
150
return plotting.make_chart(data)
151
except ModuleNotFoundError:
152
return "Plotting not available - install with: pip install mylib[plotting]"
153
```
154
155
### Hierarchical Wild Imports
156
157
Handle complex packages that use wild imports across many submodules:
158
159
```python
160
import import_tracker
161
162
# Enable lazy errors before importing large package
163
import_tracker.lazy_import_errors()
164
165
# This won't crash even if some submodules have missing dependencies
166
from large_scientific_package import *
167
168
# Errors only occur when specific functionality is used
169
try:
170
result = some_advanced_function()
171
except ModuleNotFoundError as e:
172
print(f"Advanced features not available: {e}")
173
```
174
175
### Integration with Package Extras
176
177
Coordinate lazy imports with setuptools extras for better user experience:
178
179
```python
180
import import_tracker
181
182
def get_my_extras():
183
"""Return set of modules managed as extras."""
184
return {
185
"mypackage.visualization",
186
"mypackage.machine_learning",
187
"mypackage.database"
188
}
189
190
# Enable with extras integration
191
import_tracker.lazy_import_errors(get_extras_modules=get_my_extras)
192
193
# Imports that might fail get helpful error messages
194
try:
195
from mypackage.visualization import plot_data
196
plot_data(my_data)
197
except ModuleNotFoundError as e:
198
# Error includes: "run `pip install mypackage[mypackage.visualization]`"
199
print(e)
200
```
201
202
## Implementation Notes
203
204
- Lazy import errors work by installing custom meta path finders that intercept import failures
205
- The system tracks the calling package to avoid interfering with unrelated imports
206
- When used as a context manager, the lazy error handlers are automatically cleaned up on exit
207
- The `LazyModule` class extends `ModuleType` and delegates all attribute access to the actual module once imported
208
- Import stack tracking is disabled in lazy import mode to avoid performance overhead