### Install Parsita Source: https://github.com/drhagen/parsita/blob/master/docs/index.md Installs the Parsita library from PyPI using pip. This is the recommended method for installation. ```shell pip install parsita ``` -------------------------------- ### Install Parsita Source: https://github.com/drhagen/parsita/blob/master/README.md Installs the Parsita library using pip from PyPI. This is the recommended method for installation. ```shell pip install parsita ``` -------------------------------- ### Parse and Handle Result with isinstance (Pre-Python 3.10) Source: https://github.com/drhagen/parsita/blob/master/docs/getting_started.md Shows how to parse a numeric list string and handle the `Result` object using `isinstance` checks for `Success` and `Failure` in Python versions prior to 3.10. ```python from parsita import * class NumericListParsers(ParserContext, whitespace=r'[ ]*'): integer_list = '[' >> repsep(reg('[+-]?[0-9]+') > int, ',') << ']' result = NumericListParsers.integer_list.parse('[1, 1, 2, 3, 5]') if isinstance(result, Success): python_list = result.unwrap() elif isinstance(result, Failure): raise result.failure() ``` -------------------------------- ### Parse and Handle Result with Pattern Matching (Python 3.10+) Source: https://github.com/drhagen/parsita/blob/master/docs/getting_started.md Demonstrates parsing a string representing a numeric list and handling the `Result` object using Python 3.10's `match` statement for `Success` and `Failure` cases. ```python from parsita import * class NumericListParsers(ParserContext, whitespace=r'[ ]*'): integer_list = '[' >> repsep(reg('[+-]?[0-9]+') > int, ',') << ']' result = NumericListParsers.integer_list.parse('[1, 1, 2, 3, 5]') match result: case Success(value): python_list = value case Failure(error): raise error ``` -------------------------------- ### Install Parsita and Dependencies Source: https://github.com/drhagen/parsita/blob/master/docs/contributing.md Installs the `uv` package manager and then uses `uv` to install Parsita and its dependencies from source. ```shell pip install uv uv sync ``` -------------------------------- ### Hello World Parser Example Source: https://github.com/drhagen/parsita/blob/master/README.md Demonstrates a basic parser for the string 'Hello, {name}!'. It uses Parsita's `ParserContext`, `lit`, `>>`, `reg`, `<<`, and `parse().unwrap()` to define and execute a parser. Includes examples of both successful and failed parses. ```python from parsita import * class HelloWorldParsers(ParserContext, whitespace=r'[ ]*'): hello_world = lit('Hello') >> ',' >> reg(r'[A-Z][a-z]*') << '!' # A successful parse produces the parsed value name = HelloWorldParsers.hello_world.parse('Hello, David!').unwrap() assert name == 'David' # A parsing failure produces a useful error message name = HelloWorldParsers.hello_world.parse('Hello David!').unwrap() # parsita.state.ParseError: Expected ',' but found 'David' # Line 1, character 7 # # Hello David! # ^ ``` -------------------------------- ### Define Numeric List Parser Source: https://github.com/drhagen/parsita/blob/master/docs/getting_started.md Defines a parser for a list of integers enclosed in square brackets, with optional whitespace handling. It uses `ParserContext` and regular expressions to define the grammar. ```python from parsita import * class NumericListParsers(ParserContext, whitespace=r'[ ]*'): integer_list = '[' >> repsep(reg('[+-]?[0-9]+') > int, ',') << ']' ``` -------------------------------- ### Regular Expression Parser (`reg`) Example Source: https://github.com/drhagen/parsita/blob/master/docs/terminal_parsers.md Illustrates the use of the `reg` parser for matching strings based on regular expressions. This example shows how to create a parser that extracts integer values, including optional signs, from an input string. ```python from parsita import * class IntegerParsers(ParserContext): integer = reg(r'[-+]?[0-9]+') assert IntegerParsers.integer.parse('-128') == Success('-128') ``` -------------------------------- ### Literal Parser (`lit`) Example Source: https://github.com/drhagen/parsita/blob/master/docs/terminal_parsers.md Demonstrates the usage of the `lit` parser to match exact string literals. It shows how to define a parser that matches 'Hello World!' and handles both successful and failed parsing attempts. ```python from parsita import * class HelloParsers(ParserContext): hello = lit('Hello World!') assert HelloParsers.hello.parse('Hello World!') == Success('Hello World!') assert isinstance(HelloParsers.hello.parse('Goodbye'), Failure) ``` -------------------------------- ### First Alternative Parser (first) - Expression Parsing Source: https://github.com/drhagen/parsita/blob/master/docs/alternative_parsers.md Shows the `first` function, which returns the value of the first successful parser. This example parses keywords, function calls, or names, prioritizing keywords. ```python from parsita import * class ExpressionParsers(ParserContext): keyword = lit('pi', 'nan', 'inf') name = reg(r'[a-zA-Z_]+') function = name & '(' >> expression << ')' expression = first(keyword, function, name) assert ExpressionParsers.expression.parse('f(x)') == Success(['f', 'x']) assert str(ExpressionParsers.expression.parse('pi(x)').failure()) == ( "Expected end of source but found '(' "Line 1, character 3 "pi(x) " ^ " ) ``` -------------------------------- ### Longest Alternative Parser (longest) - Expression Parsing Source: https://github.com/drhagen/parsita/blob/master/docs/alternative_parsers.md Illustrates the `longest` function (used by the '|' operator in Parsita v2) for selecting the parser that consumes the most input. This example parses either a name or a function call. ```python from parsita import * class ExpressionParsers(ParserContext): name = reg(r'[a-zA-Z_]+') function = name & '(' >> expression << ')' expression = longest(name, function) assert ExpressionParsers.expression.parse('f(x)') == Success(['f', 'x']) ``` -------------------------------- ### Deploy Documentation to GitHub Pages Source: https://github.com/drhagen/parsita/blob/master/docs/contributing.md Builds the static documentation site and deploys it to GitHub Pages using MkDocs' `gh-deploy` command. ```shell uv run mkdocs gh-deploy ``` -------------------------------- ### Serve Documentation Locally Source: https://github.com/drhagen/parsita/blob/master/docs/contributing.md Generates and serves the project's HTML documentation locally using MkDocs for development purposes. ```shell uv run mkdocs serve ``` -------------------------------- ### Hello World Parser Source: https://github.com/drhagen/parsita/blob/master/docs/index.md Demonstrates a basic parser using Parsita to extract a name from a 'Hello, {name}!' string. It shows successful parsing and how parsing failures are handled with error messages. The parser uses literal matching, regular expressions, and operator chaining. ```python from parsita import * class HelloWorldParsers(ParserContext, whitespace=r'[ ]*'): hello_world = lit('Hello') >> ',' >> reg(r'[A-Z][a-z]*') << '!' # A successful parse produces the parsed value name = HelloWorldParsers.hello_world.parse('Hello, David!').unwrap() assert name == 'David' # A parsing failure produces a useful error message name = HelloWorldParsers.hello_world.parse('Hello David!').unwrap() # parsita.state.ParseError: Expected ',' but found 'David' # Line 1, character 7 # # Hello David! # ^ ``` -------------------------------- ### Clone the Repository Source: https://github.com/drhagen/parsita/blob/master/docs/contributing.md Clones the Parsita repository from GitHub to your local machine using Git. ```shell git clone https://github.com/drhagen/parsita.git ``` -------------------------------- ### Code Quality Checks with Nox Source: https://github.com/drhagen/parsita/blob/master/docs/contributing.md Runs code quality checks including formatting, linting, and type checking using Ruff and mypy, orchestrated by Nox. ```shell uv run nox -s format uv run nox -s lint uv run nox -s type_check ``` -------------------------------- ### Optional Parser (opt) - Declaration Parsing Source: https://github.com/drhagen/parsita/blob/master/docs/alternative_parsers.md Demonstrates the `opt` function, which makes a parser optional. If the parser succeeds, its value is returned in a list; otherwise, an empty list is returned. ```python from parsita import * class DeclarationParsers(ParserContext, whitespace=r'[ ]*'): id = reg(r'[A-Za-z_][A-Za-z0-9_]*') declaration = id & opt(':' >> id) assert DeclarationParsers.declaration.parse('x: int') == Success(['x', ['int']]) assert DeclarationParsers.declaration.parse('x') == Success(['x', []]) ``` -------------------------------- ### Run Tests with Nox Source: https://github.com/drhagen/parsita/blob/master/docs/contributing.md Executes the project's tests using pytest, managed by Nox. This command runs tests across all compatible Python versions found by Nox. ```shell uv run nox -s test ``` -------------------------------- ### Run Tests for a Specific Python Version Source: https://github.com/drhagen/parsita/blob/master/docs/contributing.md Runs the project's tests using Nox for a specific Python version (e.g., Python 3.13). ```shell uv run nox -s test-3.13 ``` -------------------------------- ### Parsers Parameterized by Previous Input Source: https://github.com/drhagen/parsita/blob/master/docs/conversion_parsers.md Shows how transformation parsers can be used to select subsequent parsers based on previously parsed input. The `select_parser` function dynamically returns a parser based on the `type` string. ```python from parsita import * def select_parser(type: str): if type == 'int': return reg(r"[0-9]+") > int elif type == 'decimal': return reg(r"[0-9]+\\.[0-9]+") > float class NumberParsers(ParserContext, whitespace=r'[ ]*'): type = lit('int', 'decimal') number = type >= select_parser assert NumberParsers.number.parse('int 5') == Success(5) assert isinstance(NumberParsers.number.parse('int 2.0'), Failure) ``` -------------------------------- ### Repeated Parsers (rep, rep1) Source: https://github.com/drhagen/parsita/blob/master/docs/repeated_parsers.md Matches repeated instances of a parser. `rep` matches between `min` and `max` times, while `rep1` requires at least one match. Returns a list of matched values. If `min=0`, `rep` always succeeds. ```python from parsita import * class SummationParsers(ParserContext, whitespace=r'[ ]*'): integer = reg(r'[-+]?[0-9]+') > int summation = integer & rep('+' >> integer) > (lambda x: sum([x[0]] + x[1])) assert SummationParsers.summation.parse('1 + 1 + 2 + 3 + 5') == Success(12) ``` -------------------------------- ### Repeated Separated Parsers (repsep, rep1sep) Source: https://github.com/drhagen/parsita/blob/master/docs/repeated_parsers.md Matches a parser separated by a specified separator. `repsep` matches between `min` and `max` times, while `rep1sep` requires at least one match. Returns a list of values from the parser, discarding separator values. If `min=0`, `repsep` always succeeds. ```python from parsita import * class ListParsers(ParserContext, whitespace=r'[ ]*'): integer = reg(r'[-+]?[0-9]+') > int my_list = '[' >> repsep(integer, ',') << ']' assert ListParsers.my_list.parse('[1,2,3]') == Success([1, 2, 3]) ``` -------------------------------- ### Fallible Conversion and Transformation Parser Source: https://github.com/drhagen/parsita/blob/master/docs/conversion_parsers.md Illustrates a transformation parser using the `>=` operator for fallible conversions. The `to_percent` function validates the parsed number and returns either a `SuccessParser` or a `FailureParser`. ```python from dataclasses import dataclass from parsita import * @dataclass class Percent: number: int def to_percent(number: int) -> Parser[str, Percent]: if not 0 <= number <= 100: return failure("a number between 0 and 100") else: return success(Percent(number)) class PercentParsers(ParserContext): percent = (reg(r"[0-9]+") > int) >= to_percent assert PercentParsers.percent.parse('50') == Success(Percent(50)) assert isinstance(PercentParsers.percent.parse('150'), Failure) ``` -------------------------------- ### Parsita debug(parser, *, verbose=False, callback=None) Parser Source: https://github.com/drhagen/parsita/blob/master/docs/miscellaneous_parsers.md The `debug(parser, *, verbose=False, callback=None)` parser aids in debugging by optionally printing input/output or executing a callback function. It doesn't alter parsing results. The `verbose` flag enables location printing, and the `callback` allows custom inspection. Dependencies include `parsita` and potentially `decimal` for type conversion. ```python from decimal import Decimal from parsita import * def temp(parser, reader): # Can put a breakpoint here to inspect why the decimal parser is capturing # Spoiler: use `\. instead of `.` in regexes pass class NumberParsers(ParserContext): integer = reg(r'[-+]?[0-9]+') > int decimal = debug(reg(r'[-+]?[0-9]+.[0-9]+'), callback=temp) > Decimal scientific = reg(r'[-+]?[0-9]+e[-+]?[0-9]+') > float number = decimal | scientific | integer # Assertion is broken and needs debugged assert isinstance(NumberParsers.number.parse('1e5').unwrap(), float) ``` -------------------------------- ### Parsita success() Parser Source: https://github.com/drhagen/parsita/blob/master/docs/miscellaneous_parsers.md The `success(value)` parser always succeeds with a given value without consuming input. It's useful for inserting arbitrary values into parsers, especially during prototyping or for unimplemented code sections. Dependencies include the `parsita` library. ```python from parsita import * class HostnameParsers(ParserContext): port = success(80) # TODO: do not just ignore other ports host = rep1sep(reg('[A-Za-z0-9]+([-]+[A-Za-z0-9]+)*'), '.') server = host & port assert HostnameParsers.server.parse('drhagen.com') == Success([['drhagen', 'com'], 80]) ``` -------------------------------- ### Alternative Parser (|) - Number Parsing Source: https://github.com/drhagen/parsita/blob/master/docs/alternative_parsers.md Demonstrates the use of the '|' operator for creating alternative parsers. It defines parsers for integers and real numbers, with 'real' using '|' to handle 'nan' or 'inf' literals. ```python from parsita import * class NumberParsers(ParserContext): integer = reg(r'[-+]?[0-9]+') > int real = reg(r'[+-]?\d+\.\d+(e[+-]?\d+)?') | 'nan' | 'inf' > float number = real | integer assert NumberParsers.number.parse('4.0000') == Success(4.0) ``` -------------------------------- ### Consume Until Parser (`until`) Source: https://github.com/drhagen/parsita/blob/master/docs/miscellaneous_parsers.md The `until` parser consumes input until a given parser succeeds, without consuming the input of the successing parser. It returns all consumed input. Be cautious with performance on large inputs due to its character-by-character retry mechanism. ```python from parsita import * class TestParser(ParserContext, whitespace=r'\s*'): heredoc = reg("[A-Za-z]+") >= (lambda token: until(token) << token) content = "EOF\nAnything at all\nEOF" assert TestParser.heredoc.parse(content) == Success("Anything at all\n") ``` -------------------------------- ### Sequential Parser (`&`) Source: https://github.com/drhagen/parsita/blob/master/docs/sequential_parsers.md Combines two parsers sequentially. If a `ParserContext` is used, whitespace may separate the parsers. The returned value is a list containing values from each parser. This is useful for parsing structured data like URLs. ```python from parsita import * class UrlParsers(ParserContext): url = lit('http', 'ftp') & '://' & reg(r'[^/]+') & reg(r'.*') assert UrlParsers.url.parse('http://drhagen.com/blog/sane-equality/') == \ Success(['http', '://', 'drhagen.com', '/blog/sane-equality/']) ``` -------------------------------- ### Any Single Element Parser (`any1`) Source: https://github.com/drhagen/parsita/blob/master/docs/miscellaneous_parsers.md The `any1` parser matches a single element from the input stream. It's more useful for non-textual data than text, often used with `pred` to apply a condition to individual tokens. ```python from parsita import * class DigitParsers(ParserContext): digit = pred(any1, lambda x: x['type'] == 'digit', 'a digit') > \ (lambda x: x['payload']) assert DigitParsers.digit.parse([{'type': 'digit', 'payload': 3}]) == \ Success(3) ``` -------------------------------- ### Parsita failure(expected) Parser Source: https://github.com/drhagen/parsita/blob/master/docs/miscellaneous_parsers.md The `failure(expected)` parser always fails with a specified message, indicating an expected string. It's useful for marking unimplemented sections or providing clearer error messages for invalid input. Dependencies include the `parsita` library. ```python from parsita import * class HostnameParsers(ParserContext): # TODO: implement allowing different port port = lit('80') | reg('[0-9]+') & failure('no other port than 80') host = rep1sep(reg('[A-Za-z0-9]+([-]+[A-Za-z0-9]+)*'), '.') server = host << ':' & port assert str(HostnameParsers.server.parse('drhagen.com:443').failure()) == ( 'Expected no other port than 80 but found end of source' ) ``` -------------------------------- ### Integer Conversion Parser Source: https://github.com/drhagen/parsita/blob/master/docs/conversion_parsers.md Demonstrates a conversion parser that converts a matched regular expression string to an integer. The `>` operator is used for this conversion after a successful regex match. ```python from parsita import * class IntegerParsers(ParserContext): integer = reg(r'[-+]?[0-9]+') > int assert IntegerParsers.integer.parse('-128') == Success(-128) ``` -------------------------------- ### Forward Declaration Parser (`fwd`) Source: https://github.com/drhagen/parsita/blob/master/docs/miscellaneous_parsers.md The `fwd` function creates a forward declaration for a parser that will be defined later. This is useful for recursive or mutually dependent grammars. The definition is provided using the `define` method. ```python from parsita import * class AddingParsers(ParserContext): number = reg(r'[+-]?\d+') > int expr = fwd() base = '(' >> expr << ')' | number expr.define(rep1sep(base, '+') > sum) assert AddingParsers.expr.parse('2+(1+2)+3') == Success(8) ``` -------------------------------- ### Predicate Parser (`pred`) Source: https://github.com/drhagen/parsita/blob/master/docs/miscellaneous_parsers.md The `pred` parser matches an inner parser and then applies a predicate function to its result. If the predicate returns True, it succeeds; otherwise, it fails with a specified description. Useful for validating parsed values. ```python from parsita import * class IntervalParsers(ParserContext, whitespace=r'[ ]*'): number = reg('\d+') > int pair = '[' >> number << ',' & number << ']' interval = pred(pair, lambda x: x[0] <= x[1], 'ordered pair') assert IntervalParsers.interval.parse('[1, 2]') == Success([1, 2]) assert IntervalParsers.interval.parse('[2, 1]') != Success([2, 1]) ``` -------------------------------- ### Create a function that always returns the same value Source: https://github.com/drhagen/parsita/blob/master/docs/utility_functions.md The `constant(value)` function creates a new function that ignores its arguments and always returns the specified `value`. This is particularly useful in parser definitions where a specific literal should map to a fixed result, such as boolean values. ```Python from parsita import * from parsita.util import constant class BooleanParsers(ParserContext): true = lit('true') > constant(True) false = lit('false') > constant(False) boolean = true | false assert BooleanParsers.boolean.parse('false') == Success(False) ``` -------------------------------- ### Discard Right Parser (`<<`) Source: https://github.com/drhagen/parsita/blob/master/docs/sequential_parsers.md Matches the same text as the sequential parser (`&`) but discards the value from the right parser. The left parser's value is returned. Useful when a delimiter or surrounding syntax is not needed in the final result. ```python from parsita import * class PointParsers(ParserContext, whitespace=r'[ ]*'): integer = reg(r'[-+]?[0-9]+') > int point = '(' >> integer << ',' & integer << ')' assert PointParsers.point.parse('(4, 3)') == Success([4, 3]) ``` -------------------------------- ### Discard Left Parser (`>>`) Source: https://github.com/drhagen/parsita/blob/master/docs/sequential_parsers.md Matches the same text as the sequential parser (`&`) but discards the value from the left parser. The right parser's value is returned. Useful when a delimiter or surrounding syntax is not needed in the final result. ```python from parsita import * class PointParsers(ParserContext, whitespace=r'[ ]*'): integer = reg(r'[-+]?[0-9]+') > int point = '(' >> integer << ',' & integer << ')' assert PointParsers.point.parse('(4, 3)') == Success([4, 3]) ``` -------------------------------- ### Convert a function of one list argument to take many arguments Source: https://github.com/drhagen/parsita/blob/master/docs/utility_functions.md The `unsplat(function)` utility performs the inverse operation of `splat`. It converts a function that expects a single argument (a list or tuple of values) into a function that accepts those values as separate, individual arguments. While less common for parser creation due to how converters are called, it complements `splat`. ```Python from parsita.util import splat, unsplat def sum_args(*x): return sum(x) def sum_list(x): return sum(x) splatted_sum_args = splat(sum_args) unsplatted_sum_list = unsplat(sum_list) assert unsplatted_sum_list(2, 3, 5) == sum_args(2, 3, 5) assert splatted_sum_args([2, 3, 5]) == sum_list([2, 3, 5]) ``` -------------------------------- ### Convert a function of many arguments to take only one list argument Source: https://github.com/drhagen/parsita/blob/master/docs/utility_functions.md The `splat(function)` utility converts a function that accepts multiple arguments into one that accepts a single argument: a tuple containing all the original arguments. This is useful when a sequential parser (`&`) returns a tuple of results that need to be passed as individual arguments to a function. ```Python from collections import namedtuple from parsita import * from parsita.util import splat Url = namedtuple('Url', ['host', 'port', 'path']) class UrlParsers(ParserContext): host = reg(r'[A-Za-z0-9.]+') port = reg(r'[0-9]+') > int path = reg(r'[-._~A-Za-z0-9/]*') url = 'https://' >> host << ':' & port & path > splat(Url) assert UrlParsers.url.parse('https://drhagen.com:443/blog/') == \ Success(Url('drhagen.com', 443, '/blog/')) ``` -------------------------------- ### End of File Parser (`eof`) Source: https://github.com/drhagen/parsita/blob/master/docs/miscellaneous_parsers.md The `eof` parser matches the end of the input stream. It's used to ensure that a preceding parser is the last one to match, often as an alternative to an explicit end token. ```python from parsita import * class OptionsParsers(ParserContext): option = reg(r'[A-Za-z]+') << '=' & reg(r'[A-Za-z]+') << (';' | eof) options = rep(option) assert OptionsParsers.options.parse('log=warn;detail=minimal;') == \ Success([['log', 'warn'], ['detail', 'minimal']]) assert OptionsParsers.options.parse('log=warn;detail=minimal') == \ Success([['log', 'warn'], ['detail', 'minimal']]) ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.