Architecture Overview¶
behave-model is built in layers, each with a single responsibility. This design makes the library easy to understand, test, and extend.
Layer diagram¶
graph TD
A[.feature Files] --> B[Parser Layer]
B --> C[Domain Model]
C --> D[Visitors]
C --> E[Queries]
C --> F[Transformations]
C --> G[Serializers]
C --> H[Validation]
C --> I[Statistics]
subgraph "behave_model.parser"
B1[parser.py] --> B2[adapter.py]
B2 --> B3[loader.py]
end
subgraph "behave_model.model"
C1[Project] --> C2[Feature]
C2 --> C3[Rule]
C2 --> C4[Scenario]
C2 --> C5[Background]
C4 --> C6[Step]
C6 --> C7[Table]
C6 --> C8[DocString]
end
Layer details¶
Parser Layer (behave_model.parser)¶
Wraps Behave's built-in parser and converts results into behave-model domain objects.
| Module | Responsibility |
|---|---|
parser.py |
Low-level parse functions (parse_feature, parse_project) |
adapter.py |
Converts behave.model.* objects → behave_model.* objects |
loader.py |
File/directory loading (load_feature, load_project) |
Key design decision: We don't reimplement Gherkin parsing. We reuse Behave's battle-tested parser and adapt its output. This ensures full compatibility with all Gherkin syntax including edge cases.
Domain Model (behave_model.model)¶
Pure frozen dataclasses with no external dependencies. Every node has:
- A
Location(filename, line, column) for traceability - An
accept(visitor)method (for visitable nodes) - Container protocol support (
__len__,__iter__,__getitem__)
| Class | Represents |
|---|---|
Project |
Root container for all features |
Feature |
A single .feature file |
Rule |
Gherkin v6 Rule block |
Background |
Shared steps before each scenario |
Scenario |
A concrete scenario |
ScenarioOutline |
A data-driven scenario with Examples |
Step |
A Given/When/Then step |
Table |
A data table |
TableRow |
A row in a data table |
Tag |
A tag label |
DocString |
A multi-line text block |
Examples |
Examples block for ScenarioOutline |
Location |
Source location (filename, line, column) |
Comment |
A comment line |
Metadata |
Optional metadata container |
Visitors (behave_model.visitors)¶
Generic visitor pattern for tree traversal.
| Class | Description |
|---|---|
Visitor |
Base class — override visit_* methods |
CountingVisitor |
Counts nodes by type |
CollectingVisitor |
Collects nodes by type into lists |
Queries (behave_model.queries)¶
High-level filtering functions mixed into Project:
find_feature(name)— Find feature by exact namefind_tag(name)— Find tag by exact namefind_scenarios(tag=, name=, name_contains=)— Filter scenariosfind_steps(keyword=, text_contains=)— Filter stepsfind_features_with_tag(tag)— Features with a tagfind_scenarios_with_tag(tag)— Scenarios with a tagfind_outlines()— All Scenario Outlinesfind_plain_scenarios()— All plain Scenarios
Transformations (behave_model.transformations)¶
Safe, in-place mutations that preserve semantic meaning:
rename_tag,rename_scenariosort_tags,sort_features,sort_scenariosnormalize_whitespaceremove_tag,add_tag_to_feature
Serializers (behave_model.serializers)¶
| Serializer | Output format |
|---|---|
DictSerializer |
Python dict |
JsonSerializer |
JSON string |
PrettyPrinter |
Gherkin .feature text |
Validation (behave_model.validation)¶
Pluggable rule framework with built-in rules:
| Rule | Severity |
|---|---|
DuplicateScenarioNamesRule |
error |
DuplicateFeatureNamesRule |
error |
EmptyScenarioRule |
warning |
EmptyFeatureRule |
warning |
InvalidTableRule |
error |
Custom rules extend ValidationRule and implement check(project).
Data flow¶
sequenceDiagram
participant User
participant Loader
participant Parser
participant Adapter
participant Model
User->>Loader: load_project("features/")
Loader->>Parser: parse_feature(text)
Parser-->>Loader: behave.model.Feature
Loader->>Adapter: adapt_feature(bf)
Adapter-->>Loader: behave_model.Feature
Loader->>Model: Project(features=[...])
Model-->>User: Project
Module dependencies¶
graph TD
M[model] --> E[exceptions]
P[parser] --> M
P --> E
V[visitors] --> M
Q[queries] --> M
S[serializers] --> M
S --> E
T[transformations] --> M
T --> E
VAL[validation] --> M
VAL --> E
INIT[__init__] --> M
INIT --> P
INIT --> V
INIT --> Q
INIT --> S
INIT --> T
INIT --> VAL
The model package has zero dependencies on other behave_model packages. All other packages depend on model and exceptions only.
Next steps¶
- Design Decisions — Why things are the way they are
- Domain Model Guide — Detailed guide to every class
- API Reference — Complete API documentation