behave-model 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_model-1.0.0/.github/workflows/ci.yml +47 -0
- behave_model-1.0.0/.github/workflows/docs.yml +52 -0
- behave_model-1.0.0/.github/workflows/release.yml +85 -0
- behave_model-1.0.0/.gitignore +78 -0
- behave_model-1.0.0/.pre-commit-config.yaml +7 -0
- behave_model-1.0.0/CHANGELOG.md +54 -0
- behave_model-1.0.0/LICENSE +21 -0
- behave_model-1.0.0/Makefile +37 -0
- behave_model-1.0.0/PKG-INFO +273 -0
- behave_model-1.0.0/README.md +241 -0
- behave_model-1.0.0/behave_model/__init__.py +164 -0
- behave_model-1.0.0/behave_model/exceptions.py +28 -0
- behave_model-1.0.0/behave_model/model/__init__.py +34 -0
- behave_model-1.0.0/behave_model/model/background.py +39 -0
- behave_model-1.0.0/behave_model/model/comment.py +23 -0
- behave_model-1.0.0/behave_model/model/docstring.py +29 -0
- behave_model-1.0.0/behave_model/model/examples.py +44 -0
- behave_model-1.0.0/behave_model/model/feature.py +113 -0
- behave_model-1.0.0/behave_model/model/location.py +30 -0
- behave_model-1.0.0/behave_model/model/metadata.py +23 -0
- behave_model-1.0.0/behave_model/model/project.py +208 -0
- behave_model-1.0.0/behave_model/model/rule.py +83 -0
- behave_model-1.0.0/behave_model/model/scenario.py +56 -0
- behave_model-1.0.0/behave_model/model/scenario_outline.py +69 -0
- behave_model-1.0.0/behave_model/model/step.py +57 -0
- behave_model-1.0.0/behave_model/model/table.py +93 -0
- behave_model-1.0.0/behave_model/model/tag.py +31 -0
- behave_model-1.0.0/behave_model/parser/__init__.py +13 -0
- behave_model-1.0.0/behave_model/parser/adapter.py +240 -0
- behave_model-1.0.0/behave_model/parser/loader.py +82 -0
- behave_model-1.0.0/behave_model/parser/parser.py +46 -0
- behave_model-1.0.0/behave_model/queries/__init__.py +25 -0
- behave_model-1.0.0/behave_model/queries/query.py +155 -0
- behave_model-1.0.0/behave_model/serializers/__init__.py +11 -0
- behave_model-1.0.0/behave_model/serializers/dict_serializer.py +165 -0
- behave_model-1.0.0/behave_model/serializers/json_serializer.py +41 -0
- behave_model-1.0.0/behave_model/serializers/pretty_printer.py +191 -0
- behave_model-1.0.0/behave_model/transformations/__init__.py +23 -0
- behave_model-1.0.0/behave_model/transformations/transform.py +192 -0
- behave_model-1.0.0/behave_model/utils/__init__.py +15 -0
- behave_model-1.0.0/behave_model/utils/utils.py +29 -0
- behave_model-1.0.0/behave_model/validation/__init__.py +23 -0
- behave_model-1.0.0/behave_model/validation/validator.py +228 -0
- behave_model-1.0.0/behave_model/visitors/__init__.py +13 -0
- behave_model-1.0.0/behave_model/visitors/visitor.py +142 -0
- behave_model-1.0.0/conftest.py +12 -0
- behave_model-1.0.0/docs/api_reference.md +146 -0
- behave_model-1.0.0/docs/architecture.md +89 -0
- behave_model-1.0.0/docs/contributing.md +57 -0
- behave_model-1.0.0/docs/index.md +49 -0
- behave_model-1.0.0/docs/quick_start.md +100 -0
- behave_model-1.0.0/examples/data_tables.feature +20 -0
- behave_model-1.0.0/examples/login.feature +35 -0
- behave_model-1.0.0/examples/rules.feature +36 -0
- behave_model-1.0.0/examples/shopping_cart.feature +30 -0
- behave_model-1.0.0/mkdocs.yml +63 -0
- behave_model-1.0.0/pyproject.toml +70 -0
- behave_model-1.0.0/tests/conftest.py +135 -0
- behave_model-1.0.0/tests/test_exceptions.py +31 -0
- behave_model-1.0.0/tests/test_golden.py +120 -0
- behave_model-1.0.0/tests/test_model.py +321 -0
- behave_model-1.0.0/tests/test_parser.py +144 -0
- behave_model-1.0.0/tests/test_query.py +117 -0
- behave_model-1.0.0/tests/test_rules.py +270 -0
- behave_model-1.0.0/tests/test_serialization.py +157 -0
- behave_model-1.0.0/tests/test_statistics.py +71 -0
- behave_model-1.0.0/tests/test_transformation.py +133 -0
- behave_model-1.0.0/tests/test_validation.py +183 -0
- behave_model-1.0.0/tests/test_visitor.py +104 -0
- behave_model-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_model/ tests/
|
|
19
|
+
- run: ruff format --check behave_model/ 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_model --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,52 @@
|
|
|
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 --strict
|
|
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
|
+
steps:
|
|
50
|
+
- name: Deploy to GitHub Pages
|
|
51
|
+
id: deployment
|
|
52
|
+
uses: actions/deploy-pages@v4
|
|
@@ -0,0 +1,85 @@
|
|
|
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_model --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
|
+
steps:
|
|
58
|
+
- name: Download distributions
|
|
59
|
+
uses: actions/download-artifact@v4
|
|
60
|
+
with:
|
|
61
|
+
name: dist
|
|
62
|
+
path: dist/
|
|
63
|
+
|
|
64
|
+
- name: Publish to PyPI
|
|
65
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
66
|
+
|
|
67
|
+
github-release:
|
|
68
|
+
needs: build
|
|
69
|
+
runs-on: ubuntu-latest
|
|
70
|
+
permissions:
|
|
71
|
+
contents: write
|
|
72
|
+
steps:
|
|
73
|
+
- uses: actions/checkout@v4
|
|
74
|
+
|
|
75
|
+
- name: Download distributions
|
|
76
|
+
uses: actions/download-artifact@v4
|
|
77
|
+
with:
|
|
78
|
+
name: dist
|
|
79
|
+
path: dist/
|
|
80
|
+
|
|
81
|
+
- name: Create GitHub Release
|
|
82
|
+
uses: softprops/action-gh-release@v2
|
|
83
|
+
with:
|
|
84
|
+
generate_release_notes: true
|
|
85
|
+
files: dist/*
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
*.manifest
|
|
31
|
+
*.spec
|
|
32
|
+
|
|
33
|
+
# Installer logs
|
|
34
|
+
pip-log.txt
|
|
35
|
+
pip-delete-this-directory.txt
|
|
36
|
+
|
|
37
|
+
# Unit test / coverage reports
|
|
38
|
+
htmlcov/
|
|
39
|
+
.tox/
|
|
40
|
+
.nox/
|
|
41
|
+
.coverage
|
|
42
|
+
.coverage.*
|
|
43
|
+
.cache
|
|
44
|
+
.pytest_cache/
|
|
45
|
+
nosetests.xml
|
|
46
|
+
coverage.xml
|
|
47
|
+
*.cover
|
|
48
|
+
*.py,cover
|
|
49
|
+
.hypothesis/
|
|
50
|
+
*.lcov
|
|
51
|
+
|
|
52
|
+
# Environments
|
|
53
|
+
.env
|
|
54
|
+
.venv
|
|
55
|
+
env/
|
|
56
|
+
venv/
|
|
57
|
+
ENV/
|
|
58
|
+
env.bak/
|
|
59
|
+
venv.bak/
|
|
60
|
+
|
|
61
|
+
# IDEs
|
|
62
|
+
.idea/
|
|
63
|
+
.vscode/
|
|
64
|
+
*.swp
|
|
65
|
+
*.swo
|
|
66
|
+
*~
|
|
67
|
+
.DS_Store
|
|
68
|
+
|
|
69
|
+
# Type checkers
|
|
70
|
+
.mypy_cache/
|
|
71
|
+
.pyre/
|
|
72
|
+
.pytype/
|
|
73
|
+
|
|
74
|
+
# Ruff
|
|
75
|
+
.ruff_cache/
|
|
76
|
+
|
|
77
|
+
# MkDocs
|
|
78
|
+
site/
|
|
@@ -0,0 +1,54 @@
|
|
|
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
|
+
## [1.0.0] - 2026-07-02
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- `Rule` model class for Gherkin v6 `Rule` keyword support.
|
|
12
|
+
- `Feature.rules` list and `Feature.all_scenarios()` now includes rule scenarios.
|
|
13
|
+
- `BehaveParserAdapter._adapt_rule()` to parse Behave Rule objects.
|
|
14
|
+
- `Visitor.visit_rule()` in base visitor, `CountingVisitor`, and `CollectingVisitor`.
|
|
15
|
+
- `Project` DFS/BFS traversal now includes Rule nodes.
|
|
16
|
+
- `DictSerializer.serialize_rule()` and rules in `serialize_feature()`.
|
|
17
|
+
- `PrettyPrinter._print_rule()` with proper indentation for rule scenarios.
|
|
18
|
+
- `Rule` exported in public API (`behave_model.Rule`).
|
|
19
|
+
- Example feature file `examples/rules.feature` demonstrating Gherkin v6 Rules.
|
|
20
|
+
- 31 new tests for Rule support in `tests/test_rules.py`.
|
|
21
|
+
- MkDocs Material documentation site with GitHub Pages deployment.
|
|
22
|
+
- CI/CD workflows: `ci.yml`, `release.yml`, `docs.yml`.
|
|
23
|
+
- `.gitignore`, `.pre-commit-config.yaml`, `tox.ini`, `Makefile`, `conftest.py`.
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
- Tests moved from `behave_model/tests/` to `tests/` at project root.
|
|
27
|
+
- `pyproject.toml` `testpaths` updated to `["tests"]`.
|
|
28
|
+
- `PrettyPrinter` scenario/outline/examples methods now accept `indent` parameter.
|
|
29
|
+
- `Project.all_scenarios()` delegates to `Feature.all_scenarios()` for rule inclusion.
|
|
30
|
+
- README rewritten with badges, compatibility table, and architecture overview.
|
|
31
|
+
|
|
32
|
+
### Compatibility
|
|
33
|
+
- Verified full compatibility with Behave 1.3.3.
|
|
34
|
+
- Verified Tag Expression v2 support (both v1 and v2 parsers present in Behave).
|
|
35
|
+
- Verified Gherkin v6 `Rule` keyword parsing and roundtrip.
|
|
36
|
+
|
|
37
|
+
## [0.1.0] - 2026-07-01
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
- Initial release of `behave-model`.
|
|
41
|
+
- Domain model: `Project`, `Feature`, `Background`, `Scenario`, `ScenarioOutline`,
|
|
42
|
+
`Examples`, `Step`, `Table`, `Tag`, `DocString`, `Comment`, `Location`, `Metadata`.
|
|
43
|
+
- Parser adapter over Behave's built-in parser with `load_project` and `load_feature`.
|
|
44
|
+
- Visitor pattern with depth-first and breadth-first traversal.
|
|
45
|
+
- Query API: `find_feature`, `find_tag`, `find_steps`, `find_scenarios`.
|
|
46
|
+
- Serializers: dictionary and JSON.
|
|
47
|
+
- Transformations: rename tag, rename scenario, sort tags, sort features,
|
|
48
|
+
normalize whitespace.
|
|
49
|
+
- Validation framework with pluggable rules.
|
|
50
|
+
- Statistics: feature count, scenario count, step count, average steps per
|
|
51
|
+
scenario, tag count.
|
|
52
|
+
- Pretty printer that generates valid `.feature` files.
|
|
53
|
+
- Exception hierarchy: `BehaveModelError`, `ParseError`, `ValidationError`,
|
|
54
|
+
`TransformationError`, `SerializationError`.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 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_model/ tests/
|
|
17
|
+
ruff format --check behave_model/ tests/
|
|
18
|
+
|
|
19
|
+
format:
|
|
20
|
+
ruff format behave_model/ tests/
|
|
21
|
+
ruff check --fix behave_model/ tests/
|
|
22
|
+
|
|
23
|
+
coverage:
|
|
24
|
+
pytest tests/ --cov=behave_model --cov-report=term-missing --cov-report=html
|
|
25
|
+
|
|
26
|
+
build:
|
|
27
|
+
python -m build
|
|
28
|
+
|
|
29
|
+
docs:
|
|
30
|
+
mkdocs build --strict
|
|
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,273 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: behave-model
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Canonical object model for Behave projects
|
|
5
|
+
Project-URL: Homepage, https://github.com/MathiasPaulenko/behave-model
|
|
6
|
+
Project-URL: Repository, https://github.com/MathiasPaulenko/behave-model
|
|
7
|
+
Project-URL: Issues, https://github.com/MathiasPaulenko/behave-model/issues
|
|
8
|
+
Project-URL: Documentation, https://mathiaspaulenko.github.io/behave-model/
|
|
9
|
+
Project-URL: Changelog, https://github.com/MathiasPaulenko/behave-model/blob/main/CHANGELOG.md
|
|
10
|
+
Author: Mathias Paulenko
|
|
11
|
+
License-Expression: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: bdd,behave,cucumber,domain,gherkin,model,testing
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
22
|
+
Classifier: Topic :: Software Development :: Testing
|
|
23
|
+
Requires-Python: >=3.11
|
|
24
|
+
Requires-Dist: behave>=1.2.6
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: mkdocs-material>=9.5; extra == 'dev'
|
|
27
|
+
Requires-Dist: mkdocs>=1.6; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
30
|
+
Requires-Dist: ruff>=0.5; extra == 'dev'
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
|
|
33
|
+
<div align="center">
|
|
34
|
+
|
|
35
|
+
# behave-model
|
|
36
|
+
|
|
37
|
+
**The canonical object model for [Behave](https://github.com/behave/behave) projects.**
|
|
38
|
+
|
|
39
|
+
[](https://github.com/MathiasPaulenko/behave-model/actions/workflows/ci.yml)
|
|
40
|
+
[](https://pypi.org/project/behave-model/)
|
|
41
|
+
[](https://pypi.org/project/behave-model/)
|
|
42
|
+
[](https://opensource.org/licenses/MIT)
|
|
43
|
+
[](https://github.com/MathiasPaulenko/behave-model)
|
|
44
|
+
|
|
45
|
+
[Documentation](https://mathiaspaulenko.github.io/behave-model/) · [Quick Start](https://mathiaspaulenko.github.io/behave-model/quick_start/) · [API Reference](https://mathiaspaulenko.github.io/behave-model/api_reference/)
|
|
46
|
+
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
`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.
|
|
52
|
+
|
|
53
|
+
## Why?
|
|
54
|
+
|
|
55
|
+
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.
|
|
56
|
+
|
|
57
|
+
- **Compatible with Behave 1.3.x** — Tag Expression v2 and Gherkin v6 (including `Rule` blocks)
|
|
58
|
+
- **Clean domain model** — Pure dataclasses, no external runtime dependencies beyond Behave
|
|
59
|
+
- **Visitor pattern** — Traverse the entire tree with custom visitors
|
|
60
|
+
- **Query API** — Find features, scenarios, steps, and tags by name, tag, or keyword
|
|
61
|
+
- **Serializers** — Dict, JSON, and pretty-printed Gherkin output
|
|
62
|
+
- **Transformations** — Safe in-place modifications (rename tags, sort, normalize)
|
|
63
|
+
- **Validation framework** — Pluggable rules with built-in checks
|
|
64
|
+
- **95% test coverage** — Comprehensive unit, integration, and golden file tests
|
|
65
|
+
|
|
66
|
+
## Installation
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
pip install behave-model
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
For development:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
pip install -e ".[dev]"
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Quick Start
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
from behave_model import load_project
|
|
82
|
+
|
|
83
|
+
# Load all .feature files from a directory
|
|
84
|
+
project = load_project("features/")
|
|
85
|
+
|
|
86
|
+
# Access features, rules, and scenarios
|
|
87
|
+
print(len(project.features)) # number of features
|
|
88
|
+
print(project.features[0].name) # first feature name
|
|
89
|
+
print(len(project.features[0].rules)) # rules (Gherkin v6)
|
|
90
|
+
|
|
91
|
+
# Query the model
|
|
92
|
+
for scenario in project.find_scenarios(tag="@smoke"):
|
|
93
|
+
print(scenario.name)
|
|
94
|
+
|
|
95
|
+
# Statistics
|
|
96
|
+
stats = project.statistics()
|
|
97
|
+
print(f"{stats['features']} features, {stats['scenarios']} scenarios, {stats['steps']} steps")
|
|
98
|
+
|
|
99
|
+
# Traverse the tree
|
|
100
|
+
for node in project.walk():
|
|
101
|
+
print(type(node).__name__)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Domain Model
|
|
105
|
+
|
|
106
|
+
```text
|
|
107
|
+
Project
|
|
108
|
+
├── Metadata
|
|
109
|
+
├── Feature
|
|
110
|
+
│ ├── Tag
|
|
111
|
+
│ ├── Background
|
|
112
|
+
│ │ └── Step
|
|
113
|
+
│ ├── Scenario
|
|
114
|
+
│ │ ├── Tag
|
|
115
|
+
│ │ └── Step
|
|
116
|
+
│ ├── ScenarioOutline
|
|
117
|
+
│ │ ├── Tag
|
|
118
|
+
│ │ ├── Step
|
|
119
|
+
│ │ └── Examples
|
|
120
|
+
│ │ └── Table
|
|
121
|
+
│ └── Rule (Gherkin v6)
|
|
122
|
+
│ ├── Tag
|
|
123
|
+
│ ├── Background
|
|
124
|
+
│ │ └── Step
|
|
125
|
+
│ ├── Scenario
|
|
126
|
+
│ └── ScenarioOutline
|
|
127
|
+
└── ...
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Every node has a `Location` (filename, line, column) for precise source mapping.
|
|
131
|
+
|
|
132
|
+
## Features at a Glance
|
|
133
|
+
|
|
134
|
+
### Loading
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
from behave_model import load_project, load_feature
|
|
138
|
+
|
|
139
|
+
project = load_project("features/") # all .feature files
|
|
140
|
+
feature = load_feature("features/login.feature") # single file
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Visitor Pattern
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
from behave_model import Visitor
|
|
147
|
+
|
|
148
|
+
class StepCounter(Visitor):
|
|
149
|
+
def __init__(self):
|
|
150
|
+
self.count = 0
|
|
151
|
+
|
|
152
|
+
def visit_step(self, step):
|
|
153
|
+
self.count += 1
|
|
154
|
+
|
|
155
|
+
visitor = StepCounter()
|
|
156
|
+
project.accept(visitor)
|
|
157
|
+
print(f"Total steps: {visitor.count}")
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Query API
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
project.find_feature("Login")
|
|
164
|
+
project.find_tag("@smoke")
|
|
165
|
+
project.find_scenarios(tag="@api")
|
|
166
|
+
project.find_scenarios(name_contains="login")
|
|
167
|
+
project.find_steps(keyword="Given")
|
|
168
|
+
project.find_steps(text_contains="user")
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Serialization
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
from behave_model import JsonSerializer, DictSerializer, PrettyPrinter
|
|
175
|
+
|
|
176
|
+
# JSON
|
|
177
|
+
json_str = JsonSerializer().serialize_project(project)
|
|
178
|
+
|
|
179
|
+
# Dictionary
|
|
180
|
+
data = DictSerializer().serialize_project(project)
|
|
181
|
+
|
|
182
|
+
# Pretty-printed Gherkin
|
|
183
|
+
text = PrettyPrinter().print_feature(feature)
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Transformations
|
|
187
|
+
|
|
188
|
+
```python
|
|
189
|
+
from behave_model import rename_tag, sort_tags, normalize_whitespace
|
|
190
|
+
|
|
191
|
+
rename_tag(project, "@smoke", "@critical")
|
|
192
|
+
sort_tags(project)
|
|
193
|
+
normalize_whitespace(project)
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Validation
|
|
197
|
+
|
|
198
|
+
```python
|
|
199
|
+
from behave_model import Validator
|
|
200
|
+
|
|
201
|
+
validator = Validator()
|
|
202
|
+
issues = validator.validate(project)
|
|
203
|
+
for issue in issues:
|
|
204
|
+
print(f"[{issue.severity}] {issue.rule_name}: {issue.message}")
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Architecture
|
|
208
|
+
|
|
209
|
+
```text
|
|
210
|
+
Feature File → Parser Adapter → Domain Model → Visitors → Queries → Transformations → Serializers
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
The Domain Model never depends on report generation or formatting. Each layer has a single responsibility and can be used independently.
|
|
214
|
+
|
|
215
|
+
| Layer | Package | Responsibility |
|
|
216
|
+
|-------|---------|----------------|
|
|
217
|
+
| Parser Adapter | `behave_model.parser` | Wraps Behave's parser, adapts to domain model |
|
|
218
|
+
| Domain Model | `behave_model.model` | Pure dataclasses for every Gherkin element |
|
|
219
|
+
| Visitors | `behave_model.visitors` | Generic traversal pattern |
|
|
220
|
+
| Queries | `behave_model.queries` | High-level filtering API |
|
|
221
|
+
| Transformations | `behave_model.transformations` | Safe in-place modifications |
|
|
222
|
+
| Serializers | `behave_model.serializers` | Dict, JSON, Gherkin output |
|
|
223
|
+
| Validation | `behave_model.validation` | Pluggable rule framework |
|
|
224
|
+
|
|
225
|
+
## Compatibility
|
|
226
|
+
|
|
227
|
+
| Feature | Supported |
|
|
228
|
+
|---------|-----------|
|
|
229
|
+
| Behave 1.3.x | ✅ |
|
|
230
|
+
| Tag Expression v1 | ✅ |
|
|
231
|
+
| Tag Expression v2 | ✅ |
|
|
232
|
+
| Gherkin v6 (Rules) | ✅ |
|
|
233
|
+
| Scenario Outlines | ✅ |
|
|
234
|
+
| Data Tables | ✅ |
|
|
235
|
+
| DocStrings | ✅ |
|
|
236
|
+
| Background | ✅ |
|
|
237
|
+
| Multi-language features | ✅ |
|
|
238
|
+
|
|
239
|
+
## Development
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
# Clone and install
|
|
243
|
+
git clone https://github.com/MathiasPaulenko/behave-model.git
|
|
244
|
+
cd behave-model
|
|
245
|
+
pip install -e ".[dev]"
|
|
246
|
+
|
|
247
|
+
# Run tests
|
|
248
|
+
make test
|
|
249
|
+
|
|
250
|
+
# Run tests with coverage
|
|
251
|
+
make coverage
|
|
252
|
+
|
|
253
|
+
# Lint
|
|
254
|
+
make lint
|
|
255
|
+
|
|
256
|
+
# Format
|
|
257
|
+
make format
|
|
258
|
+
|
|
259
|
+
# Build
|
|
260
|
+
make build
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
## Documentation
|
|
264
|
+
|
|
265
|
+
Full documentation is available at [mathiaspaulenko.github.io/behave-model](https://mathiaspaulenko.github.io/behave-model/).
|
|
266
|
+
|
|
267
|
+
## Contributing
|
|
268
|
+
|
|
269
|
+
Contributions are welcome! See [CONTRIBUTING.md](docs/contributing.md) for guidelines.
|
|
270
|
+
|
|
271
|
+
## License
|
|
272
|
+
|
|
273
|
+
MIT
|