behave-modern-sheets-report

July 15, 2026 ยท View on GitHub

CI Release PyPI version Python versions License: MIT Coverage Code style: ruff Type checker: mypy Stable SemVer

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

FeatureDescription
๐Ÿ“ŠThree output formatsCSV (stdlib, zero dependencies), XLSX (via openpyxl), and ODS (via odfpy)
๐Ÿ“‘Multi-sheet workbooksSummary, Details, Failures, and Trends sheets in XLSX and ODS
๐ŸŽจConditional formattingColor-coded pass/fail cells for at-a-glance status reading
๐Ÿ“ˆAutomatic trend historyEvery run is persisted to a JSON file and visualized in a Trends sheet
โš™๏ธConfigurable columnsChoose which columns appear in the Details sheet via userdata
๐Ÿ”’Atomic history writesCorruption-proof file I/O using temp file + os.replace
โœ…100% test coverageFully tested across Python 3.11, 3.12, 3.13, and 3.14 on Linux, Windows, and macOS
๐ŸชถZero required dependenciesCSV 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

ExtraPackagesWhen to use
[behave]behave>=1.2.6You need Behave installed alongside the formatter
[xlsx]openpyxl>=3.1You want XLSX output
[ods]odfpy>=1.4You want ODS output
[dev]pytest, ruff, mypy, build, twineLocal 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

  1. 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
    
  2. Run Behave with any (or all) of the formatters:

    behave -f xlsx-modern -o report.xlsx
    
  3. Open report.xlsx in Excel, LibreOffice, or Google Sheets.

Format Comparison

FeatureCSVXLSXODS
Dependencystdlibopenpyxlodfpy
Multi-sheetSingle fileYesYes
Conditional formattingโ€”Cell fillsCell styles
Auto-filtersโ€”Yesโ€”
Freeze panesโ€”Yesโ€”
Bold headersโ€”YesYes
Trends sheetโ€”YesYes
Install extraโ€”[xlsx][ods]

Report Structure

XLSX and ODS reports contain up to four sheets:

SheetContentWhen present
SummaryOne row per feature with totals, pass rate, and durationAlways
DetailsOne row per scenario with configurable columnsAlways
FailuresFailed scenarios only โ€” error message, type, traceback, file, lineAlways (empty if no failures)
TrendsHistorical run entries with pass rate evolution over timeWhen history exists

CSV reports produce a single flat file with one row per scenario (equivalent to the Details sheet).

Conditional formatting colors

StatusCell fill
PassedGreen (#C6EFCE)
FailedRed (#FFC7CE)
SkippedYellow (#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):

OptionTypeDefaultDescription
report_columnsCSV stringfeature,scenario,status,duration,tags,errorColumns shown in Details sheet
report_only_failedboolfalseShow only failed scenarios in Details
report_delimiterstringcommaCSV delimiter (comma, semicolon, tab)
report_clear_historyboolfalseClear history before appending current run
report_history_pathstring.behave-sheets-history.jsonPath to history JSON file
report_max_historyint100Maximum 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):

ColumnDescription
featureFeature name
scenarioScenario name
statusScenario status (passed, failed, skipped, undefined)
durationExecution time (human-readable, e.g. 1.234s, 12ms)
tagsScenario tags (semicolon-separated)
errorError message with type if available (e.g. AssertionError [...])
error_typeException type name
tracebackFull traceback string
stepsTotal step count
passed_stepsNumber of passed steps
failed_stepsNumber of failed steps
skipped_stepsNumber of skipped steps
fileFeature file path
lineLine number in the feature file
ruleGherkin rule name (empty if none)
is_outlinetrue if scenario outline example row, false otherwise

Default columns: feature,scenario,status,duration,tags,error

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.py has zero external dependencies. Dataclasses can be serialized to any format without importing Behave, openpyxl, or odfpy.
  • Single Behave integration point โ€” Collector is 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. openpyxl and odfpy are only imported when their respective writer is called.
  • Atomic file I/O โ€” History writes to a .tmp file first, then uses os.replace for an atomic swap. This prevents corruption if the process is killed mid-write.

Ecosystem

Part of the behave-modern-* formatter family:

PackageFormatsStatus
behave-modern-json-reportJSONโœ…
behave-modern-html-reportHTMLโœ…
behave-modern-md-reportMarkdownโœ…
behave-modern-console-reportConsole (rich terminal)โœ…
behave-modern-sheets-reportCSV, XLSX, ODSthis 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