The opinionated formatter for Behave .feature files
Project description
behave-format
The opinionated formatter for Behave
.featurefiles.
Black is for Python. gofmt is for Go. behave-format is for Gherkin.
Overview
behave-format is a deterministic, opinionated formatter for Behave .feature files. It consumes the canonical domain model from behave-model and produces clean, consistent, beautifully formatted output.
Key principle: behave-format does NOT parse Gherkin. It does NOT lint. It does NOT validate. It ONLY transforms a behave-model.Project into formatted .feature files.
.feature files → behave-model (domain model) → behave-format → formatted .feature files
Features
- Opinionated — minimal configuration, sensible defaults
- Deterministic — same input always produces same output
- Idempotent —
format(format(x)) == format(x) - Fast — handles thousands of feature files efficiently
- CI-friendly —
--checkmode with exit code 1 when formatting is needed - Safe — never changes semantics (names, step text, table values, docstrings)
Installation
pip install behave-format
Quick Start
CLI
# Format files in place (default)
behave-format features/
# Check mode (CI) — exit 1 if formatting is needed
behave-format --check features/
# Diff mode — show differences without writing
behave-format --diff features/
Python API
from behave_model import load_project
from behave_format import format_project, render_project, Settings
project = load_project("features/")
# Format the project model in place
format_project(project)
# Or render to text
text = render_project(project, Settings())
Formatting Rules
Tags
Tags are sorted alphabetically by default:
@api @smoke
Features
- One blank line before each Feature
- Clean title formatting
Scenarios
- One blank line before each Scenario
- Two-space indentation for steps
Given user exists
When user logs in
Then dashboard is shown
Tables
Tables are always aligned:
Before:
|user|password|
|john|123|
After:
| user | password |
| john | 123 |
Blank Lines
- No trailing blank lines
- No multiple consecutive empty lines
- Consistent spacing between blocks
Indentation
- Spaces only (no tabs)
- Default: 2 spaces
Configuration
Minimal configuration via pyproject.toml:
[tool.behave-format]
indent = 2
sort_tags = true
sort_features = false
sort_scenarios = false
line_length = 120
| Option | Default | Description |
|---|---|---|
indent |
2 |
Number of spaces for indentation |
sort_tags |
true |
Sort tags alphabetically |
sort_features |
false |
Sort features by name |
sort_scenarios |
false |
Sort scenarios by name |
line_length |
120 |
Maximum line length (reference) |
Before / After
Before
@smoke @auth
Feature: Login
As a user
I want to log in
Background:
Given a database connection
@happy
Scenario: Successful login
Given the user is on the login page
When the user enters "admin" and "password"
Then the user should be logged in
After
@auth @smoke
Feature: Login
As a user
I want to log in
Background:
Given a database connection
@happy
Scenario: Successful login
Given the user is on the login page
When the user enters "admin" and "password"
Then the user should be logged in
Architecture
behave_format/
├── config/
│ └── settings.py # Settings dataclass + pyproject.toml loader
├── pipeline/
│ ├── normalize.py # Whitespace, indentation, tag normalization
│ ├── sort.py # Sort tags, features, scenarios
│ ├── align.py # Table alignment, trailing whitespace
│ ├── rules.py # Formatting rules registry
│ └── formatter.py # Main orchestrator (format_project)
├── printer/
│ ├── feature_printer.py
│ ├── scenario_printer.py
│ ├── step_printer.py
│ ├── table_printer.py
│ └── tag_printer.py
└── cli/
└── main.py # CLI entry point
Pipeline
- Normalize — clean whitespace, standardize indentation, normalize tags
- Sort — order tags (alphabetically by default), optionally features and scenarios
- Align — align table columns, remove trailing spaces
- Print — convert
behave-model→.featuretext (deterministic)
Safety
The formatter NEVER changes semantics:
- Feature names: preserved
- Scenario names: preserved
- Step text: preserved (only whitespace normalized)
- DocString content: preserved
- Table values: preserved (only alignment changes)
- Comments content: preserved
Integration
behave-format integrates naturally with the Behave ecosystem:
- behave-model — single source of truth
- behave-lint — linting
- behave-modern-json-report
- behave-modern-report
- behave-markdown-report
Development
pip install -e ".[dev]"
pytest tests/ -v
ruff check .
ruff format --check .
Contributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Run
ruff check .andpytest tests/before submitting - Open a Pull Request
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_format-1.0.0.tar.gz.
File metadata
- Download URL: behave_format-1.0.0.tar.gz
- Upload date:
- Size: 21.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
139b5c6320a42cf1e6030f01b24c405ae8d679707695c191f6892b20b1145b93
|
|
| MD5 |
df45dc93ac99a95b5cf1f27cfb1eba03
|
|
| BLAKE2b-256 |
d7181c928a243131a2c4f6e73974576f880afca7b90045057ef86f8abf668333
|
Provenance
The following attestation bundles were made for behave_format-1.0.0.tar.gz:
Publisher:
release.yml on MathiasPaulenko/behave-format
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
behave_format-1.0.0.tar.gz -
Subject digest:
139b5c6320a42cf1e6030f01b24c405ae8d679707695c191f6892b20b1145b93 - Sigstore transparency entry: 2039524101
- Sigstore integration time:
-
Permalink:
MathiasPaulenko/behave-format@4b9fc484cdd6038f8ab15e39e008d91ac0b204e5 -
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@4b9fc484cdd6038f8ab15e39e008d91ac0b204e5 -
Trigger Event:
push
-
Statement type:
File details
Details for the file behave_format-1.0.0-py3-none-any.whl.
File metadata
- Download URL: behave_format-1.0.0-py3-none-any.whl
- Upload date:
- Size: 17.1 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 |
7b0f10b3e46a8d7de8d8fc3587464ab8ae255eda758c1bfd4da0ff222a860c95
|
|
| MD5 |
b436935cc3723794b4d51313898c2bb2
|
|
| BLAKE2b-256 |
a482bacc8baee950cc0f306dfe3bdaebee4fc19fcbed736781cec65aea44c167
|
Provenance
The following attestation bundles were made for behave_format-1.0.0-py3-none-any.whl:
Publisher:
release.yml on MathiasPaulenko/behave-format
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
behave_format-1.0.0-py3-none-any.whl -
Subject digest:
7b0f10b3e46a8d7de8d8fc3587464ab8ae255eda758c1bfd4da0ff222a860c95 - Sigstore transparency entry: 2039524200
- Sigstore integration time:
-
Permalink:
MathiasPaulenko/behave-format@4b9fc484cdd6038f8ab15e39e008d91ac0b204e5 -
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@4b9fc484cdd6038f8ab15e39e008d91ac0b204e5 -
Trigger Event:
push
-
Statement type: