Metadata-Version: 2.4
Name: xfina
Version: 0.6.0
Classifier: Programming Language :: Rust
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
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: License :: OSI Approved :: Apache Software License
Classifier: Topic :: Office/Business :: Financial
Summary: Python bindings for xfina financial parsers
Requires-Python: >=3.8
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM

<p align="center">
  <a href="https://github.com/sakthipriyan/xfina" target="_blank">
    <img src="https://github.com/sakthipriyan/xfina/raw/main/web/public/favicon.svg" width="120" height="120" alt="Xfina Logo"/>
  </a>
</p>

# [Xfina (Python Bindings)](https://github.com/sakthipriyan/xfina)

[![Crates.io](https://img.shields.io/crates/v/xfina.svg?color=orange)](https://crates.io/crates/xfina)
[![PyPI](https://img.shields.io/pypi/v/xfina.svg?color=blue)](https://pypi.org/project/xfina/)
[![npm](https://img.shields.io/npm/v/xfina-wasm.svg?color=yellow)](https://www.npmjs.com/package/xfina-wasm)

**Xfina** is a blazingly fast library for parsing Indian financial statements (Bank Accounts, Credit Cards, Mutual Funds) and international brokers (IBKR), written in Rust and exposed to Python via PyO3.

It converts raw PDFs, Excel files, and CSVs into structured, ReBIT-compliant JSON dictionaries in milliseconds.

## Installation

```bash
pip install xfina
```

## Quick Start

The Python bindings expose the same entry point as the Rust core. To keep the core parsing logic as pure functions without side-effects (like file I/O), the library requires raw bytes to be passed in rather than file paths.

### Parsing a Credit Card Statement

```python
import xfina

with open("statement.xls", "rb") as fh:
    data = fh.read()

# Hand over the bytes; the format is worked out from the content.
statement = xfina.parse(data, filename="statement.xls")

statement["format"]       # "ba-hdfc"
statement["category"]     # "bank_account"
statement["institution"]  # "HDFC Bank"
statement["detection"]    # how it was identified, plus the file's metadata
statement["validation"]   # the two-level validation report
statement["data"]         # the account, in the requested schema

# ReBIT output, or a pinned format that skips detection:
xfina.parse(data, schema="rebit")
xfina.parse(data, **{"as": "ba-hdfc"})
```

Failures raise `xfina.XfinaParseError`, which is where this differs from the
JS binding: exceptions are the idiom here, so the same information arrives as
attributes rather than in an error envelope.

```python
try:
    xfina.parse(data, filename=name)
except xfina.XfinaParseError as e:
    if e.kind == "password_required":
        prompt_for_password(e.format)   # the format the filename suggested
```

## The four functions

| Function | Purpose |
|---|---|
| `parse(bytes, password=None, filename=None, modified_timestamp=None, **{"as": None}, schema=None)` | Identify and parse a statement. |
| `detect(bytes, password=None, filename=None, modified_timestamp=None)` | Identify a statement without parsing it. |
| `formats()` | Every format this build knows, with `id`, `category`, `institution`, `containers` and `enabled`. |
| `version()` | The version of the parsers actually running. |


