Edify builds regular expressions you can actually read. It’s a fluent, immutable regex builder for Python: you describe a pattern step by step in plain English, and Edify hands you a compiled regex — one your teammates can review in a pull request instead of squinting at.
Why Edify
A regular expression is easy to write and hard to read. Six months later nobody remembers what ^(?:0x)?([0-9a-fA-F]{4})$ was meant to accept, and the person reviewing the change that touches it has no way to be sure either. The syntax gives you nowhere to put a name, a comment, or a seam.
Edify moves the pattern into ordinary Python, where all three fit:
Methods say what they do. .one_or_more().digit() needs no decoding.
The quantity comes before the thing it counts, the way you say it aloud — .exactly(4).digit() is exactly four digits.
Every call returns a new builder, so a pattern you share can be extended in two directions without either one disturbing the other.
A mistake raises an error that points at the call that caused it and names the fix, rather than emitting a regex that is subtly wrong.
A first pattern
from edify import RegexBuilder
# A 16-bit hex literal like "0xC0DE" — with the four hex digits captured.
hex_literal = (
RegexBuilder()
.start_of_input()
.optional().string("0x")
.capture()
.exactly(4).any_of().range("0", "9").range("a", "f").range("A", "F").end()
.end()
.end_of_input()
)
hex_literal.to_regex_string() # '^(?:0x)?([0-9a-fA-F]{4})$'
hex_literal.test("0xC0DE") # True
hex_literal.test("0xZZZZ") # False
Read the chain top to bottom and it tells you what it accepts.
Patterns you don’t have to write
Edify ships 228 ready-made validators. Each is a callable pattern, so checking a value is a function call:
from edify.library import email, ipv4, semver
email("a@b.com") # True
semver("1.4.0") # True
ipv4("10.0.0.1") # True
ipv4("999.1.1.1") # False — the octet range is enforced
They are assembled from 83 named fragments you can build with too, so a pattern of your own inherits the same range checks rather than approximating them:
from edify import Pattern, atoms
endpoint = (
Pattern().start_of_input()
.named_capture("host").use(atoms.ipv4).end()
.char(":")
.named_capture("port").use(atoms.port).end()
.end_of_input()
)
endpoint.to_regex().match("10.0.0.1:8080").groupdict()
# {'host': '10.0.0.1', 'port': '8080'}
endpoint("10.0.0.1:99999") # False — 99999 is not a port
Ask a pattern what it means
Because Edify keeps the structure rather than a string, it can describe a pattern back to you — in prose, as a diagram, or as an annotated verbose regex:
from edify import RegexBuilder
year = RegexBuilder().start_of_input().exactly(4).digit().end_of_input()
print(year.to_regex().explain())
# - The text must start with exactly 4 digits (0-9).
#
# Text this pattern accepts:
# 1234
That same structure is what lets Edify warn you at build time about a pattern shaped for catastrophic backtracking — and the warning names the fix, because atomic groups and possessive quantifiers are chain methods like everything else. It is also what lets a pattern round-trip through JSON.
Install
Edify requires Python 3.11+:
pip install edify
Optional extras add the alternate regex engine and the framework integrations: edify[regex], edify[pydantic], edify[fastapi], edify[django], or edify[all].
Also in the box
Introspection — a plain-English explanation, an ASCII or rendered diagram, or an annotated re.VERBOSE form of any pattern.
Serialization — round-trip a pattern through a dict or JSON and keep a first-class pattern on the other side, not a flattened string.
Integrations — pydantic, FastAPI, and Django validators from a pattern.
Testing helpers — assert a pattern’s contract beside its definition, and snapshot what it emits.
Reverse parsing — turn an existing regex string back into a chain and read what it does.
Unicode-aware classes — say “any letter” and mean it, in any script, rather than settling for [a-zA-Z] or a \w that also admits digits.
Documentation
edify.readthedocs.io has the guide, a page for every validator, and the full API reference. Examples throughout the site are live — edit the chain and the emitted regex and match results update as you type, with Edify running in your browser.
License and contributing
Edify is released under the MIT License. Contributions are welcome — see CONTRIBUTING.rst to get set up.
Metadata
Release files for edify 1.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| edify-1.1.1.tar.gz | 559.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| edify-1.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 837.1 kB
Release files / edify-1.1.1.tar.gz
| Download URL | edify-1.1.1.tar.gz |
|---|---|
| Size | 559.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6b1b53c7ba5d87f6ec796d6f6accc2c05d2489a233de833c615dad37fd1db323
|
|
BLAKE2b-256 checksum How to use checksums |
926bef4d55c79c46fb80a6e20ada3c47313a152689bf0942dff7c41ff8284444
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 6, 2026.
Transparency logRelease files / edify-1.1.1-py3-none-any.whl
| Download URL | edify-1.1.1-py3-none-any.whl |
|---|---|
| Size | 277.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
514da9a61c252aabf8e6d05c1e21391b4faf3a3dd6851823e5b91021d2dc5f4b
|
|
BLAKE2b-256 checksum How to use checksums |
0e39adbacac6c05c4fdec9dcd9ef9f631bd578d9447351c3fdadc1114dc75447
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 6, 2026.
Transparency log