A Python parsing module providing an alternative approach to creating and executing simple grammars
—
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.
Foundation exception classes that provide common functionality for all parsing errors.
class ParseBaseException(Exception):
"""Base class for all pyparsing exceptions."""
def __init__(self,
pstr: str,
loc: int = 0,
msg: str = None,
elem: ParserElement = None): ...
@property
def line(self) -> str:
"""Get the line of text where the exception occurred."""
@property
def lineno(self) -> int:
"""Get the line number where the exception occurred."""
@property
def col(self) -> int:
"""Get the column number where the exception occurred."""
def mark_input_line(self, markerString: str = ">!<") -> str:
"""Return the input line with error position marked."""
def explain(self, depth: int = 16) -> str:
"""Return detailed explanation of parsing failure."""Specialized exception classes for different types of parsing failures.
class ParseException(ParseBaseException):
"""Exception raised for general parsing failures."""
def __init__(self,
pstr: str,
loc: int = 0,
msg: str = None,
elem: ParserElement = None): ...
class ParseFatalException(ParseException):
"""Exception that stops backtracking and parser recovery."""
def __init__(self,
pstr: str,
loc: int = 0,
msg: str = None,
elem: ParserElement = None): ...
class ParseSyntaxException(ParseFatalException):
"""Exception for syntax errors in parsing."""
def __init__(self,
pstr: str,
loc: int = 0,
msg: str = None,
elem: ParserElement = None): ...Exceptions related to grammar definition and structure.
class RecursiveGrammarException(Exception):
"""Exception for improperly defined recursive grammars."""
def __init__(self, parseElementList: list): ...Basic exception handling:
from pyparsing import Word, alphas, ParseException
parser = Word(alphas)
try:
result = parser.parse_string("123") # Will fail
except ParseException as pe:
print(f"Parse failed at line {pe.lineno}, column {pe.col}")
print(f"Error: {pe}")
print(pe.mark_input_line())Detailed error reporting:
def parse_with_detailed_errors(parser, text):
try:
return parser.parse_string(text, parse_all=True)
except ParseBaseException as pe:
print(f"Parsing failed:")
print(f" Location: Line {pe.lineno}, Column {pe.col}")
print(f" Message: {pe}")
print(f" Context: {pe.line}")
print(f" Marked: {pe.mark_input_line()}")
print(f" Explanation: {pe.explain()}")
return NoneCustom error messages:
# Add custom error messages to parser elements
number = Word(nums).set_name("number")
operator = oneOf("+ - * /").set_name("arithmetic operator")
expr = number + operator + number
try:
result = expr.parse_string("5 % 3") # Invalid operator
except ParseException as pe:
print(f"Expected {number.name} or {operator.name}")Fatal exceptions to prevent backtracking:
# Use ParseFatalException to stop parser recovery
def validate_positive(tokens):
if int(tokens[0]) <= 0:
raise ParseFatalException("Number must be positive")
positive_int = Word(nums).set_parse_action(validate_positive)Exception propagation in complex grammars:
# Control exception behavior in nested expressions
expr = Forward()
term = Word(nums) | "(" + expr + ")"
expr <<= term + ZeroOrMore(("+" | "-") + term)
# ParseFatalException will bubble up through the Forward reference
def check_balanced_parens(s, loc, tokens):
if tokens.count("(") != tokens.count(")"):
raise ParseFatalException("Unbalanced parentheses")
expr.set_parse_action(check_balanced_parens)Error recovery strategies:
def parse_with_recovery(parser, text):
"""Parse with multiple recovery strategies."""
try:
# Try strict parsing first
return parser.parse_string(text, parse_all=True)
except ParseFatalException:
# Fatal error - don't attempt recovery
raise
except ParseException as first_error:
try:
# Try partial parsing
return parser.parse_string(text, parse_all=False)
except ParseException:
# Return original error with more context
raise first_errorCustom exception classes:
class ConfigurationError(ParseException):
"""Custom exception for configuration parsing errors."""
def __init__(self, pstr, loc, msg, elem=None):
super().__init__(pstr, loc, f"Configuration error: {msg}", elem)
def validate_config_value(tokens):
value = tokens[0]
if not value:
raise ConfigurationError("", 0, "Empty configuration value not allowed")
return value
config_parser = Word(alphanums).set_parse_action(validate_config_value)Accessing exception information:
try:
parser.parse_string(invalid_input)
except ParseException as pe:
# Location information
line_num = pe.lineno # 1-based line number
col_num = pe.col # 1-based column number
line_text = pe.line # Text of the line containing error
# Error context
marked_line = pe.mark_input_line("<<<ERROR>>>")
explanation = pe.explain(depth=10)
# Exception details
error_msg = str(pe) # Human-readable error message
location = pe.loc # 0-based character positionException chaining for complex parsers:
def create_detailed_parser():
"""Create parser with comprehensive error reporting."""
# Add meaningful names to all elements for better error messages
identifier = Word(alphas + "_", alphanums + "_").set_name("identifier")
number = Word(nums).set_name("number")
string_literal = QuotedString('"').set_name("string literal")
value = (string_literal | number | identifier).set_name("value")
assignment = (identifier + "=" + value).set_name("assignment")
return OneOrMore(assignment).set_name("configuration")
# Usage with detailed error reporting
parser = create_detailed_parser()
try:
result = parser.parse_string(config_text)
except ParseException as pe:
print(f"Configuration parsing failed:")
print(f"Expected: {pe.expected}") # Available in some contexts
print(f"Found: '{pe.line[pe.col-1:pe.col+10]}'")
print(pe.explain())Install with Tessl CLI
npx tessl i tessl/pypi-pyparsing