0
# Exception Handling
1
2
Comprehensive exception hierarchy for error handling in setuptools operations, including both setuptools-specific errors and re-exported distutils errors for compatibility. These exceptions provide detailed error information for debugging and handling package building issues.
3
4
## Capabilities
5
6
### Setuptools Warnings
7
8
Warning classes for deprecation notices and non-fatal issues.
9
10
```python { .api }
11
class SetuptoolsDeprecationWarning(UserWarning):
12
"""
13
Base class for setuptools deprecation warnings.
14
15
Enhanced deprecation warning with better formatting and
16
contextual information about deprecated functionality.
17
18
This warning is raised when setuptools features are used
19
that will be removed in future versions.
20
"""
21
```
22
23
### Core Setuptools Errors
24
25
Primary exception classes for setuptools-specific errors.
26
27
```python { .api }
28
class BaseError(Exception):
29
"""
30
Root error class for all setuptools errors.
31
32
This is an alias to distutils.errors.DistutilsError for
33
compatibility and provides the base for setuptools exceptions.
34
"""
35
36
class InvalidConfigError(BaseError):
37
"""
38
Exception raised for invalid configuration.
39
40
Raised when configuration files (setup.cfg, pyproject.toml)
41
contain invalid values, syntax errors, or incompatible options.
42
43
Common scenarios:
44
- Invalid setup.cfg syntax
45
- Incompatible configuration values
46
- Missing required configuration sections
47
- Invalid pyproject.toml structure
48
"""
49
50
class RemovedConfigError(BaseError):
51
"""
52
Exception raised when using removed or deprecated configuration.
53
54
Raised when configuration options that have been removed from
55
setuptools are still used in configuration files.
56
57
Common scenarios:
58
- Using deprecated setup.cfg options
59
- Obsolete command configuration
60
- Removed metadata fields
61
"""
62
63
class RemovedCommandError(BaseError):
64
"""
65
Exception raised when using removed setuptools commands.
66
67
Raised when attempting to use setuptools commands that have
68
been removed or deprecated.
69
70
Common scenarios:
71
- Using removed command classes
72
- Attempting to run obsolete commands
73
- Deprecated command-line options
74
"""
75
76
class PackageDiscoveryError(BaseError):
77
"""
78
Exception raised during package discovery.
79
80
Raised when find_packages() or related functions encounter
81
issues while discovering packages in the source tree.
82
83
Common scenarios:
84
- Circular imports during discovery
85
- Invalid package structure
86
- Permission issues accessing directories
87
- Conflicting package names
88
"""
89
```
90
91
### Build Backend Errors
92
93
Errors specific to the PEP 517/518 build backend functionality.
94
95
```python { .api }
96
class SetupRequirementsError(BaseError):
97
"""
98
Exception raised when setup requirements cannot be satisfied.
99
100
Raised by the build backend when dependencies needed for building
101
the package cannot be installed or are incompatible.
102
103
Attributes:
104
- specifiers (list): List of requirement specifiers that failed
105
"""
106
107
def __init__(self, specifiers):
108
"""
109
Initialize with failed requirement specifiers.
110
111
Parameters:
112
- specifiers (list): Requirements that could not be satisfied
113
"""
114
self.specifiers = specifiers
115
super().__init__(f"Could not satisfy requirements: {specifiers}")
116
```
117
118
### Distutils Error Re-exports
119
120
Setuptools re-exports all distutils errors for compatibility, allowing code to import errors from setuptools instead of distutils.
121
122
```python { .api }
123
class DistutilsError(Exception):
124
"""Base class for distutils errors."""
125
126
class DistutilsModuleError(DistutilsError):
127
"""Module-related errors."""
128
129
class DistutilsClassError(DistutilsError):
130
"""Class-related errors."""
131
132
class DistutilsGetoptError(DistutilsError):
133
"""Command-line option parsing errors."""
134
135
class DistutilsArgError(DistutilsError):
136
"""Invalid argument errors."""
137
138
class DistutilsFileError(DistutilsError):
139
"""File operation errors."""
140
141
class DistutilsOptionError(DistutilsError):
142
"""Invalid option errors."""
143
144
class DistutilsSetupError(DistutilsError):
145
"""Setup configuration errors."""
146
147
class DistutilsPlatformError(DistutilsError):
148
"""Platform-specific errors."""
149
150
class DistutilsExecError(DistutilsError):
151
"""Command execution errors."""
152
153
class DistutilsInternalError(DistutilsError):
154
"""Internal setuptools/distutils errors."""
155
156
class DistutilsTemplateError(DistutilsError):
157
"""Template processing errors."""
158
159
class DistutilsByteCompileError(DistutilsError):
160
"""Python bytecode compilation errors."""
161
162
# Compilation and linking errors
163
class CCompilerError(Exception):
164
"""C compiler errors."""
165
166
class PreprocessError(CCompilerError):
167
"""Preprocessor errors."""
168
169
class CompileError(CCompilerError):
170
"""Compilation errors."""
171
172
class LibError(CCompilerError):
173
"""Library creation errors."""
174
175
class LinkError(CCompilerError):
176
"""Linking errors."""
177
178
class UnknownFileError(CCompilerError):
179
"""Unknown file type errors."""
180
```
181
182
## Usage Examples
183
184
### Basic Error Handling
185
186
```python
187
from setuptools import setup, find_packages
188
from setuptools.errors import (
189
InvalidConfigError,
190
PackageDiscoveryError,
191
SetupRequirementsError
192
)
193
194
try:
195
packages = find_packages()
196
setup(
197
name='my-package',
198
packages=packages,
199
# ... other configuration
200
)
201
except PackageDiscoveryError as e:
202
print(f"Could not discover packages: {e}")
203
# Handle package discovery issues
204
except InvalidConfigError as e:
205
print(f"Invalid configuration: {e}")
206
# Handle configuration errors
207
except Exception as e:
208
print(f"Setup failed: {e}")
209
raise
210
```
211
212
### Build Backend Error Handling
213
214
```python
215
from setuptools.build_meta import build_wheel, SetupRequirementsError
216
217
def safe_build_wheel(wheel_directory, config_settings=None):
218
"""Safely build a wheel with error handling."""
219
try:
220
return build_wheel(wheel_directory, config_settings)
221
except SetupRequirementsError as e:
222
print(f"Missing build requirements: {e.specifiers}")
223
# Could install requirements and retry
224
raise
225
except Exception as e:
226
print(f"Build failed: {e}")
227
raise
228
```
229
230
### Warning Handling
231
232
```python
233
import warnings
234
from setuptools.warnings import SetuptoolsDeprecationWarning
235
236
# Filter setuptools deprecation warnings
237
warnings.filterwarnings('ignore', category=SetuptoolsDeprecationWarning)
238
239
# Or handle them explicitly
240
def handle_setuptools_warnings():
241
"""Custom handler for setuptools warnings."""
242
warnings.filterwarnings(
243
'error', # Convert to exception
244
category=SetuptoolsDeprecationWarning
245
)
246
247
try:
248
# Some setuptools operation that might warn
249
from setuptools import setup
250
setup(
251
name='my-package',
252
# ... configuration that might use deprecated features
253
)
254
except SetuptoolsDeprecationWarning as w:
255
print(f"Deprecated feature used: {w}")
256
# Update configuration to remove deprecated usage
257
```
258
259
### Custom Command Error Handling
260
261
```python
262
from setuptools import Command
263
from setuptools.errors import DistutilsSetupError, DistutilsExecError
264
265
class CustomCommand(Command):
266
"""Custom command with proper error handling."""
267
268
description = 'Custom command with error handling'
269
user_options = []
270
271
def initialize_options(self):
272
pass
273
274
def finalize_options(self):
275
# Validate options
276
if not hasattr(self, 'required_option'):
277
raise DistutilsSetupError('required_option must be set')
278
279
def run(self):
280
try:
281
# Command implementation
282
self.execute_custom_logic()
283
except subprocess.CalledProcessError as e:
284
raise DistutilsExecError(f'Command failed: {e}') from e
285
except FileNotFoundError as e:
286
raise DistutilsFileError(f'Required file not found: {e}') from e
287
288
def execute_custom_logic(self):
289
"""Custom command logic that might fail."""
290
pass
291
```
292
293
### Extension Build Error Handling
294
295
```python
296
from setuptools import setup, Extension
297
from setuptools.errors import CCompilerError, CompileError
298
299
def build_extensions_safely():
300
"""Build extensions with proper error handling."""
301
extensions = [
302
Extension(
303
'my_package.fast_module',
304
sources=['src/fast_module.c'],
305
)
306
]
307
308
try:
309
setup(
310
name='my-package',
311
ext_modules=extensions,
312
)
313
except CCompilerError as e:
314
print(f"Compiler error: {e}")
315
# Could fall back to pure Python implementation
316
setup(
317
name='my-package',
318
# Setup without extensions
319
)
320
except CompileError as e:
321
print(f"Compilation failed: {e}")
322
# Handle compilation failure
323
raise
324
```
325
326
### Configuration Error Recovery
327
328
```python
329
from setuptools import setup
330
from setuptools.errors import InvalidConfigError, RemovedConfigError
331
332
def setup_with_fallback():
333
"""Setup with configuration error recovery."""
334
try:
335
# Try modern configuration
336
setup(
337
name='my-package',
338
# Modern setuptools configuration
339
)
340
except RemovedConfigError as e:
341
print(f"Using deprecated configuration: {e}")
342
# Fall back to alternative configuration
343
setup(
344
name='my-package',
345
# Alternative configuration without deprecated features
346
)
347
except InvalidConfigError as e:
348
print(f"Invalid configuration: {e}")
349
# Provide helpful error message and fix suggestions
350
print("Please check your setup.cfg or pyproject.toml for errors")
351
raise
352
```
353
354
### Comprehensive Error Handling
355
356
```python
357
from setuptools import setup, find_packages
358
from setuptools.errors import *
359
import logging
360
361
def robust_setup():
362
"""Setup with comprehensive error handling."""
363
logging.basicConfig(level=logging.INFO)
364
logger = logging.getLogger(__name__)
365
366
try:
367
packages = find_packages()
368
logger.info(f"Found packages: {packages}")
369
370
setup(
371
name='my-package',
372
version='1.0.0',
373
packages=packages,
374
# ... other configuration
375
)
376
logger.info("Setup completed successfully")
377
378
except PackageDiscoveryError as e:
379
logger.error(f"Package discovery failed: {e}")
380
# Could manually specify packages as fallback
381
raise
382
383
except InvalidConfigError as e:
384
logger.error(f"Configuration error: {e}")
385
# Log detailed error information
386
raise
387
388
except SetupRequirementsError as e:
389
logger.error(f"Build requirements not satisfied: {e.specifiers}")
390
# Could attempt to install requirements
391
raise
392
393
except DistutilsError as e:
394
logger.error(f"Distutils error: {e}")
395
# Handle general distutils errors
396
raise
397
398
except Exception as e:
399
logger.error(f"Unexpected error during setup: {e}")
400
# Log full traceback for debugging
401
logger.exception("Full traceback:")
402
raise
403
404
if __name__ == '__main__':
405
robust_setup()
406
```