0
# Warning System
1
2
Configurable warning and error reporting system with different verbosity levels and output control for handling dependency conflicts, validation issues, and other diagnostic information.
3
4
## Capabilities
5
6
### Warning Types
7
8
Enumeration defining different warning behavior levels.
9
10
```python { .api }
11
WarningType = Enum("WarningType", ["SILENCE", "SUPPRESS", "FAIL"])
12
```
13
14
The three warning levels control output and exit behavior:
15
16
- **SILENCE**: No warning output, always return exit code 0
17
- **SUPPRESS**: Print warnings to stderr, but return exit code 0
18
- **FAIL**: Print warnings to stderr and return exit code 1 if any warnings occurred
19
20
### WarningPrinter Class
21
22
Main class for managing warning output and tracking warning state.
23
24
```python { .api }
25
class WarningPrinter:
26
"""Non-thread safe class that handles printing warning logic."""
27
28
def __init__(self, warning_type: WarningType = WarningType.SUPPRESS) -> None:
29
"""
30
Initialize warning printer with specified behavior.
31
32
Parameters:
33
- warning_type: Controls warning output and exit code behavior
34
"""
35
36
@property
37
def warning_type(self) -> WarningType:
38
"""Current warning type setting."""
39
40
@warning_type.setter
41
def warning_type(self, new_warning_type: WarningType) -> None:
42
"""Update warning type setting."""
43
44
def should_warn(self) -> bool:
45
"""
46
Check if warnings should be printed.
47
48
Returns:
49
False for SILENCE, True for SUPPRESS and FAIL
50
"""
51
52
def has_warned_with_failure(self) -> bool:
53
"""
54
Check if warnings were printed with failure setting.
55
56
Returns:
57
True if warnings occurred and warning_type is FAIL
58
"""
59
60
def print_single_line(self, line: str) -> None:
61
"""
62
Print a single warning line to stderr.
63
64
Marks that a warning has occurred for exit code determination.
65
66
Parameters:
67
- line: Warning message to print
68
"""
69
70
def print_multi_line(
71
self,
72
summary: str,
73
print_func: Callable[[], None],
74
ignore_fail: bool = False
75
) -> None:
76
"""
77
Print a multi-line warning with custom formatting.
78
79
Parameters:
80
- summary: Warning summary/title
81
- print_func: Callback that prints the detailed warning content
82
- ignore_fail: If True, don't mark as failure warning
83
"""
84
```
85
86
### Global Warning Printer
87
88
Function to access the global warning printer instance.
89
90
```python { .api }
91
def get_warning_printer() -> WarningPrinter:
92
"""
93
Get the global warning printer instance.
94
95
Returns:
96
Shared WarningPrinter instance used throughout pipdeptree
97
"""
98
```
99
100
## Usage Examples
101
102
### Basic Warning Configuration
103
104
```python
105
from pipdeptree._warning import get_warning_printer, WarningType
106
107
# Get global warning printer
108
warning_printer = get_warning_printer()
109
110
# Configure warning behavior
111
warning_printer.warning_type = WarningType.FAIL
112
113
# Check configuration
114
if warning_printer.should_warn():
115
print("Warnings will be printed")
116
117
if warning_printer.warning_type == WarningType.FAIL:
118
print("Warnings will cause exit code 1")
119
```
120
121
### Single Line Warnings
122
123
```python
124
from pipdeptree._warning import get_warning_printer
125
126
warning_printer = get_warning_printer()
127
128
# Print simple warning
129
warning_printer.print_single_line("Package version conflict detected")
130
131
# Check if this was a failure warning
132
if warning_printer.has_warned_with_failure():
133
print("This warning should cause non-zero exit code")
134
```
135
136
### Multi-Line Warning Output
137
138
```python
139
from pipdeptree._warning import get_warning_printer
140
141
def print_detailed_conflicts():
142
"""Function that prints detailed conflict information."""
143
print("* package-a==1.0")
144
print(" - dependency-x [required: >=2.0, installed: 1.5]")
145
print("* package-b==2.0")
146
print(" - dependency-y [required: <1.0, installed: 1.2]")
147
148
warning_printer = get_warning_printer()
149
150
# Print multi-line warning with custom content
151
warning_printer.print_multi_line(
152
summary="Conflicting dependencies found",
153
print_func=print_detailed_conflicts
154
)
155
156
# Output:
157
# Warning!!! Conflicting dependencies found:
158
# * package-a==1.0
159
# - dependency-x [required: >=2.0, installed: 1.5]
160
# * package-b==2.0
161
# - dependency-y [required: <1.0, installed: 1.2]
162
# ------------------------------------------------------------------------
163
```
164
165
### Integration with CLI
166
167
```python
168
from pipdeptree._cli import get_options
169
from pipdeptree._warning import get_warning_printer, WarningType
170
171
# Parse CLI warning option
172
options = get_options(['--warn', 'fail'])
173
174
# Configure warning printer based on CLI option
175
warning_printer = get_warning_printer()
176
warning_printer.warning_type = options.warn
177
178
# Use throughout application
179
if warning_printer.should_warn():
180
warning_printer.print_single_line("Validation issue detected")
181
182
# Determine exit code
183
exit_code = 1 if warning_printer.has_warned_with_failure() else 0
184
```
185
186
### Integration with Validation
187
188
```python
189
from pipdeptree._validate import validate, conflicting_deps
190
from pipdeptree._warning import get_warning_printer
191
192
# Configure warnings
193
warning_printer = get_warning_printer()
194
warning_printer.warning_type = WarningType.SUPPRESS
195
196
# Validation uses warning printer internally
197
validate(dependency_tree) # Prints warnings if conflicts found
198
199
# Check if validation found issues
200
if warning_printer.has_warned_with_failure():
201
print("Validation failed")
202
203
# Manual conflict checking with warning integration
204
conflicts = conflicting_deps(dependency_tree)
205
if conflicts and warning_printer.should_warn():
206
warning_printer.print_multi_line(
207
"Dependency conflicts detected",
208
lambda: render_conflicts_text(conflicts)
209
)
210
```
211
212
## Warning Output Format
213
214
### Single Line Format
215
216
Simple warning messages printed directly to stderr:
217
218
```
219
Package pattern 'nonexistent*' not found in dependency tree
220
```
221
222
### Multi-Line Format
223
224
Structured warnings with header, content, and footer:
225
226
```
227
Warning!!! Conflicting dependencies found:
228
* Django==3.0.0
229
- requests [required: >=2.25.0, installed: 2.20.0]
230
* mypackage==1.0.0
231
- urllib3 [required: >=1.26, installed: 1.25.11]
232
------------------------------------------------------------------------
233
```
234
235
### Informational Messages
236
237
Some multi-line warnings can be marked as informational:
238
239
```
240
Warning!!! Invalid requirement strings found:
241
mypackage
242
Skipping "invalid>=requirement string"
243
NOTE: This warning isn't a failure warning.
244
------------------------------------------------------------------------
245
```
246
247
## Integration Points
248
249
### CLI Warning Control
250
251
The warning system integrates with CLI argument parsing:
252
253
```bash
254
# Suppress warnings but show them
255
pipdeptree --warn suppress
256
257
# Silence all warnings
258
pipdeptree --warn silence
259
260
# Treat warnings as failures
261
pipdeptree --warn fail
262
```
263
264
### Validation Integration
265
266
Validation functions automatically use the warning system:
267
268
- **Conflict detection**: Prints conflicts when `should_warn()` returns True
269
- **Cycle detection**: Prints circular dependencies when enabled
270
- **Invalid requirements**: Reports malformed requirement strings
271
272
### Text Output Integration
273
274
The warning system only activates for text output modes:
275
276
```python
277
# Warnings disabled for structured output formats
278
is_text_output = not any([options.json, options.json_tree, options.output_format])
279
if not is_text_output:
280
options.warn = WarningType.SILENCE
281
```
282
283
### Exit Code Determination
284
285
The warning system controls application exit codes:
286
287
```python
288
def _determine_return_code(warning_printer: WarningPrinter) -> int:
289
"""Determine exit code based on warning state."""
290
return 1 if warning_printer.has_warned_with_failure() else 0
291
```
292
293
## Thread Safety
294
295
The `WarningPrinter` class is explicitly **not thread-safe**:
296
297
- Maintains internal state (`_has_warned` flag)
298
- Not designed for concurrent access
299
- Global instance should be accessed from single thread
300
301
For multi-threaded applications, create separate `WarningPrinter` instances per thread or implement external synchronization.
302
303
## State Management
304
305
The warning printer tracks warning state internally:
306
307
- **Initial state**: `_has_warned = False`
308
- **After warning**: `_has_warned = True` (for failure warnings)
309
- **Reset**: No built-in reset mechanism (create new instance if needed)
310
311
This state tracking enables proper exit code determination and failure detection throughout the application lifecycle.