0
# Error Handling
1
2
pytest-cov provides comprehensive error handling with specific exception types and warning categories for different failure scenarios. This enables proper error reporting and allows users to handle coverage-related issues appropriately.
3
4
## Capabilities
5
6
### Core Exceptions
7
8
Custom exception types for coverage-related errors.
9
10
```python { .api }
11
class CoverageError(Exception):
12
"""
13
Indicates that coverage measurement has failed or coverage is too low.
14
15
Raised when coverage thresholds are not met or when coverage measurement
16
encounters critical errors that prevent proper operation.
17
18
Usage:
19
Used internally by coverage threshold checking and can be raised
20
by user code that implements custom coverage validation.
21
"""
22
23
class DistCovError(Exception):
24
"""
25
Raised when distributed testing configuration conflicts with coverage settings.
26
27
Specifically raised when dynamic_context='test_function' is configured
28
in coverage settings while using pytest-xdist for distributed testing,
29
which is known to cause coverage data corruption.
30
31
Reference: https://github.com/pytest-dev/pytest-cov/issues/604
32
33
Usage:
34
Automatically raised during distributed master initialization
35
if incompatible configuration is detected.
36
"""
37
```
38
39
**Usage Examples:**
40
41
```python
42
from pytest_cov import CoverageError, DistCovError
43
44
# CoverageError usage
45
def validate_coverage_threshold(coverage_percent, threshold):
46
if coverage_percent < threshold:
47
raise CoverageError(f"Coverage {coverage_percent}% below threshold {threshold}%")
48
49
# DistCovError is raised automatically by pytest-cov
50
# when incompatible configuration is detected:
51
# pytest --cov=mypackage -n 4 # with dynamic_context=test_function in .coveragerc
52
```
53
54
### Warning System
55
56
Hierarchical warning system for non-fatal coverage issues.
57
58
```python { .api }
59
class PytestCovWarning(pytest.PytestWarning):
60
"""
61
Base class for all pytest-cov warnings.
62
63
Inherits from pytest.PytestWarning to integrate with pytest's warning
64
system. Never raised directly - serves as base for specific warning types.
65
66
All pytest-cov warnings inherit from this class, allowing users to
67
filter all coverage warnings with a single filter specification.
68
"""
69
70
class CovDisabledWarning(PytestCovWarning):
71
"""
72
Warning when coverage measurement is manually disabled.
73
74
Raised when --no-cov flag is used in combination with other coverage
75
options, indicating that coverage has been intentionally disabled
76
but other coverage-related options were specified.
77
"""
78
79
class CovReportWarning(PytestCovWarning):
80
"""
81
Warning when coverage report generation fails.
82
83
Raised when coverage measurement completes successfully but report
84
generation encounters errors (e.g., file I/O issues, format errors,
85
or coverage.py exceptions during report creation).
86
"""
87
88
class CentralCovContextWarning(PytestCovWarning):
89
"""
90
Warning about suboptimal coverage context configuration.
91
92
Raised when dynamic_context='test_function' is detected in coverage
93
configuration. Recommends using --cov-context option instead, which
94
provides more complete and reliable per-test context tracking.
95
"""
96
```
97
98
**Usage Examples:**
99
100
```python
101
import warnings
102
from pytest_cov import PytestCovWarning, CovDisabledWarning
103
104
# Filter all pytest-cov warnings
105
warnings.filterwarnings('ignore', category=PytestCovWarning)
106
107
# Filter specific warning types
108
warnings.filterwarnings('ignore', category=CovDisabledWarning)
109
110
# Convert warnings to errors for strict validation
111
warnings.filterwarnings('error', category=CovReportWarning)
112
```
113
114
### Engine-Level Exceptions
115
116
Internal exceptions for coverage engine operation.
117
118
```python { .api }
119
class BrokenCovConfigError(Exception):
120
"""
121
Exception raised when coverage configuration is invalid or corrupted.
122
123
Indicates that coverage configuration files cannot be parsed or
124
contain invalid settings that prevent coverage measurement from
125
starting properly.
126
127
Usage:
128
Raised internally by coverage controllers when configuration
129
validation fails during initialization.
130
"""
131
```
132
133
## Error Handling Patterns
134
135
### Threshold Validation
136
137
How coverage threshold failures are handled:
138
139
```python
140
# Internal threshold checking logic
141
if should_fail_under(total_coverage, threshold, precision):
142
message = f'Coverage failure: total of {total_coverage} is less than fail-under={threshold}'
143
# Display error and increment test failure count
144
terminalreporter.write(f'\nERROR: {message}\n', red=True, bold=True)
145
session.testsfailed += 1
146
```
147
148
### Report Generation Errors
149
150
Handling failures during report generation:
151
152
```python
153
try:
154
total_coverage = self.cov_controller.summary(self.cov_report)
155
except CoverageException as exc:
156
message = f'Failed to generate report: {exc}\n'
157
terminalreporter.write(f'\nWARNING: {message}\n', red=True, bold=True)
158
warnings.warn(CovReportWarning(message), stacklevel=1)
159
total_coverage = 0
160
```
161
162
### Distributed Testing Validation
163
164
Validation for distributed testing compatibility:
165
166
```python
167
if self.cov.config.dynamic_context == 'test_function':
168
raise DistCovError(
169
'Detected dynamic_context=test_function in coverage configuration. '
170
'This is known to cause issues when using xdist, see: https://github.com/pytest-dev/pytest-cov/issues/604\n'
171
'It is recommended to use --cov-context instead.'
172
)
173
```
174
175
### Warning Integration
176
177
How warnings are integrated with pytest's warning system:
178
179
```python
180
# Warning filter setup during test execution
181
warnings.filterwarnings('default', 'unclosed database in <sqlite3.Connection object at', ResourceWarning)
182
warnings.simplefilter('once', PytestCovWarning)
183
warnings.simplefilter('once', CoverageWarning)
184
185
# Warning emission
186
warnings.warn(CovDisabledWarning(message), stacklevel=1)
187
warnings.warn(CovReportWarning(message), stacklevel=1)
188
warnings.warn(CentralCovContextWarning(message), stacklevel=1)
189
```
190
191
## Configuration Validation
192
193
### Command-line Validation
194
195
Validation functions for command-line arguments:
196
197
```python { .api }
198
def validate_report(arg: str) -> tuple:
199
"""
200
Validate --cov-report argument format and compatibility.
201
202
Args:
203
arg: Report specification string
204
205
Returns:
206
tuple: (report_type, modifier_or_output)
207
208
Raises:
209
argparse.ArgumentTypeError: If format invalid or unsupported
210
211
Validation includes:
212
- Report type must be valid (term, html, xml, json, lcov, annotate)
213
- LCOV requires coverage.py >= 6.3
214
- Modifiers only allowed for appropriate report types
215
"""
216
217
def validate_fail_under(num_str: str) -> Union[int, float]:
218
"""
219
Validate --cov-fail-under threshold value.
220
221
Args:
222
num_str: Numeric threshold string
223
224
Returns:
225
Union[int, float]: Validated threshold value
226
227
Raises:
228
argparse.ArgumentTypeError: If not numeric or > 100
229
230
Includes humorous error message for values > 100:
231
"Your desire for over-achievement is admirable but misplaced..."
232
"""
233
234
def validate_context(arg: str) -> str:
235
"""
236
Validate --cov-context argument and coverage.py compatibility.
237
238
Args:
239
arg: Context specification
240
241
Returns:
242
str: Validated context value
243
244
Raises:
245
argparse.ArgumentTypeError: If unsupported context or old coverage.py
246
247
Requires coverage.py >= 5.0 and currently only supports 'test' context.
248
"""
249
```
250
251
### Error Recovery
252
253
How pytest-cov handles and recovers from various error conditions:
254
255
#### Missing Coverage Plugin
256
257
```python
258
# Graceful handling when coverage plugin not available
259
if request.config.pluginmanager.hasplugin('_cov'):
260
plugin = request.config.pluginmanager.getplugin('_cov')
261
if plugin.cov_controller:
262
return plugin.cov_controller.cov
263
return None # Graceful fallback
264
```
265
266
#### Worker Communication Failures
267
268
```python
269
# Handle failed workers in distributed testing
270
if 'cov_worker_node_id' not in output:
271
self.failed_workers.append(node)
272
return
273
274
# Report failed workers in summary
275
if self.failed_workers:
276
stream.write('The following workers failed to return coverage data...\n')
277
for node in self.failed_workers:
278
stream.write(f'{node.gateway.id}\n')
279
```
280
281
#### Directory Changes
282
283
```python
284
# Handle cases where working directory disappears
285
try:
286
original_cwd = Path.cwd()
287
except OSError:
288
# Directory gone - can't restore but continue
289
original_cwd = None
290
291
# Robust directory restoration
292
if original_cwd is not None:
293
os.chdir(original_cwd)
294
```
295
296
## User Error Handling
297
298
### Common Error Scenarios
299
300
Handling common user configuration errors:
301
302
```python
303
# Conflicting options detection
304
no_cov = False
305
for arg in args:
306
if arg == '--no-cov':
307
no_cov = True
308
elif arg.startswith('--cov') and no_cov:
309
options.no_cov_should_warn = True
310
break
311
312
# Display warning for conflicting options
313
if self.options.no_cov_should_warn:
314
message = 'Coverage disabled via --no-cov switch!'
315
terminalreporter.write(f'WARNING: {message}\n', red=True, bold=True)
316
warnings.warn(CovDisabledWarning(message), stacklevel=1)
317
```
318
319
### Helpful Error Messages
320
321
Examples of user-friendly error messages:
322
323
```python
324
# Threshold validation with helpful context
325
if value > 100:
326
raise ArgumentTypeError(
327
'Your desire for over-achievement is admirable but misplaced. '
328
'The maximum value is 100. Perhaps write more integration tests?'
329
)
330
331
# Clear compatibility requirements
332
if coverage.version_info <= (5, 0):
333
raise ArgumentTypeError('Contexts are only supported with coverage.py >= 5.x')
334
335
# Specific guidance for complex issues
336
raise DistCovError(
337
'Detected dynamic_context=test_function in coverage configuration. '
338
'This is known to cause issues when using xdist, see: https://github.com/pytest-dev/pytest-cov/issues/604\n'
339
'It is recommended to use --cov-context instead.'
340
)
341
```