behave-format
The opinionated formatter for Behave
.featurefiles.
Black is for Python. gofmt is for Go. behave-format is for Gherkin.
Documentation: https://mathiaspaulenko.github.io/behave-format/
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 — wraps long tag lines |
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
├── loader.py # Parse via behave-model + restore comments/keywords
├── pipeline/
│ ├── normalize.py # Whitespace, indentation, tag normalization
│ ├── sort.py # Sort tags, features, scenarios
│ ├── align.py # Table alignment, trailing whitespace
│ └── 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
Metadata
Release files for behave-format 1.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| behave_format-1.2.0.tar.gz | 45.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| behave_format-1.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 69.7 kB
Release files / behave_format-1.2.0.tar.gz
| Download URL | behave_format-1.2.0.tar.gz |
|---|---|
| Size | 45.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c0f9b3c6434da4a32320c934775af3d559b233149f80a4de0930da7c90b157ab
|
|
BLAKE2b-256 checksum How to use checksums |
d3f5212363faec8790cd08a863c693cfc96ab42d7af61204c0fc52641eaeb55d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Oct 15, 2026.
Transparency logRelease files / behave_format-1.2.0-py3-none-any.whl
| Download URL | behave_format-1.2.0-py3-none-any.whl |
|---|---|
| Size | 23.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f8ee40ed5730931968a5d97d242493172c6ee9899f64848fdc63d7aba51bfb7b
|
|
BLAKE2b-256 checksum How to use checksums |
69eb28a32216f728b1ec450aeafb5203da13e1d20a0d9e94f037c43378efc3ea
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Oct 15, 2026.
Transparency log