0
# Exception Handling
1
2
Exception classes for parsing errors with detailed location information and error recovery mechanisms. PyParsing provides a comprehensive exception hierarchy that helps developers identify and handle parsing failures with precise error reporting.
3
4
## Capabilities
5
6
### Base Exception Classes
7
8
Foundation exception classes that provide common functionality for all parsing errors.
9
10
```python { .api }
11
class ParseBaseException(Exception):
12
"""Base class for all pyparsing exceptions."""
13
14
def __init__(self,
15
pstr: str,
16
loc: int = 0,
17
msg: str = None,
18
elem: ParserElement = None): ...
19
20
@property
21
def line(self) -> str:
22
"""Get the line of text where the exception occurred."""
23
24
@property
25
def lineno(self) -> int:
26
"""Get the line number where the exception occurred."""
27
28
@property
29
def col(self) -> int:
30
"""Get the column number where the exception occurred."""
31
32
def mark_input_line(self, markerString: str = ">!<") -> str:
33
"""Return the input line with error position marked."""
34
35
def explain(self, depth: int = 16) -> str:
36
"""Return detailed explanation of parsing failure."""
37
```
38
39
### Specific Exception Types
40
41
Specialized exception classes for different types of parsing failures.
42
43
```python { .api }
44
class ParseException(ParseBaseException):
45
"""Exception raised for general parsing failures."""
46
47
def __init__(self,
48
pstr: str,
49
loc: int = 0,
50
msg: str = None,
51
elem: ParserElement = None): ...
52
53
class ParseFatalException(ParseException):
54
"""Exception that stops backtracking and parser recovery."""
55
56
def __init__(self,
57
pstr: str,
58
loc: int = 0,
59
msg: str = None,
60
elem: ParserElement = None): ...
61
62
class ParseSyntaxException(ParseFatalException):
63
"""Exception for syntax errors in parsing."""
64
65
def __init__(self,
66
pstr: str,
67
loc: int = 0,
68
msg: str = None,
69
elem: ParserElement = None): ...
70
```
71
72
### Grammar Definition Exceptions
73
74
Exceptions related to grammar definition and structure.
75
76
```python { .api }
77
class RecursiveGrammarException(Exception):
78
"""Exception for improperly defined recursive grammars."""
79
80
def __init__(self, parseElementList: list): ...
81
```
82
83
### Exception Usage Patterns
84
85
**Basic exception handling:**
86
```python
87
from pyparsing import Word, alphas, ParseException
88
89
parser = Word(alphas)
90
91
try:
92
result = parser.parse_string("123") # Will fail
93
except ParseException as pe:
94
print(f"Parse failed at line {pe.lineno}, column {pe.col}")
95
print(f"Error: {pe}")
96
print(pe.mark_input_line())
97
```
98
99
**Detailed error reporting:**
100
```python
101
def parse_with_detailed_errors(parser, text):
102
try:
103
return parser.parse_string(text, parse_all=True)
104
except ParseBaseException as pe:
105
print(f"Parsing failed:")
106
print(f" Location: Line {pe.lineno}, Column {pe.col}")
107
print(f" Message: {pe}")
108
print(f" Context: {pe.line}")
109
print(f" Marked: {pe.mark_input_line()}")
110
print(f" Explanation: {pe.explain()}")
111
return None
112
```
113
114
**Custom error messages:**
115
```python
116
# Add custom error messages to parser elements
117
number = Word(nums).set_name("number")
118
operator = oneOf("+ - * /").set_name("arithmetic operator")
119
expr = number + operator + number
120
121
try:
122
result = expr.parse_string("5 % 3") # Invalid operator
123
except ParseException as pe:
124
print(f"Expected {number.name} or {operator.name}")
125
```
126
127
**Fatal exceptions to prevent backtracking:**
128
```python
129
# Use ParseFatalException to stop parser recovery
130
def validate_positive(tokens):
131
if int(tokens[0]) <= 0:
132
raise ParseFatalException("Number must be positive")
133
134
positive_int = Word(nums).set_parse_action(validate_positive)
135
```
136
137
**Exception propagation in complex grammars:**
138
```python
139
# Control exception behavior in nested expressions
140
expr = Forward()
141
term = Word(nums) | "(" + expr + ")"
142
expr <<= term + ZeroOrMore(("+" | "-") + term)
143
144
# ParseFatalException will bubble up through the Forward reference
145
def check_balanced_parens(s, loc, tokens):
146
if tokens.count("(") != tokens.count(")"):
147
raise ParseFatalException("Unbalanced parentheses")
148
149
expr.set_parse_action(check_balanced_parens)
150
```
151
152
**Error recovery strategies:**
153
```python
154
def parse_with_recovery(parser, text):
155
"""Parse with multiple recovery strategies."""
156
try:
157
# Try strict parsing first
158
return parser.parse_string(text, parse_all=True)
159
except ParseFatalException:
160
# Fatal error - don't attempt recovery
161
raise
162
except ParseException as first_error:
163
try:
164
# Try partial parsing
165
return parser.parse_string(text, parse_all=False)
166
except ParseException:
167
# Return original error with more context
168
raise first_error
169
```
170
171
**Custom exception classes:**
172
```python
173
class ConfigurationError(ParseException):
174
"""Custom exception for configuration parsing errors."""
175
176
def __init__(self, pstr, loc, msg, elem=None):
177
super().__init__(pstr, loc, f"Configuration error: {msg}", elem)
178
179
def validate_config_value(tokens):
180
value = tokens[0]
181
if not value:
182
raise ConfigurationError("", 0, "Empty configuration value not allowed")
183
return value
184
185
config_parser = Word(alphanums).set_parse_action(validate_config_value)
186
```
187
188
### Exception Properties and Methods
189
190
**Accessing exception information:**
191
```python
192
try:
193
parser.parse_string(invalid_input)
194
except ParseException as pe:
195
# Location information
196
line_num = pe.lineno # 1-based line number
197
col_num = pe.col # 1-based column number
198
line_text = pe.line # Text of the line containing error
199
200
# Error context
201
marked_line = pe.mark_input_line("<<<ERROR>>>")
202
explanation = pe.explain(depth=10)
203
204
# Exception details
205
error_msg = str(pe) # Human-readable error message
206
location = pe.loc # 0-based character position
207
```
208
209
**Exception chaining for complex parsers:**
210
```python
211
def create_detailed_parser():
212
"""Create parser with comprehensive error reporting."""
213
214
# Add meaningful names to all elements for better error messages
215
identifier = Word(alphas + "_", alphanums + "_").set_name("identifier")
216
number = Word(nums).set_name("number")
217
string_literal = QuotedString('"').set_name("string literal")
218
219
value = (string_literal | number | identifier).set_name("value")
220
assignment = (identifier + "=" + value).set_name("assignment")
221
222
return OneOrMore(assignment).set_name("configuration")
223
224
# Usage with detailed error reporting
225
parser = create_detailed_parser()
226
try:
227
result = parser.parse_string(config_text)
228
except ParseException as pe:
229
print(f"Configuration parsing failed:")
230
print(f"Expected: {pe.expected}") # Available in some contexts
231
print(f"Found: '{pe.line[pe.col-1:pe.col+10]}'")
232
print(pe.explain())
233
```