Canonical object model for Behave projects
Project description
behave-model
The canonical object model for Behave projects.
behave-model provides a clean, stable, and extensible Python API that represents every element of a Behave project — features, rules, scenarios, steps, tags, tables, docstrings, and more. It is the foundation for an entire ecosystem of tools: formatters, linters, analyzers, report generators, and anything else that needs to understand .feature files.
Why?
Every Behave tooling project currently parses .feature files independently. behave-model provides a single, well-tested domain model so that future tools can depend on it instead of reinventing the parser.
- Compatible with Behave 1.3.x — Tag Expression v2 and Gherkin v6 (including
Ruleblocks) - Clean domain model — Pure dataclasses, no external runtime dependencies beyond Behave
- Visitor pattern — Traverse the entire tree with custom visitors
- Query API — Find features, scenarios, steps, and tags by name, tag, or keyword
- Serializers — Dict, JSON, and pretty-printed Gherkin output
- Transformations — Safe in-place modifications (rename tags, sort, normalize)
- Validation framework — Pluggable rules with built-in checks
- 95% test coverage — Comprehensive unit, integration, and golden file tests
Installation
pip install behave-model
For development:
pip install -e ".[dev]"
Quick Start
from behave_model import load_project
# Load all .feature files from a directory
project = load_project("features/")
# Access features, rules, and scenarios
print(len(project.features)) # number of features
print(project.features[0].name) # first feature name
print(len(project.features[0].rules)) # rules (Gherkin v6)
# Query the model
for scenario in project.find_scenarios(tag="@smoke"):
print(scenario.name)
# Statistics
stats = project.statistics()
print(f"{stats['features']} features, {stats['scenarios']} scenarios, {stats['steps']} steps")
# Traverse the tree
for node in project.walk():
print(type(node).__name__)
Domain Model
Project
├── Metadata
├── Feature
│ ├── Tag
│ ├── Background
│ │ └── Step
│ ├── Scenario
│ │ ├── Tag
│ │ └── Step
│ ├── ScenarioOutline
│ │ ├── Tag
│ │ ├── Step
│ │ └── Examples
│ │ └── Table
│ └── Rule (Gherkin v6)
│ ├── Tag
│ ├── Background
│ │ └── Step
│ ├── Scenario
│ └── ScenarioOutline
└── ...
Every node has a Location (filename, line, column) for precise source mapping.
Features at a Glance
Loading
from behave_model import load_project, load_feature
project = load_project("features/") # all .feature files
feature = load_feature("features/login.feature") # single file
Visitor Pattern
from behave_model import Visitor
class StepCounter(Visitor):
def __init__(self):
self.count = 0
def visit_step(self, step):
self.count += 1
visitor = StepCounter()
project.accept(visitor)
print(f"Total steps: {visitor.count}")
Query API
project.find_feature("Login")
project.find_tag("@smoke")
project.find_scenarios(tag="@api")
project.find_scenarios(name_contains="login")
project.find_steps(keyword="Given")
project.find_steps(text_contains="user")
Serialization
from behave_model import JsonSerializer, DictSerializer, PrettyPrinter
# JSON
json_str = JsonSerializer().serialize_project(project)
# Dictionary
data = DictSerializer().serialize_project(project)
# Pretty-printed Gherkin
text = PrettyPrinter().print_feature(feature)
Transformations
from behave_model import rename_tag, sort_tags, normalize_whitespace
rename_tag(project, "@smoke", "@critical")
sort_tags(project)
normalize_whitespace(project)
Validation
from behave_model import Validator
validator = Validator()
issues = validator.validate(project)
for issue in issues:
print(f"[{issue.severity}] {issue.rule_name}: {issue.message}")
Architecture
Feature File → Parser Adapter → Domain Model → Visitors → Queries → Transformations → Serializers
The Domain Model never depends on report generation or formatting. Each layer has a single responsibility and can be used independently.
| Layer | Package | Responsibility |
|---|---|---|
| Parser Adapter | behave_model.parser |
Wraps Behave's parser, adapts to domain model |
| Domain Model | behave_model.model |
Pure dataclasses for every Gherkin element |
| Visitors | behave_model.visitors |
Generic traversal pattern |
| Queries | behave_model.queries |
High-level filtering API |
| Transformations | behave_model.transformations |
Safe in-place modifications |
| Serializers | behave_model.serializers |
Dict, JSON, Gherkin output |
| Validation | behave_model.validation |
Pluggable rule framework |
Compatibility
| Feature | Supported |
|---|---|
| Behave 1.3.x | ✅ |
| Tag Expression v1 | ✅ |
| Tag Expression v2 | ✅ |
| Gherkin v6 (Rules) | ✅ |
| Scenario Outlines | ✅ |
| Data Tables | ✅ |
| DocStrings | ✅ |
| Background | ✅ |
| Multi-language features | ✅ |
Development
# Clone and install
git clone https://github.com/MathiasPaulenko/behave-model.git
cd behave-model
pip install -e ".[dev]"
# Run tests
make test
# Run tests with coverage
make coverage
# Lint
make lint
# Format
make format
# Build
make build
Documentation
Full documentation is available at mathiaspaulenko.github.io/behave-model.
Contributing
Contributions are welcome! See CONTRIBUTING.md for guidelines.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file behave_model-1.0.0.tar.gz.
File metadata
- Download URL: behave_model-1.0.0.tar.gz
- Upload date:
- Size: 38.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5ed612885400971f0478239f7df96b61bbb31054f53a09bee10b6e3524d8c2df
|
|
| MD5 |
f3a5d9e76439ff6a4b1707ecb269e477
|
|
| BLAKE2b-256 |
0555a9ddada9af2fbf2f8d46f7f8943327597823cf19ebabc3839c188aa73a12
|
Provenance
The following attestation bundles were made for behave_model-1.0.0.tar.gz:
Publisher:
release.yml on MathiasPaulenko/behave-model
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
behave_model-1.0.0.tar.gz -
Subject digest:
5ed612885400971f0478239f7df96b61bbb31054f53a09bee10b6e3524d8c2df - Sigstore transparency entry: 2038602434
- Sigstore integration time:
-
Permalink:
MathiasPaulenko/behave-model@932cd90a0034d6bf334f95afdab4c63abc689cf1 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/MathiasPaulenko
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@932cd90a0034d6bf334f95afdab4c63abc689cf1 -
Trigger Event:
push
-
Statement type:
File details
Details for the file behave_model-1.0.0-py3-none-any.whl.
File metadata
- Download URL: behave_model-1.0.0-py3-none-any.whl
- Upload date:
- Size: 34.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a5089a342caf15bcf550095af4aa898b9de117ed34e695f09e3adee61ad5c5fc
|
|
| MD5 |
c67737fb51d1f9e86a84b6d60460d458
|
|
| BLAKE2b-256 |
f124b5716a5a83d12d2dc0a67b212943881837bac6bdb91a89ee43d66d3ae209
|
Provenance
The following attestation bundles were made for behave_model-1.0.0-py3-none-any.whl:
Publisher:
release.yml on MathiasPaulenko/behave-model
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
behave_model-1.0.0-py3-none-any.whl -
Subject digest:
a5089a342caf15bcf550095af4aa898b9de117ed34e695f09e3adee61ad5c5fc - Sigstore transparency entry: 2038602537
- Sigstore integration time:
-
Permalink:
MathiasPaulenko/behave-model@932cd90a0034d6bf334f95afdab4c63abc689cf1 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/MathiasPaulenko
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@932cd90a0034d6bf334f95afdab4c63abc689cf1 -
Trigger Event:
push
-
Statement type: