pbt4automata
pbt4automata provides tools to construct finite automata and context-free grammars in Python and validate their behavior with property-based tests powered by Hypothesis.
Installation
pip install -e .
Examples
Deterministic Finite Automata
Testing a DFA against a rule
The following example tests a DFA that accepts all strings that contain the substring "010" or "100".
from pbt4automata import DFA
automaton = DFA(
states=["q0", "q1", "q2", "q3", "q4", "q5"],
alphabet="01",
transition_function={
("q0", "0"): "q1",
("q0", "1"): "q4",
("q1", "0"): "q1",
("q1", "1"): "q2",
("q2", "0"): "q3",
("q2", "1"): "q4",
("q3", "0"): "q3",
("q3", "1"): "q3",
("q4", "0"): "q5",
("q4", "1"): "q4",
("q5", "0"): "q3",
("q5", "1"): "q2",
},
start_state="q0",
accept_states=["q3"],
)
result = automaton.test("[01]*(010|100)[01]*")
if result is True:
print("Success!")
else:
print("Counterexample:", result)
You can also pass a function of type Callable[[str], bool] to automaton.test(...) instead of a regex.
Testing two DFAs for equivalence
from pbt4automata import Automaton, DFA
automata1 = DFA(
...
)
automata2 = DFA(
...
)
result = Automaton.test_equivalence(automata1, automata2)
if result is True:
print("Success!")
else:
print("Counterexample:", repr(result))
Nondeterministic Finite Automata
Testing an NFA against a rule
NFAs support nondeterministic transitions (multiple possible next states for a given state and symbol) as well as epsilon (ε) transitions. The transition function maps (state, symbol) pairs to sets of states; use None as the symbol for ε-transitions. Unlike DFAs, the transition function may be partial.
The following example tests an NFA that accepts all strings over {0, 1} that end with the substring "01".
from pbt4automata import NFA
nfa = NFA(
states=["q0", "q1", "q2"],
alphabet="01",
transition_function={
("q0", "0"): {"q0", "q1"}, # nondeterministically guess start of "01"
("q0", "1"): {"q0"},
("q1", "1"): {"q2"},
},
start_state="q0",
accept_states=["q2"],
)
result = nfa.test("[01]*01")
if result is True:
print("Success!")
else:
print("Counterexample:", result)
You can also pass a function of type Callable[[str], bool] to nfa.test(...) instead of a regex.
NFA with epsilon transitions
from pbt4automata import NFA
# Accepts "a" or "ab"
nfa = NFA(
states=["q0", "q1", "q2", "q3"],
alphabet="ab",
transition_function={
("q0", "a"): {"q1"},
("q1", None): {"q2"}, # ε-transition: q1 is also effectively q2
("q1", "b"): {"q3"},
},
start_state="q0",
accept_states=["q2", "q3"],
)
Testing an NFA for equivalence with another automaton
Automaton.test_equivalence works with any mix of DFA and NFA objects sharing the same alphabet.
from pbt4automata import Automaton, DFA, NFA
nfa = NFA(...)
dfa = DFA(...)
result = Automaton.test_equivalence(nfa, dfa)
if result is True:
print("Success!")
else:
print("Counterexample:", repr(result))
Context-Free Grammars
Testing a CFG against a rule
The following example tests a CFG that generates all non-empty strings of balanced parentheses.
from pbt4automata import Grammar
grammar = Grammar(
terminals="()",
nonterminals="S",
productions={
"S": ["(S)", "SS", "()"],
},
start_symbol="S",
)
def check_balance(input_string: str) -> bool:
if input_string == "":
return False
s = 0
for c in input_string:
if c == "(":
s += 1
elif c == ")":
s -= 1
if s < 0:
return False
return s == 0
result = grammar.test(check_balance)
if result is True:
print("Success!")
else:
print("Counterexample:", result)
You can also pass a function of type Callable[[str], bool] to grammar.test(...).
Parsing strings
from pbt4automata import Grammar
# Grammar for "a^n b^n" (n ≥ 1): S → aSb | ab
grammar = Grammar(
terminals="ab",
nonterminals="S",
productions={
"S": ["aSb", "ab"],
},
start_symbol="S",
)
print(grammar.parse("ab")) # True
print(grammar.parse("aabb")) # True
print(grammar.parse("aaabbb")) # True
print(grammar.parse("aab")) # False
Development
Install dev dependencies and run tests:
pip install -e ".[dev]"
pytest -v
Metadata
Release files for pbt4automata 0.2.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 | Provenance | |
|---|---|---|---|---|
| pbt4automata-0.2.1.tar.gz | 16.4 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pbt4automata-0.2.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 26.3 kB
Release files / pbt4automata-0.2.1.tar.gz
| Download URL | pbt4automata-0.2.1.tar.gz |
|---|---|
| Size | 16.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
88e09d8e7625e5c14c0bf99dd2ddb19f2534accb9ffcd3005d28923104edd1de
|
|
BLAKE2b-256 checksum How to use checksums |
5a0e0a38ea874a8a4f75b6ece90aca2059cb32dae260fd6fcd79e18ad3d61311
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
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 Mar 22, 2026.
Transparency logRelease files / pbt4automata-0.2.1-py3-none-any.whl
| Download URL | pbt4automata-0.2.1-py3-none-any.whl |
|---|---|
| Size | 9.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4026072772a155b3801219f0b2b57f28c14962abe75c55deddf265c0b6359148
|
|
BLAKE2b-256 checksum How to use checksums |
86c12955d10752a65a9339210bb2ea298c4cf4f712644ffdc6b4dbccb6631fd3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
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 Mar 22, 2026.
Transparency logSecurity for pbt4automata 0.2.1
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.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for pbt4automata-0.2.1.tar.gz
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 Mar 22, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.