or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

dependency-tracking.mdindex.mdlazy-import-errors.mdsetup-tools.md

lazy-import-errors.mddocs/

0

# Lazy Import Errors

1

2

Context manager and function for deferring ImportError exceptions until modules are actually used, preventing crashes from missing optional dependencies during import time.

3

4

## Capabilities

5

6

### Lazy Import Error Context Manager

7

8

Enables lazy import error handling that captures ImportError exceptions and defers them until the module is actually used, allowing imports of optional dependencies to succeed even when the dependency is not installed.

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.

18

19

When enabled, lazy import errors will capture imports that would otherwise

20

raise ImportErrors and defer those errors until the last possible moment

21

when the functionality is needed.

22

23

This function may be used either as a function directly or as a

24

contextmanager which will disable lazy errors upon exit.

25

26

Args:

27

get_extras_modules: Optional callable that fetches the list of module names

28

that are managed as extras using setup_tools.parse_requirements.

29

(Mutually exclusive with make_error_message)

30

make_error_message: Optional callable that takes the name of the module which

31

failed to import and returns an error message string.

32

(Mutually exclusive with get_extras_modules)

33

"""

34

```

35

36

### Global Lazy Import Errors

37

38

Enable lazy import errors globally for all subsequent imports:

39

40

```python

41

from import_tracker import lazy_import_errors

42

43

# Enable globally - all failed imports will be deferred

44

lazy_import_errors()

45

46

# Now these imports won't crash even if modules are missing

47

import optional_module

48

from some_package import maybe_missing_submodule

49

50

# Error will be raised only when you try to use the module

51

try:

52

optional_module.some_function() # ModuleNotFoundError raised here

53

except ModuleNotFoundError as e:

54

print(f"Module not available: {e}")

55

```

56

57

### Context Manager Usage

58

59

Use as a context manager to enable lazy errors only for specific imports:

60

61

```python

62

from import_tracker import lazy_import_errors

63

64

# Required imports - will fail immediately if missing

65

import requests

66

import json

67

68

# Optional imports - errors deferred until usage

69

with lazy_import_errors():

70

import matplotlib.pyplot as plt

71

import seaborn as sns

72

from some_package import optional_feature

73

74

# These will work fine even if matplotlib/seaborn are not installed

75

print("Imports completed successfully")

76

77

# Error raised only when trying to use missing modules

78

try:

79

plt.plot([1, 2, 3]) # ModuleNotFoundError raised here if matplotlib missing

80

except ModuleNotFoundError:

81

print("Matplotlib not available, using basic plotting")

82

```

83

84

### Custom Error Messages

85

86

Provide custom error messages for missing dependencies:

87

88

```python

89

def custom_error_message(module_name: str) -> str:

90

return f"Missing optional dependency: {module_name}. Install with: pip install {module_name}"

91

92

with lazy_import_errors(make_error_message=custom_error_message):

93

import some_optional_module

94

95

# When used, will show custom message:

96

# ModuleNotFoundError: Missing optional dependency: some_optional_module. Install with: pip install some_optional_module

97

```

98

99

### Extras Integration

100

101

Integration with setuptools extras_require for helpful installation messages:

102

103

```python

104

def get_extras_modules():

105

return {'my_package.plotting', 'my_package.advanced_features'}

106

107

with lazy_import_errors(get_extras_modules=get_extras_modules):

108

from my_package import plotting

109

110

# When used within an extras module, provides installation instructions:

111

# ModuleNotFoundError: No module named 'matplotlib'.

112

# To install the missing dependencies, run `pip install my_package[my_package.plotting]`

113

```

114

115

### Practical Usage Patterns

116

117

#### Optional Dependency Handling

118

119

```python

120

from import_tracker import lazy_import_errors

121

122

# Enable lazy errors for optional dependencies

123

with lazy_import_errors():

124

try:

125

import pandas as pd

126

HAS_PANDAS = True

127

except ImportError:

128

HAS_PANDAS = False

129

130

def process_data(data):

131

if HAS_PANDAS:

132

return pd.DataFrame(data).describe()

133

else:

134

return {"error": "pandas not available"}

135

```

136

137

#### Hierarchical Wild Imports

138

139

Particularly useful for packages with hierarchical wild imports:

140

141

```python

142

# In my_package/__init__.py

143

from import_tracker import lazy_import_errors

144

145

# Enable lazy errors globally for this package

146

lazy_import_errors()

147

148

# These won't crash the entire package if submodules have missing dependencies

149

from .core import *

150

from .utils import *

151

from .optional_features import * # Won't crash if dependencies missing

152

```

153

154

#### Decorator Compatibility

155

156

Lazy errors work with decorators from missing dependencies:

157

158

```python

159

with lazy_import_errors():

160

from some_optional_package import optional_decorator

161

162

# This works even if some_optional_package is not installed

163

@optional_decorator

164

def my_function():

165

pass

166

167

# Error only raised when decorator functionality is actually invoked

168

```

169

170

## Internal Implementation

171

172

The lazy import error system is implemented using several internal classes:

173

174

### Meta Path Finder System

175

176

```python { .api }

177

class _LazyErrorMetaFinder(importlib.abc.MetaPathFinder):

178

"""Meta path finder for intercepting import failures"""

179

180

def find_spec(self, fullname, path, *args, **kwargs):

181

"""Returns lazy loader spec for missing modules"""

182

183

class _LazyErrorLoader(importlib.abc.Loader):

184

"""Loader for creating lazy error modules"""

185

186

def create_module(self, spec):

187

"""Creates _LazyErrorModule instances"""

188

189

def exec_module(self, *_, **__):

190

"""No-op execution"""

191

```

192

193

### Lazy Error Objects

194

195

```python { .api }

196

class _LazyErrorModule(ModuleType):

197

"""Module that defers ImportError until attribute access"""

198

199

def __getattr__(self, name: str) -> _LazyErrorAttr:

200

"""Returns lazy error attributes"""

201

202

class _LazyErrorAttr(type):

203

"""Lazy error object that raises on any meaningful usage"""

204

205

def __call__(self, *_, **__):

206

"""Handles decorator usage at import time"""

207

208

def __getattr__(self, name: str) -> "_LazyErrorAttr":

209

"""Recursive attribute access"""

210

```

211

212

## Error Behavior

213

214

### Import Time vs Usage Time

215

216

```python

217

# Import time - no error raised

218

with lazy_import_errors():

219

import missing_module

220

221

# Usage time - error raised on meaningful operations

222

missing_module.function() # Raises ModuleNotFoundError

223

str(missing_module) # Raises ModuleNotFoundError

224

missing_module == something # Returns False (import time operation)

225

missing_module.attr.nested # Returns another lazy error object

226

```

227

228

### Shell Environment Note

229

230

When using extras integration, be aware of shell escaping requirements:

231

232

```bash

233

# In bash/sh

234

pip install my_package[my_package.feature]

235

236

# In zsh - requires escaping

237

pip install my_package\[my_package.feature\]

238

```

239

240

## Types

241

242

```python { .api }

243

from typing import Callable, Optional, Set

244

from contextlib import AbstractContextManager

245

246

# Function parameter types

247

GetExtrasModulesFunc = Callable[[], Set[str]]

248

MakeErrorMessageFunc = Callable[[str], str]

249

250

# Context manager type

251

LazyImportErrorContext = AbstractContextManager[None]

252

```