Metadata-Version: 2.4
Name: bankstatementparser-writer-xlsx
Version: 0.0.19
Summary: Excel (.xlsx) writer for bankstatementparser-parsed bank statements.
License: Apache-2.0 OR MIT
License-File: LICENSE
License-File: LICENSE-APACHE
License-File: LICENSE-MIT
Keywords: bank-statements,bankstatementparser,xlsx,excel,openpyxl,accounting,reconciliation
Author: Sebastien Rousseau
Author-email: sebastian.rousseau@gmail.com
Requires-Python: >=3.10,<4.0
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: License :: OSI Approved :: Apache Software License
Classifier: License :: Other/Proprietary License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Office/Business :: Financial
Classifier: Topic :: Office/Business :: Financial :: Accounting
Requires-Dist: bankstatementparser (>=0.0.18)
Requires-Dist: openpyxl (>=3.1,<4)
Requires-Dist: pandas (>=2.0)
Project-URL: Homepage, https://bankstatementparser.com
Project-URL: Repository, https://github.com/sebastienrousseau/bankstatementparser-writer-xlsx
Description-Content-Type: text/markdown

<!-- SPDX-License-Identifier: Apache-2.0 OR MIT -->

<p align="center">
  <img
    src="https://cloudcdn.pro/bankstatementparser/v1/logos/bankstatementparser.svg"
    alt="bankstatementparser-writer-xlsx logo"
    width="120"
    height="120"
  />
</p>

<h1 align="center">bankstatementparser-writer-xlsx</h1>

<p align="center">
  <b>A polished Microsoft Excel (.xlsx) workbook export writer plugin for <code>bankstatementparser</code> transaction data.</b>
</p>

<p align="center">
  <a href="https://pypi.org/project/bankstatementparser-writer-xlsx/"><img src="https://img.shields.io/pypi/v/bankstatementparser-writer-xlsx?style=for-the-badge" alt="PyPI version" /></a>
  <a href="https://pypi.org/project/bankstatementparser-writer-xlsx/"><img src="https://img.shields.io/pypi/pyversions/bankstatementparser-writer-xlsx.svg?style=for-the-badge" alt="Python versions" /></a>
  <a href="https://pypi.org/project/bankstatementparser-writer-xlsx/"><img src="https://img.shields.io/pypi/dm/bankstatementparser-writer-xlsx.svg?style=for-the-badge" alt="PyPI downloads" /></a>
  <a href="https://github.com/sebastienrousseau/bankstatementparser-writer-xlsx/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/sebastienrousseau/bankstatementparser-writer-xlsx/ci.yml?branch=main&label=Tests&style=for-the-badge" alt="Tests" /></a>
  <a href="#license"><img src="https://img.shields.io/pypi/l/bankstatementparser-writer-xlsx?style=for-the-badge" alt="License" /></a>
</p>

> **Latest release: v0.0.19** — single `write_xlsx(data, path, ...)` function, 100% line + branch coverage, 100% docstring coverage, `mypy --strict` clean.

---

## Contents

- [Overview](#overview)
- [Install](#install)
- [Quick start](#quick-start)
- [Input shapes](#input-shapes)
- [Value coercion](#value-coercion)
- [The summary sheet](#the-summary-sheet)
- [Examples](#examples)
- [When not to use this package](#when-not-to-use-this-package)
- [Development](#development)
- [Security](#security)
- [Documentation](#documentation)
- [License](#license)
- [Contributing](#contributing)
- [Acknowledgements](#acknowledgements)

## Overview

`bankstatementparser-writer-xlsx` is a small, focused companion to the
[`bankstatementparser`][core] library. It does one thing well: given
already-parsed bank-statement records, write a clean Excel workbook with
a bold header row, one row per transaction, auto-sized columns, and an
optional second `Summary` sheet.

The package consumes _parsed_ data — it does not read PDFs, CSVs, or
XML itself. Parsing (and the security surface that comes with untrusted
input) lives upstream in the [`bankstatementparser`][core] core.

## Install

`bankstatementparser-writer-xlsx` runs on macOS, Linux, and Windows and
requires **Python 3.10+**. It pulls in `bankstatementparser`,
`openpyxl`, and `pandas` automatically.

```bash
pip install bankstatementparser-writer-xlsx
```

## Quick start

```python
from bankstatementparser import CsvStatementParser
from bankstatementparser_writer_xlsx import write_xlsx

parser = CsvStatementParser("statement.csv")
df = parser.parse()                      # a pandas DataFrame
write_xlsx(df, "statement.xlsx")         # one polished workbook
```

That's an Excel workbook ready for your accountant. Add a summary sheet
in one extra argument:

```python
from bankstatementparser import CsvStatementParser
from bankstatementparser_writer_xlsx import write_xlsx

parser = CsvStatementParser("statement.csv")
df = parser.parse()
write_xlsx(df, "statement.xlsx", summary=parser.get_summary())
```

## Input shapes

`write_xlsx(data, path, *, sheet_name="Transactions", summary=None)`
accepts three input shapes and normalises each to a flat table:

| Input | Column order |
| :--- | :--- |
| `pandas.DataFrame` (from a parser's `.parse()`) | the DataFrame's own column order |
| `list[bankstatementparser.Transaction]` | the stable `Transaction` field order |
| `list[dict]` | the union of keys, in first-seen order |

A header row (bold) is written to the `sheet_name` sheet, followed by
one row per record. Columns are auto-sized to their widest cell, capped
at **60 characters** so wide descriptions don't run off-screen (the cell
content itself is never truncated — only the displayed column width).

**Empty input** is accepted: an empty `list` writes an empty sheet (no
header), while an empty `DataFrame` that still carries column labels
writes a header-only sheet.

## Value coercion

Spreadsheet cells can't hold arbitrary Python objects, so the writer
coerces the rich types the parser emits:

| Python type | Written as |
| :--- | :--- |
| `decimal.Decimal` | `float` (Excel has no decimal type; floats aggregate natively) |
| `datetime.date` / `datetime.datetime` | native Excel date cell (unchanged) |
| `str`, `int`, `float`, `bool`, `None` | unchanged |
| `None` / `float('nan')` (e.g. a missing DataFrame cell) | blank cell |
| anything else | `str(value)` |

`bool` is preserved as a true/false cell (it is *not* coerced to `0`/`1`),
and a missing `list[dict]` key writes a blank cell in the same way a
`None` value does.

## Errors

`write_xlsx` validates its `data` argument and fails fast with a precise
exception rather than writing a malformed workbook:

| Condition | Raised |
| :--- | :--- |
| `data` is neither a `DataFrame` nor a `list`/`tuple` (e.g. a `str` or `int`) | `TypeError` |
| `data` is a non-empty sequence whose items are neither `dict` records nor `Transaction` objects (e.g. `[42]`) | `ValueError` |

```python
from bankstatementparser_writer_xlsx import write_xlsx

try:
    write_xlsx("not-a-table", "out.xlsx")  # a bare str is not a table
except TypeError as exc:
    print(f"rejected: {exc}")

try:
    write_xlsx([42], "out.xlsx")           # 42 is not a dict/Transaction
except ValueError as exc:
    print(f"rejected: {exc}")
```

## The summary sheet

If you pass `summary=` a mapping (for example a parser's
`get_summary()` result), the writer adds a second sheet titled
`Summary` with a bold `Key` / `Value` header and one row per item:

```python
from decimal import Decimal

from bankstatementparser_writer_xlsx import write_xlsx

transactions = [
    {"date": "2026-06-01", "description": "Salary", "amount": Decimal("3000.00")},
    {"date": "2026-06-03", "description": "Coffee Shop", "amount": Decimal("-4.20")},
]

write_xlsx(
    transactions,
    "out.xlsx",
    summary={
        "account_id": "DE89370400440532013000",
        "transaction_count": 128,
        "total_amount": Decimal("12045.67"),
        "currency": "EUR",
    },
)
```

## Examples

Six runnable examples live in [`examples/`](examples/) and are
exercised in CI on every commit. Together they cover every supported
input shape, option, coercion rule, and error path of `write_xlsx`:

- [`01_write_dataframe.py`](examples/01_write_dataframe.py) — write a
  pandas `DataFrame` to a single sheet.
- [`02_write_transactions.py`](examples/02_write_transactions.py) —
  write a list of `Transaction` objects in stable field order.
- [`03_write_dicts.py`](examples/03_write_dicts.py) — write a list of
  plain `dict` records (union of keys).
- [`04_write_with_summary.py`](examples/04_write_with_summary.py) —
  write a DataFrame plus a second `Summary` sheet via `summary=`.
- [`05_custom_sheet_name.py`](examples/05_custom_sheet_name.py) — rename
  the transactions sheet with `sheet_name=`.
- [`06_value_coercion_and_errors.py`](examples/06_value_coercion_and_errors.py)
  — `Decimal`/`date` coercion, `None`/`NaN`/missing keys as blank cells,
  the 60-character column-width cap, and the `TypeError`/`ValueError`
  error paths.

## When not to use this package

- **You need a custom sheet layout.** The single-sheet (+ optional
  Summary) structure is intentionally simple. Compose your own
  `openpyxl` workbook if you need pivot-ready, multi-sheet layouts.
- **You need `.xls` (legacy binary).** `openpyxl` writes `.xlsx` only;
  convert downstream if you must.
- **You need encrypted output.** Out of scope; encrypt the produced
  `.xlsx` downstream with a tool like `msoffcrypto-tool`.
- **You want to _read_ Excel.** This package is a writer.

## Development

```bash
git clone https://github.com/sebastienrousseau/bankstatementparser-writer-xlsx
cd bankstatementparser-writer-xlsx
poetry env use python3.12
poetry install
poetry run pytest        # 100% line + branch coverage gate
poetry run ruff check bankstatementparser_writer_xlsx tests
poetry run mypy bankstatementparser_writer_xlsx
poetry run interrogate -c pyproject.toml bankstatementparser_writer_xlsx
```

## Security

`bankstatementparser-writer-xlsx` consumes already-parsed data, not raw
statement files — the PDF/CSV/XML parsing surface lives upstream in the
[`bankstatementparser`][core] core. Reporting practice, supported
versions, and supply-chain posture are documented in
[`SECURITY.md`](SECURITY.md).

## Documentation

- [`README.md`](README.md) — this file
- [`ARCHITECTURE.md`](ARCHITECTURE.md) — module map and design decisions
- [`CHANGELOG.md`](CHANGELOG.md) — release notes
- [`ROADMAP.md`](ROADMAP.md) — what's next
- [`SECURITY.md`](SECURITY.md) — disclosure + supported versions
- [`examples/`](examples/) — runnable scripts, exercised in CI

## Ecosystem

`bankstatementparser` is part of a modular financial ecosystem. Optional companion packages provide specialized loaders, writers, AI agents, language servers, and transport protocol adapters:

| Package | GitHub Repository | PyPI | Role | Description |
| :--- | :--- | :--- | :--- | :--- |
| **`bankstatementparser`** | [`sebastienrousseau/bankstatementparser`](https://github.com/sebastienrousseau/bankstatementparser) | [![PyPI](https://img.shields.io/pypi/v/bankstatementparser.svg)](https://pypi.org/project/bankstatementparser/) | Core Engine | Unified parser for CAMT (052/053), PAIN.001, CSV, OFX, QFX, MT940, and PDF statements |
| **`bankstatementparser-mcp`** | [`sebastienrousseau/bankstatementparser-mcp`](https://github.com/sebastienrousseau/bankstatementparser-mcp) | [![PyPI](https://img.shields.io/pypi/v/bankstatementparser-mcp.svg)](https://pypi.org/project/bankstatementparser-mcp/) | AI Protocol | Model Context Protocol (MCP) server exposing statement tools to LLMs & AI agents |
| **`bankstatementparser-lsp`** | [`sebastienrousseau/bankstatementparser-lsp`](https://github.com/sebastienrousseau/bankstatementparser-lsp) | [![PyPI](https://img.shields.io/pypi/v/bankstatementparser-lsp.svg)](https://pypi.org/project/bankstatementparser-lsp/) | Developer Tooling | Language Server Protocol (LSP) with live SWIFT MT940 statement validation & diagnostics |
| **`bankstatementparser-transport-ebics`** | [`sebastienrousseau/bankstatementparser-transport-ebics`](https://github.com/sebastienrousseau/bankstatementparser-transport-ebics) | [![PyPI](https://img.shields.io/pypi/v/bankstatementparser-transport-ebics.svg)](https://pypi.org/project/bankstatementparser-transport-ebics/) | Transport | Automated bank statement retrieval over EBICS 3.0 (`H005`) and 2.5 (`H004`) protocols |
| **`bankstatementparser-writer-xlsx`** | [`sebastienrousseau/bankstatementparser-writer-xlsx`](https://github.com/sebastienrousseau/bankstatementparser-writer-xlsx) | [![PyPI](https://img.shields.io/pypi/v/bankstatementparser-writer-xlsx.svg)](https://pypi.org/project/bankstatementparser-writer-xlsx/) | Output Writer | Formats and exports parsed banking transactions into styled Microsoft Excel (`.xlsx`) workbooks |
| **`bankstatementparser-writer-qif`** | [`sebastienrousseau/bankstatementparser-writer-qif`](https://github.com/sebastienrousseau/bankstatementparser-writer-qif) | [![PyPI](https://img.shields.io/pypi/v/bankstatementparser-writer-qif.svg)](https://pypi.org/project/bankstatementparser-writer-qif/) | Output Writer | Serializes transactions into standard Quicken Interchange Format (`.qif`) exchange files |
| **`bankstatementparser-writer-ofx`** | [`sebastienrousseau/bankstatementparser-writer-ofx`](https://github.com/sebastienrousseau/bankstatementparser-writer-ofx) | [![PyPI](https://img.shields.io/pypi/v/bankstatementparser-writer-ofx.svg)](https://pypi.org/project/bankstatementparser-writer-ofx/) | Output Writer | Serializes transactions into standard Open Financial Exchange (`.ofx`) XML/SGML files |
| **`bankstatementparser-writer-swift`** | [`sebastienrousseau/bankstatementparser-writer-swift`](https://github.com/sebastienrousseau/bankstatementparser-writer-swift) | [![PyPI](https://img.shields.io/pypi/v/bankstatementparser-writer-swift.svg)](https://pypi.org/project/bankstatementparser-writer-swift/) | Output Writer | Exports transactions to SWIFT MT940 customer statements and MT942 interim reports |
| **`bankstatementparser-loader-bai2`** | [`sebastienrousseau/bankstatementparser-loader-bai2`](https://github.com/sebastienrousseau/bankstatementparser-loader-bai2) | [![PyPI](https://img.shields.io/pypi/v/bankstatementparser-loader-bai2.svg)](https://pypi.org/project/bankstatementparser-loader-bai2/) | Input Loader | Parses BAI2 cash-management and account balance statements |
| **`bankstatementparser-loader-mt942`** | [`sebastienrousseau/bankstatementparser-loader-mt942`](https://github.com/sebastienrousseau/bankstatementparser-loader-mt942) | [![PyPI](https://img.shields.io/pypi/v/bankstatementparser-loader-mt942.svg)](https://pypi.org/project/bankstatementparser-loader-mt942/) | Input Loader | Parses SWIFT MT942 interim transaction reports with credit/debit summary reconciliation |
| **`bankstatementparser-loader-cfonb`** | [`sebastienrousseau/bankstatementparser-loader-cfonb`](https://github.com/sebastienrousseau/bankstatementparser-loader-cfonb) | [![PyPI](https://img.shields.io/pypi/v/bankstatementparser-loader-cfonb.svg)](https://pypi.org/project/bankstatementparser-loader-cfonb/) | Input Loader | Parses French CFONB 120 / AFB120 120-byte fixed-width banking statement files |
| **`bankstatementparser-loader-camt054`** | [`sebastienrousseau/bankstatementparser-loader-camt054`](https://github.com/sebastienrousseau/bankstatementparser-loader-camt054) | [![PyPI](https://img.shields.io/pypi/v/bankstatementparser-loader-camt054.svg)](https://pypi.org/project/bankstatementparser-loader-camt054/) | Input Loader | Ingests ISO 20022 CAMT.054 real-time debit/credit notification stream XML |
| **`bankstatementparser-loader-sepa`** | [`sebastienrousseau/bankstatementparser-loader-sepa`](https://github.com/sebastienrousseau/bankstatementparser-loader-sepa) | [![PyPI](https://img.shields.io/pypi/v/bankstatementparser-loader-sepa.svg)](https://pypi.org/project/bankstatementparser-loader-sepa/) | Input Loader | Ingests ISO 20022 SEPA PAIN.002 payment status reports and PAIN.008 direct debit mandates |
| **`bankstatementparser-loader-bacs`** | [`sebastienrousseau/bankstatementparser-loader-bacs`](https://github.com/sebastienrousseau/bankstatementparser-loader-bacs) | [![PyPI](https://img.shields.io/pypi/v/bankstatementparser-loader-bacs.svg)](https://pypi.org/project/bankstatementparser-loader-bacs/) | Input Loader | Parses UK BACS Standard 18 / Faster Payments 106-byte fixed-width transmission files |

---

## License

Licensed under the [Apache License, Version 2.0][license-url]. Any
contribution submitted for inclusion shall be licensed as above, without
additional terms.

## Contributing

Contributions are welcome — open an issue or PR on
[the repository](https://github.com/sebastienrousseau/bankstatementparser-writer-xlsx).

## Acknowledgements

Built on the [`bankstatementparser`][core] library and
[openpyxl](https://openpyxl.readthedocs.io/).

[core]: https://github.com/sebastienrousseau/bankstatementparser
[pypi-url]: https://pypi.org/project/bankstatementparser-writer-xlsx/
[license-url]: https://opensource.org/license/apache-2-0/
[ci-url]: https://github.com/sebastienrousseau/bankstatementparser-writer-xlsx/actions/workflows/ci.yml
[pypi-badge]: https://img.shields.io/pypi/v/bankstatementparser-writer-xlsx.svg?style=for-the-badge
[python-versions-badge]: https://img.shields.io/pypi/pyversions/bankstatementparser-writer-xlsx.svg?style=for-the-badge
[license-badge]: https://img.shields.io/badge/License-Apache%202.0-blue.svg?style=for-the-badge
[coverage-badge]: https://img.shields.io/badge/Coverage-100%25-brightgreen?style=for-the-badge

