Easy-to-use parser combinators for parsing in pure Python
npx @tessl/cli install tessl/pypi-parsy@1.4.0A comprehensive Python library for building parser combinators in pure Python. Parsy provides a declarative way to construct complex parsers by combining simple, small parsers together. It offers a monadic parser combinator library for LL(infinity) grammars, inspired by Parsec, Parsnip, and Parsimmon.
pip install parsyimport parsyCommon for working with specific parsers:
from parsy import string, regex, generate, seq, altImport all core functionality:
from parsy import *Version information:
from parsy import __version__from parsy import string, regex, generate, seq, alt
# Simple string parser
hello_parser = string('hello')
result = hello_parser.parse('hello') # Returns 'hello'
# Regex parser
number_parser = regex(r'\d+').map(int)
result = number_parser.parse('123') # Returns 123
# Combining parsers with sequences
greeting_parser = seq(
string('hello'),
regex(r'\s+'),
regex(r'\w+')
).combine(lambda hello, space, name: f"{hello} {name}")
result = greeting_parser.parse('hello world') # Returns 'hello world'
# Using generator syntax for complex parsing
@generate
def simple_expression():
left = yield number_parser
operator = yield regex(r'\s*[+\-*/]\s*')
right = yield number_parser
return (left, operator.strip(), right)
result = simple_expression.parse('5 + 3') # Returns (5, '+', 3)Parsy follows a functional programming approach with these core concepts:
The library uses monadic composition patterns, allowing parsers to be bound together with proper error propagation and backtracking.
The fundamental Parser class provides the foundation for all parsing operations, including execution, transformation, and combination methods.
class Parser:
def parse(self, stream): ...
def parse_partial(self, stream): ...
def bind(self, bind_fn): ...
def map(self, map_fn): ...
def then(self, other): ...
def skip(self, other): ...
def many(self): ...
def times(self, min, max=None): ...
def optional(self): ...Fundamental parser constructors for strings, regular expressions, character matching, and success/failure cases.
def string(s, transform=noop): ...
def regex(exp, flags=0, group=0): ...
def test_char(func, description): ...
def success(val): ...
def fail(expected): ...Functions for combining multiple parsers into more complex parsing logic, including alternatives, sequences, and generator-based composition.
def alt(*parsers): ...
def seq(*parsers, **kw_parsers): ...
def generate(fn): ...Ready-to-use parser constants for common parsing tasks like whitespace, digits, letters, and end-of-input detection.
any_char: Parser
whitespace: Parser
letter: Parser
digit: Parser
decimal_digit: Parser
eof: Parser
index: Parser
line_info: ParserHelper functions for common operations and transformations.
def line_info_at(stream, index): ...
noop: functionfrom collections import namedtuple
class ParseError(RuntimeError):
expected: frozenset
stream: str
index: int
def line_info(self) -> str: ...
class Result(namedtuple('Result', 'status index value furthest expected')):
"""
Result of a parsing operation.
Attributes:
status: bool - True if parsing succeeded, False if failed
index: int - Position after successful parse (or -1 for failure)
value: Any - Parsed value (or None for failure)
furthest: int - Furthest position reached during parsing
expected: frozenset - Set of expected values at failure point
"""
@staticmethod
def success(index, value): ...
@staticmethod
def failure(index, expected): ...
def aggregate(self, other): ...
class forward_declaration(Parser):
"""
Forward declaration for recursive parsers.
An empty parser that can be used as a forward declaration,
especially for parsers that need to be defined recursively.
You must use .become(parser) before using.
"""
def __init__(self): ...
def become(self, other): ...
# These methods raise ValueError before become() is called:
def parse(self, stream): ... # Raises ValueError if become() not called
def parse_partial(self, stream): ... # Raises ValueError if become() not called