behave-format 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- behave_format-1.0.0/.github/workflows/ci.yml +47 -0
- behave_format-1.0.0/.github/workflows/docs.yml +53 -0
- behave_format-1.0.0/.github/workflows/release.yml +86 -0
- behave_format-1.0.0/.gitignore +20 -0
- behave_format-1.0.0/.pre-commit-config.yaml +7 -0
- behave_format-1.0.0/CHANGELOG.md +24 -0
- behave_format-1.0.0/LICENSE +21 -0
- behave_format-1.0.0/Makefile +37 -0
- behave_format-1.0.0/PKG-INFO +280 -0
- behave_format-1.0.0/README.md +248 -0
- behave_format-1.0.0/behave_format/__init__.py +41 -0
- behave_format-1.0.0/behave_format/cli/__init__.py +1 -0
- behave_format-1.0.0/behave_format/cli/main.py +175 -0
- behave_format-1.0.0/behave_format/config/__init__.py +1 -0
- behave_format-1.0.0/behave_format/config/settings.py +81 -0
- behave_format-1.0.0/behave_format/pipeline/__init__.py +1 -0
- behave_format-1.0.0/behave_format/pipeline/align.py +69 -0
- behave_format-1.0.0/behave_format/pipeline/formatter.py +96 -0
- behave_format-1.0.0/behave_format/pipeline/normalize.py +124 -0
- behave_format-1.0.0/behave_format/pipeline/rules.py +31 -0
- behave_format-1.0.0/behave_format/pipeline/sort.py +65 -0
- behave_format-1.0.0/behave_format/printer/__init__.py +1 -0
- behave_format-1.0.0/behave_format/printer/feature_printer.py +93 -0
- behave_format-1.0.0/behave_format/printer/scenario_printer.py +117 -0
- behave_format-1.0.0/behave_format/printer/step_printer.py +46 -0
- behave_format-1.0.0/behave_format/printer/table_printer.py +47 -0
- behave_format-1.0.0/behave_format/printer/tag_printer.py +21 -0
- behave_format-1.0.0/conftest.py +12 -0
- behave_format-1.0.0/docs/api/formatter.md +3 -0
- behave_format-1.0.0/docs/api/overview.md +18 -0
- behave_format-1.0.0/docs/api/pipeline.md +17 -0
- behave_format-1.0.0/docs/api/printers.md +21 -0
- behave_format-1.0.0/docs/api/settings.md +3 -0
- behave_format-1.0.0/docs/architecture.md +47 -0
- behave_format-1.0.0/docs/changelog.md +3 -0
- behave_format-1.0.0/docs/contributing.md +40 -0
- behave_format-1.0.0/docs/design_decisions.md +26 -0
- behave_format-1.0.0/docs/examples.md +76 -0
- behave_format-1.0.0/docs/getting-started/installation.md +20 -0
- behave_format-1.0.0/docs/getting-started/quick_start.md +29 -0
- behave_format-1.0.0/docs/guides/cli_usage.md +48 -0
- behave_format-1.0.0/docs/guides/configuration.md +42 -0
- behave_format-1.0.0/docs/guides/formatting_rules.md +54 -0
- behave_format-1.0.0/docs/guides/pipeline.md +45 -0
- behave_format-1.0.0/docs/guides/python_api.md +63 -0
- behave_format-1.0.0/docs/index.md +25 -0
- behave_format-1.0.0/examples/data_tables.feature +20 -0
- behave_format-1.0.0/examples/login.feature +35 -0
- behave_format-1.0.0/examples/rules.feature +36 -0
- behave_format-1.0.0/examples/shopping_cart.feature +30 -0
- behave_format-1.0.0/mkdocs.yml +80 -0
- behave_format-1.0.0/pyproject.toml +81 -0
- behave_format-1.0.0/tests/conftest.py +27 -0
- behave_format-1.0.0/tests/golden/data_tables_expected.feature +20 -0
- behave_format-1.0.0/tests/golden/login_expected.feature +35 -0
- behave_format-1.0.0/tests/golden/rules_expected.feature +36 -0
- behave_format-1.0.0/tests/golden/shopping_cart_expected.feature +30 -0
- behave_format-1.0.0/tests/test_cli.py +113 -0
- behave_format-1.0.0/tests/test_formatting.py +89 -0
- behave_format-1.0.0/tests/test_golden.py +36 -0
- behave_format-1.0.0/tests/test_idempotency.py +73 -0
- behave_format-1.0.0/tests/test_performance.py +67 -0
- behave_format-1.0.0/tox.ini +22 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, master]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main, master]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
lint:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
- uses: actions/setup-python@v5
|
|
15
|
+
with:
|
|
16
|
+
python-version: "3.11"
|
|
17
|
+
- run: pip install ruff
|
|
18
|
+
- run: ruff check behave_format/ tests/
|
|
19
|
+
- run: ruff format --check behave_format/ tests/
|
|
20
|
+
|
|
21
|
+
test:
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
strategy:
|
|
24
|
+
matrix:
|
|
25
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
26
|
+
steps:
|
|
27
|
+
- uses: actions/checkout@v4
|
|
28
|
+
- uses: actions/setup-python@v5
|
|
29
|
+
with:
|
|
30
|
+
python-version: ${{ matrix.python-version }}
|
|
31
|
+
- run: pip install -e ".[dev]"
|
|
32
|
+
- run: python -m pytest tests/ --cov=behave_format --cov-report=xml --cov-report=term
|
|
33
|
+
- uses: codecov/codecov-action@v4
|
|
34
|
+
with:
|
|
35
|
+
file: ./coverage.xml
|
|
36
|
+
fail_ci_if_error: false
|
|
37
|
+
|
|
38
|
+
packaging:
|
|
39
|
+
runs-on: ubuntu-latest
|
|
40
|
+
steps:
|
|
41
|
+
- uses: actions/checkout@v4
|
|
42
|
+
- uses: actions/setup-python@v5
|
|
43
|
+
with:
|
|
44
|
+
python-version: "3.11"
|
|
45
|
+
- run: pip install build twine
|
|
46
|
+
- run: python -m build
|
|
47
|
+
- run: python -m twine check dist/*
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
name: Docs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
paths:
|
|
8
|
+
- "docs/**"
|
|
9
|
+
- "mkdocs.yml"
|
|
10
|
+
- "README.md"
|
|
11
|
+
workflow_dispatch:
|
|
12
|
+
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
pages: write
|
|
16
|
+
id-token: write
|
|
17
|
+
|
|
18
|
+
concurrency:
|
|
19
|
+
group: "pages"
|
|
20
|
+
cancel-in-progress: false
|
|
21
|
+
|
|
22
|
+
jobs:
|
|
23
|
+
build:
|
|
24
|
+
runs-on: ubuntu-latest
|
|
25
|
+
steps:
|
|
26
|
+
- uses: actions/checkout@v4
|
|
27
|
+
|
|
28
|
+
- uses: actions/setup-python@v5
|
|
29
|
+
with:
|
|
30
|
+
python-version: "3.12"
|
|
31
|
+
|
|
32
|
+
- name: Install MkDocs
|
|
33
|
+
run: pip install mkdocs mkdocs-material
|
|
34
|
+
|
|
35
|
+
- name: Build site
|
|
36
|
+
run: mkdocs build
|
|
37
|
+
|
|
38
|
+
- name: Upload artifact
|
|
39
|
+
uses: actions/upload-pages-artifact@v3
|
|
40
|
+
with:
|
|
41
|
+
path: site
|
|
42
|
+
|
|
43
|
+
deploy:
|
|
44
|
+
needs: build
|
|
45
|
+
runs-on: ubuntu-latest
|
|
46
|
+
environment:
|
|
47
|
+
name: github-pages
|
|
48
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
49
|
+
continue-on-error: true
|
|
50
|
+
steps:
|
|
51
|
+
- name: Deploy to GitHub Pages
|
|
52
|
+
id: deployment
|
|
53
|
+
uses: actions/deploy-pages@v4
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: write
|
|
10
|
+
id-token: write
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
test:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
strategy:
|
|
16
|
+
matrix:
|
|
17
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
- uses: actions/setup-python@v5
|
|
21
|
+
with:
|
|
22
|
+
python-version: ${{ matrix.python-version }}
|
|
23
|
+
- run: pip install -e ".[dev]"
|
|
24
|
+
- run: python -m pytest tests/ --cov=behave_format --cov-report=term
|
|
25
|
+
|
|
26
|
+
build:
|
|
27
|
+
needs: test
|
|
28
|
+
runs-on: ubuntu-latest
|
|
29
|
+
steps:
|
|
30
|
+
- uses: actions/checkout@v4
|
|
31
|
+
|
|
32
|
+
- uses: actions/setup-python@v5
|
|
33
|
+
with:
|
|
34
|
+
python-version: "3.12"
|
|
35
|
+
|
|
36
|
+
- name: Install build dependencies
|
|
37
|
+
run: pip install build twine
|
|
38
|
+
|
|
39
|
+
- name: Build distributions
|
|
40
|
+
run: python -m build
|
|
41
|
+
|
|
42
|
+
- name: Check distributions
|
|
43
|
+
run: python -m twine check dist/*
|
|
44
|
+
|
|
45
|
+
- name: Upload distributions
|
|
46
|
+
uses: actions/upload-artifact@v4
|
|
47
|
+
with:
|
|
48
|
+
name: dist
|
|
49
|
+
path: dist/
|
|
50
|
+
|
|
51
|
+
publish-pypi:
|
|
52
|
+
needs: build
|
|
53
|
+
runs-on: ubuntu-latest
|
|
54
|
+
environment: pypi
|
|
55
|
+
permissions:
|
|
56
|
+
id-token: write
|
|
57
|
+
continue-on-error: true
|
|
58
|
+
steps:
|
|
59
|
+
- name: Download distributions
|
|
60
|
+
uses: actions/download-artifact@v4
|
|
61
|
+
with:
|
|
62
|
+
name: dist
|
|
63
|
+
path: dist/
|
|
64
|
+
|
|
65
|
+
- name: Publish to PyPI
|
|
66
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
67
|
+
|
|
68
|
+
github-release:
|
|
69
|
+
needs: build
|
|
70
|
+
runs-on: ubuntu-latest
|
|
71
|
+
permissions:
|
|
72
|
+
contents: write
|
|
73
|
+
steps:
|
|
74
|
+
- uses: actions/checkout@v4
|
|
75
|
+
|
|
76
|
+
- name: Download distributions
|
|
77
|
+
uses: actions/download-artifact@v4
|
|
78
|
+
with:
|
|
79
|
+
name: dist
|
|
80
|
+
path: dist/
|
|
81
|
+
|
|
82
|
+
- name: Create GitHub Release
|
|
83
|
+
uses: softprops/action-gh-release@v2
|
|
84
|
+
with:
|
|
85
|
+
generate_release_notes: true
|
|
86
|
+
files: dist/*
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [1.0.0] - 2025-07-02
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Initial release of behave-format
|
|
15
|
+
- Opinionated, deterministic formatter for Behave `.feature` files
|
|
16
|
+
- Consumes `behave-model.Project` as input (no direct Gherkin parsing)
|
|
17
|
+
- Formatting pipeline: normalize → sort → align → print
|
|
18
|
+
- Tags sorted alphabetically by default
|
|
19
|
+
- Table column alignment
|
|
20
|
+
- Whitespace normalization (trailing spaces, indentation)
|
|
21
|
+
- CLI with `--check` (CI mode), `--diff`, and write modes
|
|
22
|
+
- Configuration via `pyproject.toml` under `[tool.behave-format]`
|
|
23
|
+
- Golden file tests, idempotency tests, CLI tests, performance tests
|
|
24
|
+
- GitHub Actions CI workflow (lint, test, coverage, packaging)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Mathias Paulenko
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
.PHONY: install dev test test-verbose lint format coverage build clean docs docs-serve
|
|
2
|
+
|
|
3
|
+
install:
|
|
4
|
+
pip install -e .
|
|
5
|
+
|
|
6
|
+
dev:
|
|
7
|
+
pip install -e ".[dev]"
|
|
8
|
+
|
|
9
|
+
test:
|
|
10
|
+
pytest tests/ -q
|
|
11
|
+
|
|
12
|
+
test-verbose:
|
|
13
|
+
pytest tests/ -v --tb=short
|
|
14
|
+
|
|
15
|
+
lint:
|
|
16
|
+
ruff check behave_format/ tests/
|
|
17
|
+
ruff format --check behave_format/ tests/
|
|
18
|
+
|
|
19
|
+
format:
|
|
20
|
+
ruff format behave_format/ tests/
|
|
21
|
+
ruff check --fix behave_format/ tests/
|
|
22
|
+
|
|
23
|
+
coverage:
|
|
24
|
+
pytest tests/ --cov=behave_format --cov-report=term-missing --cov-report=html
|
|
25
|
+
|
|
26
|
+
build:
|
|
27
|
+
python -m build
|
|
28
|
+
|
|
29
|
+
docs:
|
|
30
|
+
mkdocs build
|
|
31
|
+
|
|
32
|
+
docs-serve:
|
|
33
|
+
mkdocs serve
|
|
34
|
+
|
|
35
|
+
clean:
|
|
36
|
+
rm -rf build/ dist/ *.egg-info/ .coverage .pytest_cache/ htmlcov/ .tox/ .ruff_cache/
|
|
37
|
+
find . -type d -name __pycache__ -exec rm -rf {} +
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: behave-format
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: The opinionated formatter for Behave .feature files
|
|
5
|
+
Project-URL: Homepage, https://github.com/MathiasPaulenko/behave-format
|
|
6
|
+
Project-URL: Repository, https://github.com/MathiasPaulenko/behave-format
|
|
7
|
+
Project-URL: Issues, https://github.com/MathiasPaulenko/behave-format/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/MathiasPaulenko/behave-format/blob/main/CHANGELOG.md
|
|
9
|
+
Author: Mathias Paulenko
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: bdd,behave,cucumber,format,formatter,gherkin,testing
|
|
13
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
21
|
+
Classifier: Topic :: Software Development :: Testing
|
|
22
|
+
Requires-Python: >=3.11
|
|
23
|
+
Requires-Dist: behave-model>=0.1.0
|
|
24
|
+
Provides-Extra: dev
|
|
25
|
+
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
|
|
26
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
27
|
+
Requires-Dist: ruff>=0.5; extra == 'dev'
|
|
28
|
+
Provides-Extra: docs
|
|
29
|
+
Requires-Dist: mkdocs-material>=9.5; extra == 'docs'
|
|
30
|
+
Requires-Dist: mkdocs>=1.6; extra == 'docs'
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
|
|
33
|
+
# behave-format
|
|
34
|
+
|
|
35
|
+
> The opinionated formatter for Behave `.feature` files.
|
|
36
|
+
|
|
37
|
+
[Black](https://github.com/psf/black) is for Python. [gofmt](https://go.dev/blog/gofmt) is for Go. **behave-format** is for Gherkin.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Overview
|
|
42
|
+
|
|
43
|
+
`behave-format` is a deterministic, opinionated formatter for Behave `.feature` files. It consumes the canonical domain model from [behave-model](https://github.com/MathiasPaulenko/behave-model) and produces clean, consistent, beautifully formatted output.
|
|
44
|
+
|
|
45
|
+
**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.
|
|
46
|
+
|
|
47
|
+
```text
|
|
48
|
+
.feature files → behave-model (domain model) → behave-format → formatted .feature files
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Features
|
|
52
|
+
|
|
53
|
+
- **Opinionated** — minimal configuration, sensible defaults
|
|
54
|
+
- **Deterministic** — same input always produces same output
|
|
55
|
+
- **Idempotent** — `format(format(x)) == format(x)`
|
|
56
|
+
- **Fast** — handles thousands of feature files efficiently
|
|
57
|
+
- **CI-friendly** — `--check` mode with exit code 1 when formatting is needed
|
|
58
|
+
- **Safe** — never changes semantics (names, step text, table values, docstrings)
|
|
59
|
+
|
|
60
|
+
## Installation
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pip install behave-format
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Quick Start
|
|
67
|
+
|
|
68
|
+
### CLI
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# Format files in place (default)
|
|
72
|
+
behave-format features/
|
|
73
|
+
|
|
74
|
+
# Check mode (CI) — exit 1 if formatting is needed
|
|
75
|
+
behave-format --check features/
|
|
76
|
+
|
|
77
|
+
# Diff mode — show differences without writing
|
|
78
|
+
behave-format --diff features/
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Python API
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
from behave_model import load_project
|
|
85
|
+
from behave_format import format_project, render_project, Settings
|
|
86
|
+
|
|
87
|
+
project = load_project("features/")
|
|
88
|
+
|
|
89
|
+
# Format the project model in place
|
|
90
|
+
format_project(project)
|
|
91
|
+
|
|
92
|
+
# Or render to text
|
|
93
|
+
text = render_project(project, Settings())
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Formatting Rules
|
|
97
|
+
|
|
98
|
+
### Tags
|
|
99
|
+
|
|
100
|
+
Tags are sorted alphabetically by default:
|
|
101
|
+
|
|
102
|
+
```gherkin
|
|
103
|
+
@api @smoke
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Features
|
|
107
|
+
|
|
108
|
+
- One blank line before each Feature
|
|
109
|
+
- Clean title formatting
|
|
110
|
+
|
|
111
|
+
### Scenarios
|
|
112
|
+
|
|
113
|
+
- One blank line before each Scenario
|
|
114
|
+
- Two-space indentation for steps
|
|
115
|
+
|
|
116
|
+
```gherkin
|
|
117
|
+
Given user exists
|
|
118
|
+
When user logs in
|
|
119
|
+
Then dashboard is shown
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Tables
|
|
123
|
+
|
|
124
|
+
Tables are always aligned:
|
|
125
|
+
|
|
126
|
+
Before:
|
|
127
|
+
|
|
128
|
+
```gherkin
|
|
129
|
+
|user|password|
|
|
130
|
+
|john|123|
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
After:
|
|
134
|
+
|
|
135
|
+
```gherkin
|
|
136
|
+
| user | password |
|
|
137
|
+
| john | 123 |
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Blank Lines
|
|
141
|
+
|
|
142
|
+
- No trailing blank lines
|
|
143
|
+
- No multiple consecutive empty lines
|
|
144
|
+
- Consistent spacing between blocks
|
|
145
|
+
|
|
146
|
+
### Indentation
|
|
147
|
+
|
|
148
|
+
- Spaces only (no tabs)
|
|
149
|
+
- Default: 2 spaces
|
|
150
|
+
|
|
151
|
+
## Configuration
|
|
152
|
+
|
|
153
|
+
Minimal configuration via `pyproject.toml`:
|
|
154
|
+
|
|
155
|
+
```toml
|
|
156
|
+
[tool.behave-format]
|
|
157
|
+
indent = 2
|
|
158
|
+
sort_tags = true
|
|
159
|
+
sort_features = false
|
|
160
|
+
sort_scenarios = false
|
|
161
|
+
line_length = 120
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
| Option | Default | Description |
|
|
165
|
+
|--------|---------|-------------|
|
|
166
|
+
| `indent` | `2` | Number of spaces for indentation |
|
|
167
|
+
| `sort_tags` | `true` | Sort tags alphabetically |
|
|
168
|
+
| `sort_features` | `false` | Sort features by name |
|
|
169
|
+
| `sort_scenarios` | `false` | Sort scenarios by name |
|
|
170
|
+
| `line_length` | `120` | Maximum line length (reference) |
|
|
171
|
+
|
|
172
|
+
## Before / After
|
|
173
|
+
|
|
174
|
+
### Before
|
|
175
|
+
|
|
176
|
+
```gherkin
|
|
177
|
+
@smoke @auth
|
|
178
|
+
Feature: Login
|
|
179
|
+
As a user
|
|
180
|
+
I want to log in
|
|
181
|
+
|
|
182
|
+
Background:
|
|
183
|
+
Given a database connection
|
|
184
|
+
|
|
185
|
+
@happy
|
|
186
|
+
Scenario: Successful login
|
|
187
|
+
Given the user is on the login page
|
|
188
|
+
When the user enters "admin" and "password"
|
|
189
|
+
Then the user should be logged in
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### After
|
|
193
|
+
|
|
194
|
+
```gherkin
|
|
195
|
+
@auth @smoke
|
|
196
|
+
Feature: Login
|
|
197
|
+
As a user
|
|
198
|
+
I want to log in
|
|
199
|
+
|
|
200
|
+
Background:
|
|
201
|
+
Given a database connection
|
|
202
|
+
|
|
203
|
+
@happy
|
|
204
|
+
Scenario: Successful login
|
|
205
|
+
Given the user is on the login page
|
|
206
|
+
When the user enters "admin" and "password"
|
|
207
|
+
Then the user should be logged in
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Architecture
|
|
211
|
+
|
|
212
|
+
```text
|
|
213
|
+
behave_format/
|
|
214
|
+
├── config/
|
|
215
|
+
│ └── settings.py # Settings dataclass + pyproject.toml loader
|
|
216
|
+
├── pipeline/
|
|
217
|
+
│ ├── normalize.py # Whitespace, indentation, tag normalization
|
|
218
|
+
│ ├── sort.py # Sort tags, features, scenarios
|
|
219
|
+
│ ├── align.py # Table alignment, trailing whitespace
|
|
220
|
+
│ ├── rules.py # Formatting rules registry
|
|
221
|
+
│ └── formatter.py # Main orchestrator (format_project)
|
|
222
|
+
├── printer/
|
|
223
|
+
│ ├── feature_printer.py
|
|
224
|
+
│ ├── scenario_printer.py
|
|
225
|
+
│ ├── step_printer.py
|
|
226
|
+
│ ├── table_printer.py
|
|
227
|
+
│ └── tag_printer.py
|
|
228
|
+
└── cli/
|
|
229
|
+
└── main.py # CLI entry point
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## Pipeline
|
|
233
|
+
|
|
234
|
+
1. **Normalize** — clean whitespace, standardize indentation, normalize tags
|
|
235
|
+
2. **Sort** — order tags (alphabetically by default), optionally features and scenarios
|
|
236
|
+
3. **Align** — align table columns, remove trailing spaces
|
|
237
|
+
4. **Print** — convert `behave-model` → `.feature` text (deterministic)
|
|
238
|
+
|
|
239
|
+
## Safety
|
|
240
|
+
|
|
241
|
+
The formatter NEVER changes semantics:
|
|
242
|
+
|
|
243
|
+
- Feature names: preserved
|
|
244
|
+
- Scenario names: preserved
|
|
245
|
+
- Step text: preserved (only whitespace normalized)
|
|
246
|
+
- DocString content: preserved
|
|
247
|
+
- Table values: preserved (only alignment changes)
|
|
248
|
+
- Comments content: preserved
|
|
249
|
+
|
|
250
|
+
## Integration
|
|
251
|
+
|
|
252
|
+
`behave-format` integrates naturally with the Behave ecosystem:
|
|
253
|
+
|
|
254
|
+
- [behave-model](https://github.com/MathiasPaulenko/behave-model) — single source of truth
|
|
255
|
+
- [behave-lint](https://github.com/MathiasPaulenko/behave-lint) — linting
|
|
256
|
+
- [behave-modern-json-report](https://github.com/MathiasPaulenko/behave-modern-json-report)
|
|
257
|
+
- [behave-modern-report](https://github.com/MathiasPaulenko/behave-modern-report)
|
|
258
|
+
- [behave-markdown-report](https://github.com/MathiasPaulenko/behave-markdown-report)
|
|
259
|
+
|
|
260
|
+
## Development
|
|
261
|
+
|
|
262
|
+
```bash
|
|
263
|
+
pip install -e ".[dev]"
|
|
264
|
+
pytest tests/ -v
|
|
265
|
+
ruff check .
|
|
266
|
+
ruff format --check .
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
## Contributing
|
|
270
|
+
|
|
271
|
+
Contributions are welcome! Please:
|
|
272
|
+
|
|
273
|
+
1. Fork the repository
|
|
274
|
+
2. Create a feature branch
|
|
275
|
+
3. Run `ruff check .` and `pytest tests/` before submitting
|
|
276
|
+
4. Open a Pull Request
|
|
277
|
+
|
|
278
|
+
## License
|
|
279
|
+
|
|
280
|
+
MIT
|