Registry / serialization / parsimonious

parsimonious

JSON →
library0.11.0pypypi✓ verified 23d ago

Parsimonious is a pure-Python library for creating parsers based on Parsing Expression Grammars (PEGs). It aims for speed and usability, allowing users to define grammars using a simplified EBNF notation. It is designed for applications requiring efficient parsing of structured text, such as configuration files or domain-specific languages. The current version is 0.11.0.

pip install parsimonious
INSTALL
IMPORT
SIG · PARSIMONIOUS
P
parsimonious
serializationpythonv0.11.0
Install
2.2s avg
Import
156ms
Disk
19MB
Pass rate
10/ 10
Env Coverage10 / 10
glibc
3.93.13
musl
3.93.13
Install & Compatibility
Where this runs
tested against v0.11.0 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
musl
py 3.103.95 runs
installs and imports cleanly · install 0.0s · import 0.162s · 20.8MB
glibc
py 3.103.95 runs
installs and imports cleanly · install 2.2s · import 0.150s · 22MB
19MB installed
● package 19MB
Code
Verified usage

Verified import paths — ran on the pinned version, not inferred.

Grammar
from parsimonious.grammar import Grammar
NodeVisitor
from parsimonious.nodes import NodeVisitor
Used for structured traversal and transformation of the parse tree.

This quickstart demonstrates how to define a simple arithmetic grammar, parse an input string, and then process the resulting parse tree using a `NodeVisitor` to evaluate the expression. This pattern of grammar definition followed by a visitor for tree manipulation is central to using Parsimonious effectively.

from parsimonious.grammar import Grammar from parsimonious.nodes import NodeVisitor # 1. Define your grammar grammar = Grammar( """ expression = term (("+" / "-") term)* term = factor (("*" / "/") factor)* factor = "(" expression ")" / number number = ~"[0-9]+" """ ) # 2. Parse an input string input_string = "(10 + 20) * 3" try: tree = grammar.parse(input_string) print(f"Successfully parsed: {input_string}") # print(tree.prettily()) # 3. (Optional) Process the parse tree using a NodeVisitor class CalculatorVisitor(NodeVisitor): def visit_number(self, node, visited_children): return int(node.text) def visit_factor(self, node, visited_children): if len(visited_children) == 3: # ( expression ) _, expr, _ = visited_children return expr return visited_children[0] # number def visit_term(self, node, visited_children): result = visited_children[0] for i in range(1, len(visited_children), 2): op = visited_children[i][0].text # Access the operator node's text num = visited_children[i+1] if op == '*': result *= num elif op == '/': result /= num return result def visit_expression(self, node, visited_children): result = visited_children[0] for i in range(1, len(visited_children), 2): op = visited_children[i][0].text # Access the operator node's text num = visited_children[i+1] if op == '+': result += num elif op == '-': result -= num return result def generic_visit(self, node, visited_children): return visited_children or node calculator = CalculatorVisitor() result = calculator.visit(tree) print(f"Result: {result}") except Exception as e: print(f"Error parsing: {e}")
Debug
Known issues
breakingParsimonious is pre-1.0, and API changes have occurred in previous versions (e.g., 0.5). While 0.11.0 doesn't have explicitly documented breaking changes from 0.10.x, it's generally advised to pin exact versions to avoid unexpected behavior changes in future minor releases.
fix
Always pin your `parsimonious` dependency to a specific version (e.g., `parsimonious==0.11.0`) to ensure stability. Consult the GitHub changelog for specific migration details between versions.
affects: <1.0
gotchaThe library's internal regex handling uses the `regex` library (not Python's built-in `re`) and employs a specific `~"regex"` syntax. The author has also indicated a potential future deprecation of explicit regexes in favor of dynamically built primitives.
fix
Adhere strictly to Parsimonious's regex syntax (`~"pattern"`). Be aware that future versions might change how regexes are defined or preferred. For complex character classes, explicit regexes are currently efficient.
affects: All
gotchaParsimonious is a 'Collection parser' rather than a 'stream parser'. This means it loads the entire input (e.g., a string or file content) into memory before parsing. For extremely large inputs, this can lead to high memory consumption.
fix
For very large files or data streams, consider pre-processing to break them into smaller, manageable chunks, or evaluate if a stream-based parsing library is more suitable for your specific use case. Parsimonious is best suited for inputs that fit comfortably in memory.
affects: All
gotchaWhile direct manipulation of `Node` objects is possible, the recommended and most robust way to process the Abstract Syntax Tree (AST) after parsing is to create a subclass of `NodeVisitor`.
fix
For any non-trivial processing of the parse tree, implement a `NodeVisitor` subclass. This provides an organized, maintainable, and less error-prone way to traverse and transform the tree.
affects: All
Errors
Common errors & fixes
parsimonious.exceptions.IncompleteParseError: Rule 'program' matched in its entirety, but it didn't consume all the text. The non-matching portion of the text begins with '...' (line ..., column ...).
This error occurs when the grammar's default rule (or the rule explicitly called with `parse()`) successfully matches a prefix of the input string but fails to consume the *entire* input, leaving unmatched text at the end. This often happens due to missing whitespace rules or a top-level rule not accounting for all possible input elements.
fix
Ensure your top-level grammar rule accounts for all expected input, including optional whitespace or other characters at the end of the text. Often, adding an implicit or explicit whitespace rule (e.g., `_ = ~'\s*'` and applying it where necessary) or ensuring the main rule covers the full pattern can resolve this. For example, if parsing a full file, make sure your top rule matches all lines/statements.
parsimonious.exceptions.ParseError: Rule 'some_rule' didn't match at '...' (line ..., column ...).
This is the general parse error indicating that a specific rule within your grammar failed to match the input at the given position. This means the input string does not conform to the structure expected by that particular rule.
fix
Examine the grammar rule mentioned in the error (`'some_rule'`) and the input string section indicated by `didn't match at '...'`. Adjust the grammar definition to correctly reflect the expected input format, or modify the input to conform to the grammar. Pay close attention to literals, regular expressions (`~"..."`), and the order of alternatives.
parsimonious.exceptions.LeftRecursionError: Left recursion in rule 'some_rule' at '...' (line ..., column ...). Parsimonious is a packrat parser, so it can't handle left recursion.
Parsimonious uses a Parsing Expression Grammar (PEG) approach, which does not inherently support direct left recursion (e.g., `A = A 'x' | 'y'`). Such rules would lead to an infinite loop during parsing.
fix
Rewrite the left-recursive rule to an iterative (usually right-recursive) form. For example, a left-recursive rule like `expr = expr '+' term / term` can be rewritten as `expr = term (('+' term)*)`. This converts the recursive definition into one that uses repetition operators.
parsimonious.exceptions.BadGrammar: Undefined label: 'missing_rule_name'
This error signifies that your grammar definition references a rule or label (`'missing_rule_name'`) that has not been defined anywhere else in the grammar string.
fix
Review your grammar definition and ensure that all referenced rule names are correctly spelled and have a corresponding definition within the `Grammar` string. If a rule is intentionally left undefined, it might indicate a logical error in the grammar design.
Upgrade
Version history
0.11.0latest on PyPI · released Nov 12, 2025
Audit
Dependencies

No dependency data recorded yet.

Agent activity
5 hits · last 30 days
node
4
Resources
parsimonious — pip install parsimonious · libregistry