behave-modern-sheets-report
July 15, 2026 ยท View on GitHub
Modern spreadsheet report formatters for Behave BDD โ generate CSV, XLSX, and ODS execution reports with multi-sheet layouts, conditional formatting, and automatic trend history.
Table of Contents
- Features
- Requirements
- Installation
- Quick Start
- Format Comparison
- Report Structure
- CLI Usage
- Configuration Options
- Available Columns
- Automatic History & Trends
- Programmatic Usage
- Architecture
- Ecosystem
- Contributing
- Security
- Changelog
- License
Features
| Feature | Description | |
|---|---|---|
| ๐ | Three output formats | CSV (stdlib, zero dependencies), XLSX (via openpyxl), and ODS (via odfpy) |
| ๐ | Multi-sheet workbooks | Summary, Details, Failures, and Trends sheets in XLSX and ODS |
| ๐จ | Conditional formatting | Color-coded pass/fail cells for at-a-glance status reading |
| ๐ | Automatic trend history | Every run is persisted to a JSON file and visualized in a Trends sheet |
| โ๏ธ | Configurable columns | Choose which columns appear in the Details sheet via userdata |
| ๐ | Atomic history writes | Corruption-proof file I/O using temp file + os.replace |
| โ | 100% test coverage | Fully tested across Python 3.11, 3.12, 3.13, and 3.14 on Linux, Windows, and macOS |
| ๐ชถ | Zero required dependencies | CSV works with Python stdlib alone; XLSX and ODS are opt-in extras |
Requirements
- Python 3.11 or higher
- Behave >= 1.2.6 (for running BDD tests)
openpyxl >= 3.1(optional, for XLSX output)odfpy >= 1.4(optional, for ODS output)
Installation
pip install behave-modern-sheets-report
Extras
| Extra | Packages | When to use |
|---|---|---|
[behave] | behave>=1.2.6 | You need Behave installed alongside the formatter |
[xlsx] | openpyxl>=3.1 | You want XLSX output |
[ods] | odfpy>=1.4 | You want ODS output |
[dev] | pytest, ruff, mypy, build, twine | Local development |
Install with multiple extras:
pip install "behave-modern-sheets-report[xlsx,ods]"
For full development setup:
git clone https://github.com/MathiasPaulenko/behave-modern-sheets-report.git
cd behave-modern-sheets-report
pip install -e ".[dev,xlsx,ods]"
pre-commit install
Quick Start
-
Register the formatters in your
behave.ini:[behave.formatters] csv-modern = behave_modern_sheets_report.csv_formatter:CSVFormatter xlsx-modern = behave_modern_sheets_report.xlsx_formatter:XLSXFormatter ods-modern = behave_modern_sheets_report.ods_formatter:ODSFormatter -
Run Behave with any (or all) of the formatters:
behave -f xlsx-modern -o report.xlsx -
Open
report.xlsxin Excel, LibreOffice, or Google Sheets.
Format Comparison
| Feature | CSV | XLSX | ODS |
|---|---|---|---|
| Dependency | stdlib | openpyxl | odfpy |
| Multi-sheet | Single file | Yes | Yes |
| Conditional formatting | โ | Cell fills | Cell styles |
| Auto-filters | โ | Yes | โ |
| Freeze panes | โ | Yes | โ |
| Bold headers | โ | Yes | Yes |
| Trends sheet | โ | Yes | Yes |
| Install extra | โ | [xlsx] | [ods] |
Report Structure
XLSX and ODS reports contain up to four sheets:
| Sheet | Content | When present |
|---|---|---|
| Summary | One row per feature with totals, pass rate, and duration | Always |
| Details | One row per scenario with configurable columns | Always |
| Failures | Failed scenarios only โ error message, type, traceback, file, line | Always (empty if no failures) |
| Trends | Historical run entries with pass rate evolution over time | When history exists |
CSV reports produce a single flat file with one row per scenario (equivalent to the Details sheet).
Conditional formatting colors
| Status | Cell fill |
|---|---|
| Passed | Green (#C6EFCE) |
| Failed | Red (#FFC7CE) |
| Skipped | Yellow (#FFEB9C) |
CLI Usage
Register formatters in behave.ini:
[behave.formatters]
csv-modern = behave_modern_sheets_report.csv_formatter:CSVFormatter
xlsx-modern = behave_modern_sheets_report.xlsx_formatter:XLSXFormatter
ods-modern = behave_modern_sheets_report.ods_formatter:ODSFormatter
Generate reports:
behave -f csv-modern -o report.csv
behave -f xlsx-modern -o report.xlsx
behave -f ods-modern -o report.ods
Multiple formatters can be used simultaneously to produce all formats in a single run:
behave -f csv-modern -o report.csv -f xlsx-modern -o report.xlsx -f ods-modern -o report.ods
You can also set userdata options directly in behave.ini:
[behave.userdata]
report_columns = feature,scenario,status,duration,error
report_only_failed = false
report_max_history = 50
Configuration Options
All options are passed via Behave's userdata (command-line -D or behave.ini):
| Option | Type | Default | Description |
|---|---|---|---|
report_columns | CSV string | feature,scenario,status,duration,tags,error | Columns shown in Details sheet |
report_only_failed | bool | false | Show only failed scenarios in Details |
report_delimiter | string | comma | CSV delimiter (comma, semicolon, tab) |
report_clear_history | bool | false | Clear history before appending current run |
report_history_path | string | .behave-sheets-history.json | Path to history JSON file |
report_max_history | int | 100 | Maximum history entries to retain |
Examples
Generate an XLSX report with only failed scenarios and a custom column set:
behave -f xlsx-modern -o report.xlsx \
-D report_only_failed=true \
-D report_columns=feature,scenario,status,error \
-D report_max_history=50
Use a semicolon delimiter for CSV (useful in European locales):
behave -f csv-modern -o report.csv -D report_delimiter=semicolon
Clear history before a fresh run (e.g. after changing the test suite):
behave -f xlsx-modern -o report.xlsx -D report_clear_history=true
Store history in a custom location (e.g. outside the working directory):
behave -f xlsx-modern -o report.xlsx -D report_history_path=/tmp/behave-history.json
Available Columns
The report_columns option accepts any combination of the following column names (comma-separated):
| Column | Description |
|---|---|
feature | Feature name |
scenario | Scenario name |
status | Scenario status (passed, failed, skipped, undefined) |
duration | Execution time (human-readable, e.g. 1.234s, 12ms) |
tags | Scenario tags (semicolon-separated) |
error | Error message with type if available (e.g. AssertionError [...]) |
error_type | Exception type name |
traceback | Full traceback string |
steps | Total step count |
passed_steps | Number of passed steps |
failed_steps | Number of failed steps |
skipped_steps | Number of skipped steps |
file | Feature file path |
line | Line number in the feature file |
rule | Gherkin rule name (empty if none) |
is_outline | true if scenario outline example row, false otherwise |
Default columns: feature,scenario,status,duration,tags,error
Automatic History & Trends
Every run is automatically appended to a JSON history file (.behave-sheets-history.json by default). The history feeds the Trends sheet in XLSX and ODS reports, showing pass rate evolution across runs.
report_history_pathโ custom location for the history file.report_clear_historyโ clears all previous entries before appending the current run (useful for fresh starts).report_max_historyโ limits the number of retained entries (oldest are dropped).
History is managed atomically (write to .tmp, then os.replace) to prevent corruption.
History file format
The history file is a JSON array of entry objects:
[
{
"run_id": "run_a1b2c3d4e5f6",
"timestamp": "2025-01-15T10:30:00.123456+00:00",
"total_features": 3,
"total_scenarios": 15,
"passed": 14,
"failed": 1,
"skipped": 0,
"undefined": 0,
"pass_rate": 93.3,
"duration": 2.45
}
]
Programmatic Usage
You can use the collector, writers, and history directly without Behave:
from behave_modern_sheets_report import Collector, CSVWriter, XLSXWriter, History
from pathlib import Path
# Collect results from Behave events
collector = Collector()
collector.start_feature(feature_obj)
collector.start_scenario(scenario_obj)
collector.start_step(step_obj)
collector.end_step(step_obj)
collector.end_scenario()
collector.end_feature()
run_summary = collector.finalize()
# Write CSV (no extra dependencies needed)
with open("report.csv", "w", newline="") as f:
CSVWriter.write(run_summary, f)
# Write XLSX (requires openpyxl)
history = History(max_entries=50)
trends = history.append(run_summary)
XLSXWriter.write(run_summary, Path("report.xlsx"), trends=trends)
This is useful for integrating the report generation into custom test runners or CI pipelines.
Architecture
Behave Runner
โ
โโโ CSVFormatter โโโบ Collector โโโบ RunSummary โโโบ CSVWriter โโโบ report.csv
โโโ XLSXFormatter โโโบ Collector โโโบ RunSummary โโโบ XLSXWriter โโโบ report.xlsx
โโโ ODSFormatter โโโโบ Collector โโโบ RunSummary โโโบ ODSWriter โโโโบ report.ods
โ
โโโโบ History โโโบ .behave-sheets-history.json
โ
โโโโบ Trends sheet
Collector processes Behave events (feature, scenario, step, result) and builds a RunSummary. Writers serialize the summary into the target format. History persists run metrics between executions for trend analysis.
Key design decisions
- Pure data models โ
models.pyhas zero external dependencies. Dataclasses can be serialized to any format without importing Behave, openpyxl, or odfpy. - Single Behave integration point โ
Collectoris the only module that touches Behave objects. Everything else operates on pure dataclasses, making the writers and history fully testable without Behave. - Opt-in dependencies โ CSV works with stdlib alone.
openpyxlandodfpyare only imported when their respective writer is called. - Atomic file I/O โ History writes to a
.tmpfile first, then usesos.replacefor an atomic swap. This prevents corruption if the process is killed mid-write.
Ecosystem
Part of the behave-modern-* formatter family:
| Package | Formats | Status |
|---|---|---|
behave-modern-json-report | JSON | โ |
behave-modern-html-report | HTML | โ |
behave-modern-md-report | Markdown | โ |
behave-modern-console-report | Console (rich terminal) | โ |
behave-modern-sheets-report | CSV, XLSX, ODS | this package |
Contributing
Contributions are welcome! Please read the Contributing Guide and our Code of Conduct before submitting pull requests.
Development commands
make lint # ruff check + format check
make typecheck # mypy --strict
make test # pytest with verbose output
make format # ruff auto-fix + format
make build # build sdist + wheel
Security
If you discover a security vulnerability, please refer to our Security Policy for responsible disclosure instructions.
Changelog
See CHANGELOG.md for release history and notable changes.
License
MIT โ see LICENSE for full text.
Made with care by Mathias Paulenko