Metadata-Version: 2.5
Name: pdf-statement-parser
Version: 0.1.0a1
Summary: Extract account metadata and transactions from bank and credit card PDF statements, with a plugin per statement format.
Project-URL: Homepage, https://github.com/lukasz-karolewski/pdf-statement-parser
Project-URL: Issues, https://github.com/lukasz-karolewski/pdf-statement-parser/issues
Author: Lukasz Karolewski
License-Expression: MIT
License-File: LICENSE
Keywords: bank statement,chase,finance,parser,pdf,transactions
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
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: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: pdfplumber>=0.11
Provides-Extra: dev
Requires-Dist: fpdf2>=2.7; extra == 'dev'
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: pre-commit>=3.7; extra == 'dev'
Requires-Dist: pytest-cov>=5; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Description-Content-Type: text/markdown

# pdf-statement-parser

`statement-parser` extracts account metadata and transactions from bank statement PDFs.
Each statement format is a parser plugin. The registry runs detection and picks the
best parser for a document.

Do not upload real statements to issues, pull requests, or fixtures. Use
`statement-parser dump` on your own machine and redact names, addresses, account
numbers, and amounts before sharing text.

## Install

```bash
pip install pdf-statement-parser
```

For local development:

```bash
uv pip install --python .venv/bin/python -e '.[dev]'
```

## CLI quickstart

Parse one file as JSON:

```bash
statement-parser parse examples/fake-example-bank.pdf
```

Example output with fake data:

```json
[
  {
    "source": "examples/fake-example-bank.pdf",
    "parser_id": "example-bank",
    "bank": "Example Bank",
    "page_count": 1,
    "statements": [
      {
        "bank": "Example Bank",
        "account_type": "checking",
        "account_number": "00001234",
        "period_start": "2026-01-01",
        "period_end": "2026-01-31",
        "account_name": "Example Checking",
        "account_holder": "Jane Doe",
        "currency": "USD",
        "opening_balance": "100.00",
        "closing_balance": "130.00",
        "total_deposits": "50.00",
        "total_expenses": "20.00",
        "transactions": [
          {
            "date": "2026-01-05",
            "description": "Coffee",
            "amount": "-20.00",
            "balance": "80.00",
            "kind": "purchase",
            "post_date": null,
            "extra": {}
          }
        ],
        "extra": {},
        "warnings": [],
        "account_last4": "1234"
      }
    ]
  }
]
```

Useful commands:

```bash
statement-parser parse statements/ --format csv -o statements.csv -r
statement-parser transactions statements/ --format csv -o transactions.csv
statement-parser detect statements/example.pdf --all
statement-parser validate statements/ -j 8 --report report.json
statement-parser dump statements/example.pdf --page 1
statement-parser parsers
python -m pdf_statement_parser parse statements/example.pdf
```

Directories expand to `*.pdf` in that directory. `parse -r` searches directories
recursively. `validate` always searches directories recursively because corpus
validation usually works on nested folders.

## Python API quickstart

```python
from pdf_statement_parser import parse

result = parse("statement.pdf")
statement = result.statement
print(statement.bank, statement.account_last4, statement.closing_balance)
for transaction in statement.transactions:
    print(transaction.date, transaction.description, transaction.amount)
```

Use a specific parser when you already know the format:

```python
result = parse("statement.pdf", parser="chase-credit-card")
```

## Data model

| Field | Meaning |
| --- | --- |
| `ParseResult` | One parsed PDF, including parser id, bank, source, page count, and statements. |
| `Statement` | One account in one statement period. Consolidated PDFs can return several statements. |
| `Transaction` | One transaction with date, description, signed amount, optional running balance, and kind. |
| `Transaction.amount` | Signed from the account holder's point of view. Positive means money in. Negative means money out. |
| `total_deposits` | Non-negative total for money in during the period. |
| `total_expenses` | Non-negative total for money out during the period. |
| `opening_balance`, `closing_balance` | Balances as printed by the bank. For credit cards, a positive balance is the amount owed. |

JSON writes `Decimal` values as strings. CSV writes amounts as plain numeric text.

## Supported statements

| Bank | Statement type | Status |
| --- | --- | --- |
| Chase | Credit cards | See `docs/providers/chase.md`. |
| Chase | Checking and savings | See `docs/providers/chase.md`. |
| Chase | Consolidated personal statements | See `docs/providers/chase.md`. |
| Chase | Business checking and savings | See `docs/providers/chase.md`. |

## Detection

Each parser implements `detect(document) -> float`. The registry runs every
parser, clamps scores to 0.0 through 1.0, ignores parsers that raise during
detection, and picks the highest score at or above the detection threshold. If
scores tie, the parser with the higher `priority` wins.

## Writing a parser

Start with `statement-parser dump your-statement.pdf`. Redact the output before
sharing it. Follow `docs/writing-a-parser.md` for in-tree parsers and plugins.
The example plugin in `examples/example_bank_plugin/` shows the entry point
needed for out-of-tree packages.

## Privacy

Bank statements contain names, addresses, account numbers, balances, and
transactions. Keep real PDFs out of the repository. Redact dump output before
posting it. Synthetic PDFs are fine for tests when they contain only fake data.

## License

MIT. See `LICENSE`.
