Metadata-Version: 2.4
Name: abnf
Version: 2.6.0
Summary: Parsers for ABNF grammars.
Author-email: Charles Yeomans <charles@declaresub.com>
Project-URL: Homepage, https://github.com/declaresub/abnf
Project-URL: Documentation, https://abnf.readthedocs.io/
Project-URL: Source, https://github.com/declaresub/abnf
Project-URL: Changelog, https://github.com/declaresub/abnf/blob/master/CHANGELOG.md
Project-URL: Issues, https://github.com/declaresub/abnf/issues
Keywords: abnf,generator,parser
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: Code Generators
Classifier: Topic :: Software Development :: Interpreters
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE.txt
Provides-Extra: dev
Requires-Dist: check-manifest==0.51; extra == "dev"
Requires-Dist: pre-commit==4.6.0; extra == "dev"
Requires-Dist: pyright[nodejs]==1.1.410; extra == "dev"
Requires-Dist: pytest==9.1.1; extra == "dev"
Requires-Dist: pytest-cov==7.1.0; extra == "dev"
Requires-Dist: pytest-benchmark==5.2.3; extra == "dev"
Requires-Dist: hypothesis==6.156.6; extra == "dev"
Requires-Dist: ruff==0.15.17; extra == "dev"
Requires-Dist: setuptools==82.0.1; extra == "dev"
Requires-Dist: tox==4.55.1; extra == "dev"
Requires-Dist: setuptools_scm==10.0.5; extra == "dev"
Provides-Extra: rust
Requires-Dist: abnf-rust<3,>=2.5; extra == "rust"
Provides-Extra: docs
Requires-Dist: sphinx==8.1.3; extra == "docs"
Requires-Dist: myst-parser==4.0.1; extra == "docs"
Requires-Dist: furo==2025.12.19; extra == "docs"
Requires-Dist: sphinx-copybutton==0.5.2; extra == "docs"
Dynamic: license-file

# ABNF

[![PyPI](https://img.shields.io/pypi/v/abnf)](https://pypi.org/project/abnf/)
![abnf-tox](https://github.com/declaresub/abnf/workflows/abnf-tox/badge.svg)
[![CodeQL](https://github.com/declaresub/abnf/actions/workflows/codeql-analysis.yml/badge.svg?branch=master)](https://github.com/declaresub/abnf/actions/workflows/codeql-analysis.yml)
[![Docs](https://readthedocs.org/projects/abnf/badge/?version=latest)](https://abnf.readthedocs.io/en/latest/)

ABNF generates parsers from ABNF grammars as described in
[RFC 5234](https://tools.ietf.org/html/rfc5234) and
[RFC 7405](https://tools.ietf.org/html/rfc7405). Its main purpose is parsing data
specified in RFCs — HTTP headers, email addresses, URIs, and the like — but it
handles any ABNF grammar. It ships with 30+ ready-to-use grammar modules for common
RFCs and has been in production use since it was first written for parsing HTTP
headers in a web framework.

## Installation

```console
pip install abnf
pip install 'abnf[rust]'   # optional Rust backend, for substantially faster parsing
```

ABNF is tested with Python 3.10–3.14.

## Quick start

```python
from abnf.grammars import rfc7232

# parse an ETag header value
node, offset = rfc7232.Rule("ETag").parse('W/"moof"', 0)
print(node.value)          # 'W/"moof"'

# validate a whole string against a rule (raises ParseError otherwise)
from abnf.grammars import rfc5322
rfc5322.Rule("address").parse_all("test@example.com")

# compile your own rule; the RFC 5234 core rules are always available
from abnf import Rule
greeting = Rule.create('greeting = "hello" SP 1*ALPHA')
greeting.parse_all("hello world")
```

## Documentation

Full documentation is hosted at **[abnf.readthedocs.io](https://abnf.readthedocs.io/en/latest/)**
and follows the [Diátaxis](https://diataxis.fr/) framework:

- **Tutorial** — *Parse your first header*, a ten-minute end-to-end walkthrough.
- **How-to guides** — validate input, extract values with visitors, load a grammar
  from a file, write your own grammar module, use the Rust backend.
- **Reference** — the public API, the built-in core rules, the bundled grammars, and
  configuration knobs.
- **Explanation** — the combinator architecture, the two backends, alternation
  semantics, and how backtracking is kept in check.

To build the docs locally:

```console
pip install -e '.[docs]'
sphinx-build -W docs docs/_build/html
```

## Contributing

Set up a development environment with the `dev` extra:

```console
pip install -e '.[dev]'          # or: uv sync --extra dev
```

Run the test suite (skip the slower fuzz tests with `--ignore=tests/fuzz`):

```console
pytest --cov-report term-missing --cov=abnf
```

Pre-commit hooks run ruff, pyright, check-manifest, and tox. Install them once with
`pre-commit install`. See the *Explanation* and *How-to* docs for working with the
Rust backend.

## Third-party packages

- [abnf-to-regexp](https://pypi.org/project/abnf-to-regexp/) — converts ABNF to a
  regular expression.
