0
# Error Handling and Analysis
1
2
Comprehensive error detection, syntax error reporting, and code quality analysis including PEP 8 normalization and custom rule systems for Python code analysis.
3
4
## Capabilities
5
6
### Exception Classes
7
8
Core exception types for parser and syntax errors.
9
10
```python { .api }
11
class ParserSyntaxError(Exception):
12
"""
13
Exception raised when parsing fails.
14
15
Attributes:
16
message (str): Error description
17
error_leaf (ErrorLeaf): Token where error occurred
18
"""
19
20
def __init__(self, message, error_leaf):
21
"""
22
Initialize syntax error.
23
24
Args:
25
message (str): Error message
26
error_leaf (ErrorLeaf): Problematic token
27
"""
28
29
class InternalParseError(Exception):
30
"""
31
Internal parser error indicating parser failure.
32
33
Attributes:
34
msg (str): Error description
35
type: Token type where error occurred
36
value (str): Token value
37
start_pos (tuple[int, int]): Error position
38
"""
39
```
40
41
### Error Detection
42
43
Advanced error finder for syntax and semantic analysis.
44
45
```python { .api }
46
class ErrorFinder:
47
"""
48
Finds and reports syntax and semantic errors in Python code.
49
"""
50
51
def find_errors(self, node):
52
"""
53
Find all errors in a syntax tree.
54
55
Args:
56
node (NodeOrLeaf): Root node to analyze
57
58
Returns:
59
list[Issue]: List of error issues found
60
"""
61
62
class ErrorFinderConfig:
63
"""
64
Configuration for error detection behavior.
65
"""
66
67
def create_normalizer(self, grammar):
68
"""
69
Create error finder normalizer.
70
71
Args:
72
grammar (Grammar): Grammar instance
73
74
Returns:
75
ErrorFinder: Configured error finder
76
"""
77
```
78
79
### Normalization System
80
81
Code normalization and transformation system with rule-based architecture.
82
83
```python { .api }
84
class Normalizer:
85
"""
86
Base class for code normalization and analysis.
87
88
Attributes:
89
issues (list[Issue]): Found issues during normalization
90
"""
91
92
def __init__(self, grammar, config):
93
"""
94
Initialize normalizer.
95
96
Args:
97
grammar (Grammar): Grammar instance
98
config (NormalizerConfig): Configuration
99
"""
100
101
def walk(self, node):
102
"""
103
Walk syntax tree and apply normalization.
104
105
Args:
106
node (NodeOrLeaf): Root node to process
107
108
Returns:
109
str: Normalized code
110
"""
111
112
def add_issue(self, node, code, message):
113
"""
114
Add an issue to the issue list.
115
116
Args:
117
node (NodeOrLeaf): Node where issue occurred
118
code (str): Issue code identifier
119
message (str): Issue description
120
121
Returns:
122
bool: True if issue was added
123
"""
124
125
class NormalizerConfig:
126
"""Base configuration for normalizers."""
127
128
def create_normalizer(self, grammar):
129
"""Create configured normalizer instance."""
130
131
class RefactoringNormalizer(Normalizer):
132
"""
133
Normalizer for code refactoring transformations.
134
"""
135
136
def __init__(self, node_to_str_map):
137
"""
138
Initialize refactoring normalizer.
139
140
Args:
141
node_to_str_map (dict): Mapping from nodes to replacement strings
142
"""
143
144
class Issue:
145
"""
146
Represents a code issue or error.
147
148
Attributes:
149
node (NodeOrLeaf): Node where issue occurs
150
code (str): Issue code
151
message (str): Issue description
152
start_pos (tuple[int, int]): Issue position
153
"""
154
```
155
156
#### Usage Examples
157
158
```python
159
import parso
160
161
# Parse code with errors
162
code = '''
163
def function(: # Missing parameter name
164
x = 1 + # Incomplete expression
165
return x
166
167
continue # Continue outside loop
168
class MissingColon # Missing colon
169
pass
170
'''
171
172
grammar = parso.load_grammar()
173
module = grammar.parse(code)
174
175
# Find syntax and semantic errors
176
errors = list(grammar.iter_errors(module))
177
print(f"Found {len(errors)} errors:")
178
179
for error in errors:
180
print(f" Line {error.start_pos[0]}: {error.message}")
181
print(f" Code: {error.code}")
182
print(f" Position: {error.start_pos}")
183
184
# Handle parser exceptions in strict mode
185
try:
186
strict_module = grammar.parse(code, error_recovery=False)
187
except parso.ParserSyntaxError as e:
188
print(f"Parse failed: {e.message}")
189
print(f"Error at: {e.error_leaf.start_pos}")
190
print(f"Error token: '{e.error_leaf.value}'")
191
```
192
193
### PEP 8 Normalization
194
195
Python PEP 8 style guide enforcement and formatting.
196
197
```python { .api }
198
class PEP8Normalizer(Normalizer):
199
"""
200
PEP 8 style guide normalizer.
201
"""
202
203
def normalize(self, code):
204
"""
205
Apply PEP 8 formatting to code.
206
207
Args:
208
code (str): Input Python code
209
210
Returns:
211
str: PEP 8 formatted code
212
"""
213
214
class PEP8NormalizerConfig(NormalizerConfig):
215
"""
216
Configuration for PEP 8 normalization.
217
"""
218
```
219
220
#### Usage Examples
221
222
```python
223
import parso
224
from parso.python import pep8
225
226
# Code with PEP 8 violations
227
messy_code = '''
228
def bad_spacing(x,y):
229
return x+y
230
231
class BadClass:
232
def method(self):
233
pass
234
'''
235
236
grammar = parso.load_grammar()
237
module = grammar.parse(messy_code)
238
239
# Get PEP 8 normalizer
240
config = pep8.PEP8NormalizerConfig()
241
normalizer = config.create_normalizer(grammar)
242
243
# Apply normalization
244
normalized_code = normalizer.walk(module)
245
print("Normalized code:")
246
print(normalized_code)
247
248
# Check for PEP 8 issues
249
pep8_issues = normalizer.issues
250
print(f"Found {len(pep8_issues)} PEP 8 issues:")
251
for issue in pep8_issues:
252
print(f" {issue.code}: {issue.message} at {issue.start_pos}")
253
```
254
255
### Custom Rule System
256
257
Creating custom rules for code analysis and transformation.
258
259
```python { .api }
260
class Rule:
261
"""
262
Base class for normalization rules.
263
264
Attributes:
265
error_code (int): Rule error code
266
"""
267
268
def __init__(self, normalizer):
269
"""
270
Initialize rule.
271
272
Args:
273
normalizer (Normalizer): Parent normalizer
274
"""
275
276
def feed_node(self, node):
277
"""
278
Process a node with this rule.
279
280
Args:
281
node (NodeOrLeaf): Node to process
282
"""
283
284
@Normalizer.register_rule(type='funcdef')
285
class CustomFunctionRule(Rule):
286
"""Example custom rule for function analysis."""
287
error_code = 1001
288
289
def feed_node(self, node):
290
# Custom logic for function nodes
291
if len(node.name.value) < 3:
292
self.normalizer.add_issue(
293
node,
294
f"C{self.error_code}",
295
"Function name should be at least 3 characters"
296
)
297
```
298
299
## Advanced Error Analysis
300
301
### Error Categorization
302
303
```python
304
def categorize_errors(errors):
305
"""Categorize errors by type."""
306
categories = {
307
'syntax': [],
308
'indentation': [],
309
'semantic': [],
310
'other': []
311
}
312
313
for error in errors:
314
message = error.message.lower()
315
if 'syntax' in message:
316
categories['syntax'].append(error)
317
elif 'indent' in message:
318
categories['indentation'].append(error)
319
elif any(word in message for word in ['continue', 'break', 'return', 'yield']):
320
categories['semantic'].append(error)
321
else:
322
categories['other'].append(error)
323
324
return categories
325
326
# Usage
327
grammar = parso.load_grammar()
328
module = grammar.parse('''
329
def func():
330
pass # Wrong indentation
331
continue # Continue not in loop
332
def invalid(: pass # Syntax error
333
''')
334
335
errors = list(grammar.iter_errors(module))
336
categorized = categorize_errors(errors)
337
338
for category, error_list in categorized.items():
339
if error_list:
340
print(f"{category.title()} errors ({len(error_list)}):")
341
for error in error_list:
342
print(f" Line {error.start_pos[0]}: {error.message}")
343
```
344
345
### Error Recovery Analysis
346
347
```python
348
def analyze_error_recovery(code):
349
"""Analyze how well error recovery handles broken code."""
350
grammar = parso.load_grammar()
351
352
# Parse with error recovery
353
module = grammar.parse(code, error_recovery=True)
354
errors = list(grammar.iter_errors(module))
355
356
# Count different node types
357
def count_nodes(node, counts=None):
358
if counts is None:
359
counts = {'total': 0, 'error_nodes': 0, 'error_leaves': 0}
360
361
counts['total'] += 1
362
if hasattr(node, 'type'):
363
if node.type == 'error_node':
364
counts['error_nodes'] += 1
365
elif node.type == 'error_leaf':
366
counts['error_leaves'] += 1
367
368
if hasattr(node, 'children'):
369
for child in node.children:
370
count_nodes(child, counts)
371
372
return counts
373
374
node_counts = count_nodes(module)
375
376
return {
377
'errors_found': len(errors),
378
'error_nodes': node_counts['error_nodes'],
379
'error_leaves': node_counts['error_leaves'],
380
'total_nodes': node_counts['total'],
381
'recovery_success': len(errors) > 0 and node_counts['total'] > 0
382
}
383
384
# Test error recovery
385
broken_code = '''
386
def func1():
387
pass
388
389
def broken_func(missing_param:
390
x = incomplete +
391
return x
392
393
def func2():
394
return "ok"
395
'''
396
397
analysis = analyze_error_recovery(broken_code)
398
print("Error recovery analysis:", analysis)
399
```
400
401
### Validation Utilities
402
403
```python
404
def validate_python_syntax(code, version="3.9"):
405
"""Validate Python code syntax."""
406
try:
407
grammar = parso.load_grammar(version=version)
408
grammar.parse(code, error_recovery=False)
409
return True, "Valid syntax"
410
except parso.ParserSyntaxError as e:
411
return False, f"Syntax error: {e.message} at {e.error_leaf.start_pos}"
412
except Exception as e:
413
return False, f"Parse error: {str(e)}"
414
415
def check_code_quality(code, version="3.9"):
416
"""Comprehensive code quality check."""
417
grammar = parso.load_grammar(version=version)
418
module = grammar.parse(code)
419
errors = list(grammar.iter_errors(module))
420
421
# Get PEP 8 issues
422
from parso.python import pep8
423
config = pep8.PEP8NormalizerConfig()
424
normalizer = config.create_normalizer(grammar)
425
normalizer.walk(module)
426
pep8_issues = normalizer.issues
427
428
return {
429
'syntax_valid': len(errors) == 0,
430
'syntax_errors': errors,
431
'pep8_issues': pep8_issues,
432
'total_issues': len(errors) + len(pep8_issues)
433
}
434
435
# Usage
436
code_quality = check_code_quality('''
437
def example():
438
x=1+2 # PEP 8: spaces around operators
439
return x
440
''')
441
442
print(f"Syntax valid: {code_quality['syntax_valid']}")
443
print(f"Total issues: {code_quality['total_issues']}")
444
```