0
# Message System
1
2
Structured message definitions with categories, confidence levels, and detailed location information for precise error reporting and filtering. Pylint's message system provides comprehensive information about code issues with standardized formatting and metadata.
3
4
## Capabilities
5
6
### Message Representation
7
8
Core classes for representing individual messages and their metadata.
9
10
```python { .api }
11
class Message:
12
"""
13
Individual message/warning representation.
14
15
Attributes:
16
msg_id (str): Message identifier (e.g., 'C0111')
17
symbol (str): Message symbol (e.g., 'missing-docstring')
18
msg (str): Formatted message text
19
C (str): Message category letter (C/R/W/E/F/I)
20
category (str): Full category name
21
confidence (str): Confidence level
22
abspath (str): Absolute file path
23
path (str): Relative file path
24
module (str): Module name
25
obj (str): Object name (function, class, etc.)
26
line (int): Line number
27
column (int): Column number
28
end_line (int): End line number (optional)
29
end_column (int): End column number (optional)
30
"""
31
32
def __init__(self, msg_id, line=None, node=None, args=None,
33
confidence=None, col_offset=None, end_lineno=None,
34
end_col_offset=None):
35
"""
36
Initialize message instance.
37
38
Args:
39
msg_id (str): Message identifier
40
line (int): Line number
41
node: AST node
42
args (tuple): Message arguments
43
confidence (str): Confidence level
44
col_offset (int): Column offset
45
end_lineno (int): End line number
46
end_col_offset (int): End column offset
47
"""
48
49
def format(self, template=None):
50
"""
51
Format message according to template.
52
53
Args:
54
template (str): Format template
55
56
Returns:
57
str: Formatted message
58
"""
59
```
60
61
### Message Definitions
62
63
Classes for defining and managing message types and their properties.
64
65
```python { .api }
66
class MessageDefinition:
67
"""
68
Message type definition.
69
70
Defines the structure and properties of a specific message type
71
including its identifier, description, and formatting template.
72
"""
73
74
def __init__(self, checker, msgid, msg, description, symbol=None,
75
scope=None, minversion=None, maxversion=None,
76
old_names=None):
77
"""
78
Initialize message definition.
79
80
Args:
81
checker: Checker that defines this message
82
msgid (str): Unique message identifier (e.g., 'C0111')
83
msg (str): Message template with placeholders
84
description (str): Detailed description
85
symbol (str): Symbolic name (e.g., 'missing-docstring')
86
scope (str): Scope where message applies
87
minversion (tuple): Minimum Python version
88
maxversion (tuple): Maximum Python version
89
old_names (list): Previous names for this message
90
"""
91
92
@property
93
def msgid(self):
94
"""Message identifier."""
95
return self._msgid
96
97
@property
98
def symbol(self):
99
"""Message symbol."""
100
return self._symbol
101
102
def format_help(self, checkerref=False):
103
"""
104
Format help text for this message.
105
106
Args:
107
checkerref (bool): Include checker reference
108
109
Returns:
110
str: Formatted help text
111
"""
112
113
class MessageDefinitionStore:
114
"""
115
Storage for message definitions.
116
117
Manages the collection of all message definitions from
118
all checkers, providing lookup and validation capabilities.
119
"""
120
121
def __init__(self):
122
"""Initialize empty message definition store."""
123
self._messages_definitions = {}
124
self._msgs_by_category = {}
125
126
def register_message(self, message_definition):
127
"""
128
Register a message definition.
129
130
Args:
131
message_definition: MessageDefinition instance
132
"""
133
134
def get_message_definitions(self, msgid_or_symbol):
135
"""
136
Get message definition by ID or symbol.
137
138
Args:
139
msgid_or_symbol (str): Message ID or symbol
140
141
Returns:
142
MessageDefinition: Message definition if found
143
"""
144
145
def get_msg_display_string(self, msgid):
146
"""
147
Get display string for message.
148
149
Args:
150
msgid (str): Message identifier
151
152
Returns:
153
str: Display string combining ID and symbol
154
"""
155
```
156
157
### Message ID Management
158
159
Classes for managing message identifiers and symbolic names.
160
161
```python { .api }
162
class MessageIdStore:
163
"""
164
Message ID management and lookup.
165
166
Provides mapping between message IDs, symbols, and their
167
definitions, including support for deprecated message names.
168
"""
169
170
def __init__(self):
171
"""Initialize message ID store."""
172
self._msgid_to_symbol = {}
173
self._symbol_to_msgid = {}
174
self._old_names = {}
175
176
def register_message_definition(self, msgid, symbol, old_names=None):
177
"""
178
Register message ID and symbol mapping.
179
180
Args:
181
msgid (str): Message identifier
182
symbol (str): Message symbol
183
old_names (list): List of deprecated names
184
"""
185
186
def get_active_msgids(self, msgid_or_symbol):
187
"""
188
Get active message IDs for given ID or symbol.
189
190
Args:
191
msgid_or_symbol (str): Message ID or symbol
192
193
Returns:
194
list: Active message IDs
195
"""
196
197
def get_msgid(self, symbol):
198
"""
199
Get message ID from symbol.
200
201
Args:
202
symbol (str): Message symbol
203
204
Returns:
205
str: Message ID
206
"""
207
208
def get_symbol(self, msgid):
209
"""
210
Get symbol from message ID.
211
212
Args:
213
msgid (str): Message ID
214
215
Returns:
216
str: Message symbol
217
"""
218
```
219
220
## Message Categories
221
222
### Category Definitions
223
224
```python { .api }
225
# Message category mappings
226
MSG_TYPES = {
227
'I': 'info', # Informational messages
228
'C': 'convention', # Coding standard violations
229
'R': 'refactor', # Refactoring suggestions
230
'W': 'warning', # Potential issues
231
'E': 'error', # Probable bugs
232
'F': 'fatal' # Errors preventing further processing
233
}
234
235
# Category status codes for exit codes
236
MSG_TYPES_STATUS = {
237
'I': 0, # Info - no impact on exit code
238
'C': 2, # Convention violation
239
'R': 4, # Refactor suggestion
240
'W': 8, # Warning
241
'E': 16, # Error
242
'F': 32 # Fatal error
243
}
244
```
245
246
### Confidence Levels
247
248
```python { .api }
249
# Confidence level constants
250
HIGH = "HIGH" # High confidence in the issue
251
CONTROL_FLOW = "CONTROL_FLOW" # Based on control flow analysis
252
INFERENCE = "INFERENCE" # Based on type inference
253
INFERENCE_FAILURE = "INFERENCE_FAILURE" # Failed type inference
254
UNDEFINED = "UNDEFINED" # No confidence level specified
255
```
256
257
## Usage Examples
258
259
### Creating Custom Messages
260
261
```python
262
from pylint.checkers import BaseChecker
263
from pylint.interfaces import HIGH, INFERENCE
264
265
class CustomChecker(BaseChecker):
266
"""Example checker with custom messages."""
267
268
name = 'custom'
269
msgs = {
270
'W9001': (
271
'Function "%s" has too many parameters (%d > %d)',
272
'too-many-params-custom',
273
'Function should have fewer parameters for better maintainability',
274
),
275
'C9001': (
276
'Variable name "%s" should use snake_case',
277
'invalid-variable-name-custom',
278
'Variable names should follow snake_case convention',
279
),
280
'E9001': (
281
'Undefined variable "%s" used in function "%s"',
282
'undefined-variable-custom',
283
'Variable must be defined before use',
284
)
285
}
286
287
def visit_functiondef(self, node):
288
"""Check function parameters."""
289
max_params = 5
290
param_count = len(node.args.args)
291
292
if param_count > max_params:
293
self.add_message(
294
'too-many-params-custom',
295
node=node,
296
args=(node.name, param_count, max_params),
297
confidence=HIGH
298
)
299
300
def visit_name(self, node):
301
"""Check variable naming."""
302
import re
303
if not re.match(r'^[a-z_][a-z0-9_]*$', node.name):
304
self.add_message(
305
'invalid-variable-name-custom',
306
node=node,
307
args=(node.name,),
308
confidence=INFERENCE
309
)
310
```
311
312
### Message Processing and Filtering
313
314
```python
315
from pylint.lint import PyLinter
316
from pylint.reporters import CollectingReporter
317
318
# Collect messages for processing
319
collector = CollectingReporter()
320
linter = PyLinter()
321
linter.set_reporter(collector)
322
linter.check(['mymodule.py'])
323
324
messages = collector.finalize()
325
326
# Filter messages by category
327
errors = [msg for msg in messages if msg.category == 'error']
328
warnings = [msg for msg in messages if msg.category == 'warning']
329
330
# Filter by confidence level
331
high_confidence = [msg for msg in messages if msg.confidence == 'HIGH']
332
333
# Filter by message type
334
missing_docstrings = [msg for msg in messages
335
if msg.symbol == 'missing-docstring']
336
337
# Group messages by file
338
from collections import defaultdict
339
by_file = defaultdict(list)
340
for msg in messages:
341
by_file[msg.path].append(msg)
342
343
# Process each message
344
for msg in messages:
345
print(f"{msg.path}:{msg.line}:{msg.column} - {msg.msg_id}: {msg.msg}")
346
print(f" Category: {msg.category}")
347
print(f" Confidence: {msg.confidence}")
348
print(f" Symbol: {msg.symbol}")
349
```
350
351
### Custom Message Formatting
352
353
```python
354
def format_message_custom(msg):
355
"""Custom message formatting function."""
356
severity_map = {
357
'error': '❌',
358
'warning': '⚠️ ',
359
'convention': '📋',
360
'refactor': '♻️ ',
361
'info': 'ℹ️ '
362
}
363
364
icon = severity_map.get(msg.category, '?')
365
return f"{icon} {msg.path}:{msg.line} - {msg.msg} ({msg.symbol})"
366
367
# Apply custom formatting
368
for msg in messages:
369
formatted = format_message_custom(msg)
370
print(formatted)
371
```
372
373
### Message Template Configuration
374
375
```python
376
# Configure message template
377
linter = PyLinter()
378
379
# Standard templates
380
linter.config.msg_template = '{path}:{line}: [{msg_id}({symbol}), {obj}] {msg}'
381
linter.config.msg_template = '{path}:{line}:{column}: {category}: {msg} ({symbol})'
382
383
# Custom template with all fields
384
template = (
385
'{path}:{line}:{column}: {msg_id}: {msg}\n'
386
' Category: {category} | Confidence: {confidence}\n'
387
' Object: {obj} | Symbol: {symbol}'
388
)
389
linter.config.msg_template = template
390
```
391
392
## Built-in Message Examples
393
394
### Convention Messages (C)
395
396
```python { .api }
397
# C0103: invalid-name
398
# "Name doesn't conform to naming convention"
399
400
# C0111: missing-docstring
401
# "Missing module/class/function docstring"
402
403
# C0301: line-too-long
404
# "Line too long (%d/%d characters)"
405
406
# C0326: bad-whitespace
407
# "Wrong hanging indentation"
408
```
409
410
### Refactor Messages (R)
411
412
```python { .api }
413
# R0201: no-self-use
414
# "Method could be a function"
415
416
# R0903: too-few-public-methods
417
# "Too few public methods (%d/%d)"
418
419
# R0913: too-many-arguments
420
# "Too many arguments (%d/%d)"
421
422
# R1705: no-else-return
423
# "Unnecessary else after return statement"
424
```
425
426
### Warning Messages (W)
427
428
```python { .api }
429
# W0613: unused-argument
430
# "Unused argument '%s'"
431
432
# W0622: redefined-builtin
433
# "Redefining built-in '%s'"
434
435
# W0703: broad-except
436
# "Catching too general exception %s"
437
438
# W1203: logging-fstring-interpolation
439
# "Use lazy % formatting in logging functions"
440
```
441
442
### Error Messages (E)
443
444
```python { .api }
445
# E0601: used-before-assignment
446
# "Using variable '%s' before assignment"
447
448
# E1101: no-member
449
# "%s %r has no %r member"
450
451
# E1120: no-value-for-parameter
452
# "No value provided for parameter %s in function call"
453
454
# E1136: unsubscriptable-object
455
# "Value '%s' is unsubscriptable"
456
```
457
458
### Fatal Messages (F)
459
460
```python { .api }
461
# F0001: fatal
462
# "Error occurred preventing further processing: %s"
463
464
# F0010: error
465
# "Error while code parsing: %s"
466
467
# F0202: method-check-failed
468
# "Unable to check methods signature (%s / %s)"
469
```
470
471
## Message State Management
472
473
### Disabling Messages
474
475
```python
476
# Disable globally in configuration
477
linter.config.disable = ['missing-docstring', 'invalid-name']
478
479
# Disable via command line
480
# pylint --disable=missing-docstring,invalid-name mymodule.py
481
482
# Disable in code with comments
483
def my_function(): # pylint: disable=missing-docstring
484
pass
485
486
class MyClass: # pylint: disable=too-few-public-methods
487
pass
488
489
# Disable for entire file
490
# pylint: disable=missing-docstring
491
492
# Disable for code block
493
# pylint: disable-next=unused-variable
494
x = get_value()
495
```
496
497
### Enabling Messages
498
499
```python
500
# Enable specific messages
501
linter.config.enable = ['unused-variable']
502
503
# Enable message categories
504
linter.config.enable = ['warning', 'error']
505
506
# Enable all messages then disable specific ones
507
linter.config.disable = 'all'
508
linter.config.enable = ['error', 'fatal']
509
```