Parsy
Parsy is an easy-to-use parser combinator library for building parsers in pure Python. It provides a straightforward and Pythonic solution for parsing text without external dependencies, focusing on combining small parsers into complex ones. The library is highly mature and stable, with its current version being 2.2. Releases are active, often aligning with Python version lifecycle updates.
Warnings
- breaking Parsy version 2.2 (released 2025-09-12) dropped support for Python 3.7 and 3.8, which have reached their End-of-Life (EOL). Users on these Python versions must upgrade to Python 3.9+ or stick to an older `parsy` version (e.g., 2.1 or earlier).
- gotcha While `parsy` provides good basic error messages, for highly detailed, end-user-facing error reporting in complex custom languages (e.g., for a programming language's compiler), significant extra effort might be required to customize the error output, or a more heavyweight parser generator might be a better fit.
- gotcha Parsy excels at quickly writing clear, declarative parsers for relatively small to medium-sized languages. However, for applications with extremely demanding performance requirements or exceptionally large and complex grammars, other parser generators that use different parsing algorithms (e.g., LALR, PEG) might offer better performance characteristics.
Install
-
pip install parsy
Imports
- string
from parsy import string
- regex
from parsy import regex
- generate
from parsy import generate
- ParseError
from parsy import ParseError
Quickstart
from parsy import string, regex, generate, ParseError
from datetime import date
# Example 1: Simple date parsing using combinators
year = regex(r"[0-9]{4}").map(int)
month = regex(r"[0-9]{2}").map(int)
day = regex(r"[0-9]{2}").map(int)
dash = string('-')
iso_date_parser = year.then(dash).then(month).then(dash).then(day)
try:
parsed_date_list = iso_date_parser.parse("2023-10-26")
# The default behavior of .then() chain is to return the value of the *last* parser.
# To combine results, .map() or @generate is often used.
print(f"Simple parse result (last element): {parsed_date_list}")
except ParseError as e:
print(f"Parse Error: {e}")
# Example 2: More complex date parsing using the @generate decorator
# This allows you to combine parsed values into a structured result.
@generate
def full_date_parser():
y = yield year << dash
m = yield month << dash
d = yield day
return date(y, m, d)
try:
parsed_date_obj = full_date_parser.parse("2023-10-26")
print(f"Structured parse result (date object): {parsed_date_obj}")
assert parsed_date_obj == date(2023, 10, 26)
# Example of a failure
full_date_parser.parse("2023/10/26")
except ParseError as e:
print(f"Parse Error for '2023/10/26': {e}")
# Example 3: Using .map to transform simple results
weekday_parser = string('Mon') | string('Tue') | string('Wed') # ...and so on
weekday_mapping = {'Mon': 'Monday', 'Tue': 'Tuesday', 'Wed': 'Wednesday'}
mapped_weekday_parser = weekday_parser.map(lambda s: weekday_mapping.get(s, s))
try:
print(f"Mapped weekday: {mapped_weekday_parser.parse('Tue')}")
except ParseError as e:
print(f"Parse Error: {e}")