0
# Violation System
1
2
Comprehensive violation reporting system with specific error codes (DOC0xx-DOC6xx) covering all categories of docstring issues, from formatting to argument mismatches.
3
4
## Capabilities
5
6
### Violation Class
7
8
Core class representing individual docstring violations with detailed error information.
9
10
```python { .api }
11
class Violation:
12
"""
13
Represents a docstring violation with detailed error information.
14
15
Provides comprehensive violation reporting including error codes,
16
line numbers, and formatted messages for both CLI and flake8 output.
17
"""
18
19
code: int # Violation code number (1-6xx range)
20
line: int # Line number where violation occurs
21
msg: str # Complete violation message
22
msgPostfix: str # Additional message content
23
24
def __init__(
25
self,
26
line: int,
27
code: int,
28
msgPrefix: str = '',
29
msgPostfix: str = '',
30
) -> None:
31
"""
32
Initialize violation with error details.
33
34
Parameters:
35
- line: Line number of violation (0 for file-level issues)
36
- code: Violation code number
37
- msgPrefix: Prefix for violation message (deprecated)
38
- msgPostfix: Additional information to append to standard message
39
"""
40
41
@property
42
def fullErrorCode(self) -> str:
43
"""
44
Get full error code with DOC prefix.
45
46
Returns:
47
str: Full error code (e.g., "DOC101", "DOC201")
48
"""
49
50
def getInfoForFlake8(self) -> tuple[int, int, str]:
51
"""
52
Format violation information for flake8 output.
53
54
Returns:
55
tuple containing:
56
- int: Line number
57
- int: Column offset (always 0)
58
- str: Formatted error message with DOC code
59
"""
60
61
def __str__(self) -> str:
62
"""
63
String representation of violation.
64
65
Returns:
66
str: Formatted violation message
67
"""
68
```
69
70
### Violation Codes Reference
71
72
Complete mapping of violation codes to their standard error messages.
73
74
```python { .api }
75
VIOLATION_CODES: dict[int, str] = {
76
# General and formatting issues (DOC0xx)
77
1: "Potential formatting errors in docstring. Error message:",
78
2: "Syntax errors; cannot parse this Python file. Error message:",
79
3: "Docstring style mismatch. (Please read more at https://jsh9.github.io/pydoclint/style_mismatch.html ).",
80
81
# Argument-related violations (DOC1xx)
82
101: "Docstring contains fewer arguments than in function signature.",
83
102: "Docstring contains more arguments than in function signature.",
84
103: "Docstring arguments are different from function arguments. (Or could be other formatting issues: https://jsh9.github.io/pydoclint/violation_codes.html#notes-on-doc103 ).",
85
104: "Arguments are the same in the docstring and the function signature, but are in a different order.",
86
105: "Argument names match, but type hints in these args do not match:",
87
106: "The option `--arg-type-hints-in-signature` is `True` but there are no argument type hints in the signature",
88
107: "The option `--arg-type-hints-in-signature` is `True` but not all args in the signature have type hints",
89
108: "The option `--arg-type-hints-in-signature` is `False` but there are argument type hints in the signature",
90
109: "The option `--arg-type-hints-in-docstring` is `True` but there are no type hints in the docstring arg list",
91
110: "The option `--arg-type-hints-in-docstring` is `True` but not all args in the docstring arg list have type hints",
92
111: "The option `--arg-type-hints-in-docstring` is `False` but there are type hints in the docstring arg list",
93
94
# Return-related violations (DOC2xx)
95
201: "does not have a return section in docstring",
96
202: "has a return section in docstring, but there are no return statements or annotations",
97
203: "return type(s) in docstring not consistent with the return annotation.",
98
99
# Class and __init__ violations (DOC3xx)
100
301: "__init__() should not have a docstring; please combine it with the docstring of the class",
101
302: "The class docstring does not need a \"Returns\" section, because __init__() cannot return anything",
102
303: "The __init__() docstring does not need a \"Returns\" section, because it cannot return anything",
103
304: "Class docstring has an argument/parameter section; please put it in the __init__() docstring",
104
305: "Class docstring has a \"Raises\" section; please put it in the __init__() docstring",
105
306: "The class docstring does not need a \"Yields\" section, because __init__() cannot yield anything",
106
307: "The __init__() docstring does not need a \"Yields\" section, because __init__() cannot yield anything",
107
108
# Yield-related violations (DOC4xx)
109
402: "has \"yield\" statements, but the docstring does not have a \"Yields\" section",
110
403: "has a \"Yields\" section in the docstring, but there are no \"yield\" statements, or the return annotation is not a Generator/Iterator/Iterable. (Or it could be because the function lacks a return annotation.)",
111
404: "yield type(s) in docstring not consistent with the return annotation.",
112
405: "has both \"return\" and \"yield\" statements. Please use Generator[YieldType, SendType, ReturnType] as the return type annotation, and put your yield type in YieldType and return type in ReturnType. More details in https://jsh9.github.io/pydoclint/notes_generator_vs_iterator.html",
113
114
# Raises-related violations (DOC5xx)
115
501: "has raise statements, but the docstring does not have a \"Raises\" section",
116
502: "has a \"Raises\" section in the docstring, but there are not \"raise\" statements in the body",
117
503: "exceptions in the \"Raises\" section in the docstring do not match those in the function body.",
118
504: "has assert statements, but the docstring does not have a \"Raises\" section. (Assert statements could raise \"AssertError\".)",
119
120
# Class attribute violations (DOC6xx)
121
601: "Class docstring contains fewer class attributes than actual class attributes.",
122
602: "Class docstring contains more class attributes than in actual class attributes.",
123
603: "Class docstring attributes are different from actual class attributes. (Or could be other formatting issues: https://jsh9.github.io/pydoclint/violation_codes.html#notes-on-doc103 ).",
124
604: "Attributes are the same in docstring and class def, but are in a different order",
125
605: "Attribute names match, but type hints in these attributes do not match",
126
}
127
```
128
129
## Usage Examples
130
131
### Creating and Using Violations
132
133
```python
134
from pydoclint.utils.violation import Violation, VIOLATION_CODES
135
136
# Create a violation for missing arguments
137
violation = Violation(
138
code=101,
139
line=15,
140
msgPostfix="Missing arguments: x, y"
141
)
142
143
print(violation.fullErrorCode) # "DOC101"
144
print(str(violation)) # Full formatted message
145
print(violation.getInfoForFlake8()) # (15, 0, "DOC101: Docstring contains fewer arguments...")
146
147
# Check violation code meaning
148
print(VIOLATION_CODES[101]) # "Docstring contains fewer arguments than in function signature."
149
```
150
151
### Processing Violations from Analysis
152
153
```python
154
from pydoclint.main import _checkFile
155
from pathlib import Path
156
157
# Analyze file and process violations
158
violations = _checkFile(Path("example.py"), style="numpy")
159
160
for violation in violations:
161
print(f"Line {violation.line}: {violation.fullErrorCode}")
162
print(f" {violation.msg}")
163
164
# Handle specific violation types
165
if violation.code in [101, 102, 103]:
166
print(" -> Argument mismatch issue")
167
elif violation.code in [201, 202, 203]:
168
print(" -> Return section issue")
169
elif violation.code in [402, 403, 404]:
170
print(" -> Yield section issue")
171
```
172
173
### Filtering and Categorizing Violations
174
175
```python
176
def categorize_violations(violations: list[Violation]) -> dict[str, list[Violation]]:
177
"""Categorize violations by type."""
178
categories = {
179
"general": [], # DOC001-DOC003
180
"arguments": [], # DOC101-DOC111
181
"returns": [], # DOC201-DOC203
182
"class_init": [], # DOC301-DOC307
183
"yields": [], # DOC402-DOC405
184
"raises": [], # DOC501-DOC502
185
"class_attrs": [], # DOC601-DOC603
186
}
187
188
for violation in violations:
189
if 1 <= violation.code <= 3:
190
categories["general"].append(violation)
191
elif 101 <= violation.code <= 111:
192
categories["arguments"].append(violation)
193
elif 201 <= violation.code <= 203:
194
categories["returns"].append(violation)
195
elif 301 <= violation.code <= 307:
196
categories["class_init"].append(violation)
197
elif 402 <= violation.code <= 405:
198
categories["yields"].append(violation)
199
elif 501 <= violation.code <= 502:
200
categories["raises"].append(violation)
201
elif 601 <= violation.code <= 603:
202
categories["class_attrs"].append(violation)
203
204
return categories
205
206
# Usage
207
violations = _checkFile(Path("example.py"))
208
categorized = categorize_violations(violations)
209
210
print(f"Argument issues: {len(categorized['arguments'])}")
211
print(f"Return issues: {len(categorized['returns'])}")
212
```
213
214
### Custom Violation Processing
215
216
```python
217
class ViolationProcessor:
218
"""Process and format violations for different outputs."""
219
220
def __init__(self, show_filenames: bool = False):
221
self.show_filenames = show_filenames
222
223
def format_for_console(self, filename: str, violations: list[Violation]) -> str:
224
"""Format violations for console output."""
225
if not violations:
226
return ""
227
228
output = []
229
if not self.show_filenames:
230
output.append(f"{filename}:")
231
232
for violation in violations:
233
prefix = f"{filename}:" if self.show_filenames else " "
234
output.append(f"{prefix}{violation.line}: {violation.fullErrorCode}: {violation.msg}")
235
236
return "\n".join(output)
237
238
def format_for_json(self, filename: str, violations: list[Violation]) -> dict:
239
"""Format violations for JSON output."""
240
return {
241
"file": filename,
242
"violations": [
243
{
244
"line": v.line,
245
"code": v.fullErrorCode,
246
"message": v.msg,
247
"severity": self._get_severity(v.code)
248
}
249
for v in violations
250
]
251
}
252
253
def _get_severity(self, code: int) -> str:
254
"""Determine violation severity."""
255
if code in [1, 2]:
256
return "error"
257
elif code in [101, 102, 201, 402, 501]:
258
return "warning"
259
else:
260
return "info"
261
262
# Usage
263
processor = ViolationProcessor(show_filenames=True)
264
violations = _checkFile(Path("example.py"))
265
266
# Console output
267
console_output = processor.format_for_console("example.py", violations)
268
print(console_output)
269
270
# JSON output
271
json_output = processor.format_for_json("example.py", violations)
272
import json
273
print(json.dumps(json_output, indent=2))
274
```
275
276
## Violation Code Categories
277
278
### General Issues (DOC001-DOC003)
279
- **DOC001**: Docstring parsing/formatting errors
280
- **DOC002**: Python syntax errors preventing analysis
281
- **DOC003**: Docstring style mismatch (e.g., Google style in numpy-configured project)
282
283
### Argument Issues (DOC101-DOC111)
284
- **DOC101-DOC104**: Argument count and order mismatches
285
- **DOC105**: Type hint inconsistencies
286
- **DOC106-DOC111**: Type hint presence/absence violations
287
288
### Return Issues (DOC201-DOC203)
289
- **DOC201**: Missing return section
290
- **DOC202**: Unnecessary return section
291
- **DOC203**: Return type inconsistencies
292
293
### Class and Init Issues (DOC301-DOC307)
294
- **DOC301**: Improper __init__ docstring placement
295
- **DOC302-DOC303**: Inappropriate return sections in class/__init__
296
- **DOC304-DOC305**: Misplaced argument/raises sections
297
- **DOC306-DOC307**: Inappropriate yields sections
298
299
### Yield Issues (DOC402-DOC405)
300
- **DOC402**: Missing yields section for generators
301
- **DOC403**: Unnecessary yields section
302
- **DOC404**: Yield type inconsistencies
303
- **DOC405**: Mixed return/yield usage
304
305
### Raises Issues (DOC501-DOC502)
306
- **DOC501**: Missing raises section
307
- **DOC502**: Unnecessary raises section
308
309
### Class Attribute Issues (DOC601-DOC603)
310
- **DOC601-DOC603**: Class attribute documentation mismatches