open-finance-toolkit 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- open_finance_toolkit-0.1.0/.gitignore +220 -0
- open_finance_toolkit-0.1.0/CHANGELOG.md +28 -0
- open_finance_toolkit-0.1.0/LICENSE +21 -0
- open_finance_toolkit-0.1.0/PKG-INFO +169 -0
- open_finance_toolkit-0.1.0/README.md +113 -0
- open_finance_toolkit-0.1.0/docs/adding-a-bank-format.md +78 -0
- open_finance_toolkit-0.1.0/docs/publishing-to-pypi.md +64 -0
- open_finance_toolkit-0.1.0/docs/roadmap.md +36 -0
- open_finance_toolkit-0.1.0/docs/usage.md +165 -0
- open_finance_toolkit-0.1.0/examples/dashboard/README.md +15 -0
- open_finance_toolkit-0.1.0/examples/dashboard/app.py +757 -0
- open_finance_toolkit-0.1.0/examples/dashboard/requirements.txt +3 -0
- open_finance_toolkit-0.1.0/examples/quickstart.py +44 -0
- open_finance_toolkit-0.1.0/examples/sample_debit_credit.csv +17 -0
- open_finance_toolkit-0.1.0/examples/sample_transactions.csv +11 -0
- open_finance_toolkit-0.1.0/pyproject.toml +62 -0
- open_finance_toolkit-0.1.0/src/open_finance_toolkit/__init__.py +51 -0
- open_finance_toolkit-0.1.0/src/open_finance_toolkit/__main__.py +7 -0
- open_finance_toolkit-0.1.0/src/open_finance_toolkit/categorize.py +218 -0
- open_finance_toolkit-0.1.0/src/open_finance_toolkit/cli.py +79 -0
- open_finance_toolkit-0.1.0/src/open_finance_toolkit/duplicates.py +97 -0
- open_finance_toolkit-0.1.0/src/open_finance_toolkit/exceptions.py +42 -0
- open_finance_toolkit-0.1.0/src/open_finance_toolkit/formats.py +219 -0
- open_finance_toolkit-0.1.0/src/open_finance_toolkit/importer.py +187 -0
- open_finance_toolkit-0.1.0/src/open_finance_toolkit/parsing.py +41 -0
- open_finance_toolkit-0.1.0/src/open_finance_toolkit/py.typed +0 -0
- open_finance_toolkit-0.1.0/src/open_finance_toolkit/schema.py +13 -0
- open_finance_toolkit-0.1.0/src/open_finance_toolkit/summary.py +102 -0
- open_finance_toolkit-0.1.0/tests/test_categorize.py +93 -0
- open_finance_toolkit-0.1.0/tests/test_cli.py +50 -0
- open_finance_toolkit-0.1.0/tests/test_duplicates.py +66 -0
- open_finance_toolkit-0.1.0/tests/test_importer.py +229 -0
- open_finance_toolkit-0.1.0/tests/test_summary.py +104 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[codz]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
# Usually these files are written by a python script from a template
|
|
31
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
*.py.cover
|
|
50
|
+
*.lcov
|
|
51
|
+
.hypothesis/
|
|
52
|
+
.pytest_cache/
|
|
53
|
+
cover/
|
|
54
|
+
|
|
55
|
+
# Translations
|
|
56
|
+
*.mo
|
|
57
|
+
*.pot
|
|
58
|
+
|
|
59
|
+
# Django stuff:
|
|
60
|
+
*.log
|
|
61
|
+
local_settings.py
|
|
62
|
+
db.sqlite3
|
|
63
|
+
db.sqlite3-journal
|
|
64
|
+
|
|
65
|
+
# Flask stuff:
|
|
66
|
+
instance/
|
|
67
|
+
.webassets-cache
|
|
68
|
+
|
|
69
|
+
# Scrapy stuff:
|
|
70
|
+
.scrapy
|
|
71
|
+
|
|
72
|
+
# Sphinx documentation
|
|
73
|
+
docs/_build/
|
|
74
|
+
|
|
75
|
+
# PyBuilder
|
|
76
|
+
.pybuilder/
|
|
77
|
+
target/
|
|
78
|
+
|
|
79
|
+
# Jupyter Notebook
|
|
80
|
+
.ipynb_checkpoints
|
|
81
|
+
|
|
82
|
+
# IPython
|
|
83
|
+
profile_default/
|
|
84
|
+
ipython_config.py
|
|
85
|
+
|
|
86
|
+
# pyenv
|
|
87
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
88
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
89
|
+
# .python-version
|
|
90
|
+
|
|
91
|
+
# pipenv
|
|
92
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
93
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
94
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
95
|
+
# install all needed dependencies.
|
|
96
|
+
# Pipfile.lock
|
|
97
|
+
|
|
98
|
+
# uv
|
|
99
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
100
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
101
|
+
# commonly ignored for libraries.
|
|
102
|
+
# uv.lock
|
|
103
|
+
|
|
104
|
+
# poetry
|
|
105
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
106
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
107
|
+
# commonly ignored for libraries.
|
|
108
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
109
|
+
# poetry.lock
|
|
110
|
+
# poetry.toml
|
|
111
|
+
|
|
112
|
+
# pdm
|
|
113
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
114
|
+
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
|
115
|
+
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
|
116
|
+
# pdm.lock
|
|
117
|
+
# pdm.toml
|
|
118
|
+
.pdm-python
|
|
119
|
+
.pdm-build/
|
|
120
|
+
|
|
121
|
+
# pixi
|
|
122
|
+
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
|
123
|
+
# pixi.lock
|
|
124
|
+
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
|
125
|
+
# in the .venv directory. It is recommended not to include this directory in version control.
|
|
126
|
+
.pixi/*
|
|
127
|
+
!.pixi/config.toml
|
|
128
|
+
|
|
129
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
130
|
+
__pypackages__/
|
|
131
|
+
|
|
132
|
+
# Celery stuff
|
|
133
|
+
celerybeat-schedule*
|
|
134
|
+
celerybeat.pid
|
|
135
|
+
|
|
136
|
+
# Redis
|
|
137
|
+
*.rdb
|
|
138
|
+
*.aof
|
|
139
|
+
*.pid
|
|
140
|
+
|
|
141
|
+
# RabbitMQ
|
|
142
|
+
mnesia/
|
|
143
|
+
rabbitmq/
|
|
144
|
+
rabbitmq-data/
|
|
145
|
+
|
|
146
|
+
# ActiveMQ
|
|
147
|
+
activemq-data/
|
|
148
|
+
|
|
149
|
+
# SageMath parsed files
|
|
150
|
+
*.sage.py
|
|
151
|
+
|
|
152
|
+
# Environments
|
|
153
|
+
.env
|
|
154
|
+
.envrc
|
|
155
|
+
.venv
|
|
156
|
+
env/
|
|
157
|
+
venv/
|
|
158
|
+
ENV/
|
|
159
|
+
env.bak/
|
|
160
|
+
venv.bak/
|
|
161
|
+
|
|
162
|
+
# Spyder project settings
|
|
163
|
+
.spyderproject
|
|
164
|
+
.spyproject
|
|
165
|
+
|
|
166
|
+
# Rope project settings
|
|
167
|
+
.ropeproject
|
|
168
|
+
|
|
169
|
+
# mkdocs/Zensical documentation
|
|
170
|
+
/site
|
|
171
|
+
|
|
172
|
+
# mypy
|
|
173
|
+
.mypy_cache/
|
|
174
|
+
.dmypy.json
|
|
175
|
+
dmypy.json
|
|
176
|
+
|
|
177
|
+
# Pyre type checker
|
|
178
|
+
.pyre/
|
|
179
|
+
|
|
180
|
+
# pytype static type analyzer
|
|
181
|
+
.pytype/
|
|
182
|
+
|
|
183
|
+
# Cython debug symbols
|
|
184
|
+
cython_debug/
|
|
185
|
+
|
|
186
|
+
# PyCharm
|
|
187
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
188
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
189
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
190
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
191
|
+
# .idea/
|
|
192
|
+
|
|
193
|
+
# Abstra
|
|
194
|
+
# Abstra is an AI-powered process automation framework.
|
|
195
|
+
# Ignore directories containing user credentials, local state, and settings.
|
|
196
|
+
# Learn more at https://abstra.io/docs
|
|
197
|
+
.abstra/
|
|
198
|
+
|
|
199
|
+
# Visual Studio Code
|
|
200
|
+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore that
|
|
201
|
+
# can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
|
202
|
+
# and can be added to the global gitignore or merged into this file. However, if you prefer, you
|
|
203
|
+
# could uncomment the following to ignore the entire vscode folder
|
|
204
|
+
# .vscode/
|
|
205
|
+
# Temporary file for partial code execution
|
|
206
|
+
tempCodeRunnerFile.py
|
|
207
|
+
|
|
208
|
+
# Ruff stuff:
|
|
209
|
+
.ruff_cache/
|
|
210
|
+
|
|
211
|
+
# PyPI configuration file
|
|
212
|
+
.pypirc
|
|
213
|
+
|
|
214
|
+
# Marimo
|
|
215
|
+
marimo/_static/
|
|
216
|
+
marimo/_lsp/
|
|
217
|
+
__marimo__/
|
|
218
|
+
|
|
219
|
+
# Streamlit
|
|
220
|
+
.streamlit/secrets.toml
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are recorded here. The format follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
|
|
5
|
+
uses [Semantic Versioning](https://semver.org/).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [0.1.0] - 2026-11-12
|
|
10
|
+
|
|
11
|
+
First release as a reusable library. It grew out of the Personal Finance
|
|
12
|
+
Analytics dashboard.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
- `load_transactions` and `clean_transactions` to read and standardise CSVs, with automatic layout detection and skipping of lines above the table.
|
|
16
|
+
- Layouts: `standard`, `generic-debit-credit`, `generic-signed`, and unverified `hdfc`, `sbi`, `icici`, `axis`.
|
|
17
|
+
- `categorize`, a keyword-based categoriser with built-in rules and support for your own.
|
|
18
|
+
- `mark_duplicates`, `find_duplicates`, `remove_duplicates`.
|
|
19
|
+
- `totals`, `summarize` (by month or year) and `spending_by_category`.
|
|
20
|
+
- A command-line tool: `open-finance-toolkit summary` and `open-finance-toolkit categories`.
|
|
21
|
+
- Tests, continuous integration, contribution guidelines and issue templates.
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
- The Streamlit dashboard moved to `examples/dashboard/` and is otherwise unchanged.
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
- ISO dates such as `2026-11-01` are no longer read day-first (which turned them into 11 January). This fix is in the library. The demo dashboard still has the old behaviour.
|
|
28
|
+
- A blank category now becomes `Uncategorised` instead of the text `nan`.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Itz-https
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: open-finance-toolkit
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Clean, categorise and summarise bank transaction CSVs, with support for Indian bank statement formats.
|
|
5
|
+
Project-URL: Homepage, https://github.com/Itz-https/open-finance-toolkit
|
|
6
|
+
Project-URL: Documentation, https://github.com/Itz-https/open-finance-toolkit/tree/main/docs
|
|
7
|
+
Project-URL: Issues, https://github.com/Itz-https/open-finance-toolkit/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/Itz-https/open-finance-toolkit/blob/main/CHANGELOG.md
|
|
9
|
+
Author: Itz-https
|
|
10
|
+
License: MIT License
|
|
11
|
+
|
|
12
|
+
Copyright (c) 2026 Itz-https
|
|
13
|
+
|
|
14
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
15
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
16
|
+
in the Software without restriction, including without limitation the rights
|
|
17
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
18
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
19
|
+
furnished to do so, subject to the following conditions:
|
|
20
|
+
|
|
21
|
+
The above copyright notice and this permission notice shall be included in all
|
|
22
|
+
copies or substantial portions of the Software.
|
|
23
|
+
|
|
24
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
25
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
26
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
27
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
28
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
29
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
30
|
+
SOFTWARE.
|
|
31
|
+
License-File: LICENSE
|
|
32
|
+
Keywords: bank statement,csv,finance,india,pandas,personal finance,transactions
|
|
33
|
+
Classifier: Development Status :: 3 - Alpha
|
|
34
|
+
Classifier: Intended Audience :: Developers
|
|
35
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
36
|
+
Classifier: Programming Language :: Python :: 3
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
41
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
42
|
+
Classifier: Topic :: Office/Business :: Financial
|
|
43
|
+
Classifier: Typing :: Typed
|
|
44
|
+
Requires-Python: >=3.9
|
|
45
|
+
Requires-Dist: pandas>=2.0
|
|
46
|
+
Provides-Extra: dashboard
|
|
47
|
+
Requires-Dist: plotly; extra == 'dashboard'
|
|
48
|
+
Requires-Dist: streamlit; extra == 'dashboard'
|
|
49
|
+
Provides-Extra: dev
|
|
50
|
+
Requires-Dist: build; extra == 'dev'
|
|
51
|
+
Requires-Dist: pytest-cov; extra == 'dev'
|
|
52
|
+
Requires-Dist: pytest>=7; extra == 'dev'
|
|
53
|
+
Requires-Dist: ruff; extra == 'dev'
|
|
54
|
+
Requires-Dist: twine; extra == 'dev'
|
|
55
|
+
Description-Content-Type: text/markdown
|
|
56
|
+
|
|
57
|
+
# Open Finance Toolkit
|
|
58
|
+
|
|
59
|
+
Clean, categorise and summarise bank transaction CSVs in Python, with a focus on Indian bank statement formats.
|
|
60
|
+
|
|
61
|
+
[](https://github.com/Itz-https/open-finance-toolkit/actions/workflows/ci.yml)
|
|
62
|
+
[](LICENSE)
|
|
63
|
+
|
|
64
|
+
> **Status: alpha (v0.1).** The core works and is tested, but the bank layouts for HDFC, SBI, ICICI and Axis are built from commonly seen column headers and have **not yet been checked against real statements**. If you have a statement from any bank, you can help. See [Contributing](#contributing).
|
|
65
|
+
|
|
66
|
+
## Why this exists
|
|
67
|
+
|
|
68
|
+
Every bank exports transactions slightly differently. Some put account details above the table. Some use separate Debit and Credit columns, others one signed Amount column. Dates may be `03/04/2026` or `2026-04-03`, and amounts look like `1,25,000.50`. Every developer who builds a budgeting tool ends up rewriting the same cleaning code.
|
|
69
|
+
|
|
70
|
+
Open Finance Toolkit does that part once, so you can focus on your app.
|
|
71
|
+
|
|
72
|
+
- Reads messy statement CSVs and returns one clean, standard table
|
|
73
|
+
- Detects the layout automatically and skips lines above the table
|
|
74
|
+
- Categorises transactions with simple rules you can read and extend
|
|
75
|
+
- Flags duplicate transactions without deleting anything behind your back
|
|
76
|
+
- Calculates income, expenses, savings and savings rate
|
|
77
|
+
- Summarises by month or year
|
|
78
|
+
- Runs entirely on your computer. No network calls, no accounts, no tracking.
|
|
79
|
+
|
|
80
|
+
## Install
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
pip install open-finance-toolkit
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Requires Python 3.9 or newer. The only dependency is `pandas`.
|
|
87
|
+
|
|
88
|
+
> The package is not on PyPI yet. Until the first release, install from GitHub:
|
|
89
|
+
> `pip install git+https://github.com/Itz-https/open-finance-toolkit.git`
|
|
90
|
+
|
|
91
|
+
## Quick start
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
from open_finance_toolkit import load_transactions, categorize, summarize, totals
|
|
95
|
+
|
|
96
|
+
transactions = load_transactions("statement.csv") # any supported layout
|
|
97
|
+
transactions = categorize(transactions) # fill in categories
|
|
98
|
+
|
|
99
|
+
print(totals(transactions))
|
|
100
|
+
print(summarize(transactions, by="month"))
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Example output from the included fictional statement:
|
|
104
|
+
|
|
105
|
+
```text
|
|
106
|
+
Income: 85,312.00
|
|
107
|
+
Expenses: 32,567.50
|
|
108
|
+
Savings: 52,744.50
|
|
109
|
+
Savings rate: 61.8%
|
|
110
|
+
|
|
111
|
+
Period Income Expenses Savings SavingsRate
|
|
112
|
+
2026-10 85312.0 32567.5 52744.5 61.825417
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Run the full tour with `python examples/quickstart.py`.
|
|
116
|
+
|
|
117
|
+
### Command line
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
open-finance-toolkit summary statement.csv --by month
|
|
121
|
+
open-finance-toolkit categories statement.csv
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## What you get back
|
|
125
|
+
|
|
126
|
+
`load_transactions` returns a pandas DataFrame with the same columns no matter which bank the file came from:
|
|
127
|
+
|
|
128
|
+
| Column | Meaning |
|
|
129
|
+
|---|---|
|
|
130
|
+
| `Date` | Transaction date (datetime) |
|
|
131
|
+
| `Type` | `Income` or `Expense` |
|
|
132
|
+
| `Category` | Category, or `Uncategorised` until you call `categorize` |
|
|
133
|
+
| `Amount` | Always positive |
|
|
134
|
+
| `Description` | The bank's narration text |
|
|
135
|
+
|
|
136
|
+
## Supported layouts
|
|
137
|
+
|
|
138
|
+
| Layout | Status |
|
|
139
|
+
|---|---|
|
|
140
|
+
| `standard`: Date, Type, Category, Amount | Verified (the original dashboard format) |
|
|
141
|
+
| `generic-debit-credit`: any file with separate Debit and Credit columns | Works on test data, not yet on real statements |
|
|
142
|
+
| `generic-signed`: any file with one signed Amount column | Works on test data, not yet on real statements |
|
|
143
|
+
| `hdfc`, `sbi`, `icici`, `axis` | **Unverified.** Based on commonly seen headers |
|
|
144
|
+
|
|
145
|
+
Anything the named layouts miss usually still loads through the generic ones. Details and how to add a bank are in [docs/adding-a-bank-format.md](docs/adding-a-bank-format.md).
|
|
146
|
+
|
|
147
|
+
## Documentation
|
|
148
|
+
|
|
149
|
+
- [Usage guide](docs/usage.md): every function with examples
|
|
150
|
+
- [Adding a bank format](docs/adding-a-bank-format.md)
|
|
151
|
+
- [Roadmap](docs/roadmap.md)
|
|
152
|
+
- [Publishing to PyPI](docs/publishing-to-pypi.md) (for maintainers)
|
|
153
|
+
- [Changelog](CHANGELOG.md)
|
|
154
|
+
|
|
155
|
+
## The demo dashboard
|
|
156
|
+
|
|
157
|
+
The original Streamlit dashboard lives in [`examples/dashboard`](examples/dashboard) as a demo of what you can build on top of the library.
|
|
158
|
+
|
|
159
|
+
## Contributing
|
|
160
|
+
|
|
161
|
+
Contributions of every size are welcome, including fixing a typo. The most valuable thing you can do is **verify or add a bank format**: open a [bank format request](https://github.com/Itz-https/open-finance-toolkit/issues/new?template=bank_format_request.yml) with the column headers of your statement (never the real transactions). Read [CONTRIBUTING.md](CONTRIBUTING.md) to get started.
|
|
162
|
+
|
|
163
|
+
## Privacy
|
|
164
|
+
|
|
165
|
+
Never post real statements, account numbers or personal details in issues or pull requests. The test data in this repository is entirely fictional.
|
|
166
|
+
|
|
167
|
+
## License
|
|
168
|
+
|
|
169
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Open Finance Toolkit
|
|
2
|
+
|
|
3
|
+
Clean, categorise and summarise bank transaction CSVs in Python, with a focus on Indian bank statement formats.
|
|
4
|
+
|
|
5
|
+
[](https://github.com/Itz-https/open-finance-toolkit/actions/workflows/ci.yml)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
> **Status: alpha (v0.1).** The core works and is tested, but the bank layouts for HDFC, SBI, ICICI and Axis are built from commonly seen column headers and have **not yet been checked against real statements**. If you have a statement from any bank, you can help. See [Contributing](#contributing).
|
|
9
|
+
|
|
10
|
+
## Why this exists
|
|
11
|
+
|
|
12
|
+
Every bank exports transactions slightly differently. Some put account details above the table. Some use separate Debit and Credit columns, others one signed Amount column. Dates may be `03/04/2026` or `2026-04-03`, and amounts look like `1,25,000.50`. Every developer who builds a budgeting tool ends up rewriting the same cleaning code.
|
|
13
|
+
|
|
14
|
+
Open Finance Toolkit does that part once, so you can focus on your app.
|
|
15
|
+
|
|
16
|
+
- Reads messy statement CSVs and returns one clean, standard table
|
|
17
|
+
- Detects the layout automatically and skips lines above the table
|
|
18
|
+
- Categorises transactions with simple rules you can read and extend
|
|
19
|
+
- Flags duplicate transactions without deleting anything behind your back
|
|
20
|
+
- Calculates income, expenses, savings and savings rate
|
|
21
|
+
- Summarises by month or year
|
|
22
|
+
- Runs entirely on your computer. No network calls, no accounts, no tracking.
|
|
23
|
+
|
|
24
|
+
## Install
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install open-finance-toolkit
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Requires Python 3.9 or newer. The only dependency is `pandas`.
|
|
31
|
+
|
|
32
|
+
> The package is not on PyPI yet. Until the first release, install from GitHub:
|
|
33
|
+
> `pip install git+https://github.com/Itz-https/open-finance-toolkit.git`
|
|
34
|
+
|
|
35
|
+
## Quick start
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
from open_finance_toolkit import load_transactions, categorize, summarize, totals
|
|
39
|
+
|
|
40
|
+
transactions = load_transactions("statement.csv") # any supported layout
|
|
41
|
+
transactions = categorize(transactions) # fill in categories
|
|
42
|
+
|
|
43
|
+
print(totals(transactions))
|
|
44
|
+
print(summarize(transactions, by="month"))
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Example output from the included fictional statement:
|
|
48
|
+
|
|
49
|
+
```text
|
|
50
|
+
Income: 85,312.00
|
|
51
|
+
Expenses: 32,567.50
|
|
52
|
+
Savings: 52,744.50
|
|
53
|
+
Savings rate: 61.8%
|
|
54
|
+
|
|
55
|
+
Period Income Expenses Savings SavingsRate
|
|
56
|
+
2026-10 85312.0 32567.5 52744.5 61.825417
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Run the full tour with `python examples/quickstart.py`.
|
|
60
|
+
|
|
61
|
+
### Command line
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
open-finance-toolkit summary statement.csv --by month
|
|
65
|
+
open-finance-toolkit categories statement.csv
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## What you get back
|
|
69
|
+
|
|
70
|
+
`load_transactions` returns a pandas DataFrame with the same columns no matter which bank the file came from:
|
|
71
|
+
|
|
72
|
+
| Column | Meaning |
|
|
73
|
+
|---|---|
|
|
74
|
+
| `Date` | Transaction date (datetime) |
|
|
75
|
+
| `Type` | `Income` or `Expense` |
|
|
76
|
+
| `Category` | Category, or `Uncategorised` until you call `categorize` |
|
|
77
|
+
| `Amount` | Always positive |
|
|
78
|
+
| `Description` | The bank's narration text |
|
|
79
|
+
|
|
80
|
+
## Supported layouts
|
|
81
|
+
|
|
82
|
+
| Layout | Status |
|
|
83
|
+
|---|---|
|
|
84
|
+
| `standard`: Date, Type, Category, Amount | Verified (the original dashboard format) |
|
|
85
|
+
| `generic-debit-credit`: any file with separate Debit and Credit columns | Works on test data, not yet on real statements |
|
|
86
|
+
| `generic-signed`: any file with one signed Amount column | Works on test data, not yet on real statements |
|
|
87
|
+
| `hdfc`, `sbi`, `icici`, `axis` | **Unverified.** Based on commonly seen headers |
|
|
88
|
+
|
|
89
|
+
Anything the named layouts miss usually still loads through the generic ones. Details and how to add a bank are in [docs/adding-a-bank-format.md](docs/adding-a-bank-format.md).
|
|
90
|
+
|
|
91
|
+
## Documentation
|
|
92
|
+
|
|
93
|
+
- [Usage guide](docs/usage.md): every function with examples
|
|
94
|
+
- [Adding a bank format](docs/adding-a-bank-format.md)
|
|
95
|
+
- [Roadmap](docs/roadmap.md)
|
|
96
|
+
- [Publishing to PyPI](docs/publishing-to-pypi.md) (for maintainers)
|
|
97
|
+
- [Changelog](CHANGELOG.md)
|
|
98
|
+
|
|
99
|
+
## The demo dashboard
|
|
100
|
+
|
|
101
|
+
The original Streamlit dashboard lives in [`examples/dashboard`](examples/dashboard) as a demo of what you can build on top of the library.
|
|
102
|
+
|
|
103
|
+
## Contributing
|
|
104
|
+
|
|
105
|
+
Contributions of every size are welcome, including fixing a typo. The most valuable thing you can do is **verify or add a bank format**: open a [bank format request](https://github.com/Itz-https/open-finance-toolkit/issues/new?template=bank_format_request.yml) with the column headers of your statement (never the real transactions). Read [CONTRIBUTING.md](CONTRIBUTING.md) to get started.
|
|
106
|
+
|
|
107
|
+
## Privacy
|
|
108
|
+
|
|
109
|
+
Never post real statements, account numbers or personal details in issues or pull requests. The test data in this repository is entirely fictional.
|
|
110
|
+
|
|
111
|
+
## License
|
|
112
|
+
|
|
113
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Adding or verifying a bank format
|
|
2
|
+
|
|
3
|
+
A *layout* tells the library which column headers mean what. Adding a bank is usually one small entry in `src/open_finance_toolkit/formats.py`.
|
|
4
|
+
|
|
5
|
+
## Step 1: collect only what is safe to share
|
|
6
|
+
|
|
7
|
+
From your statement you need:
|
|
8
|
+
|
|
9
|
+
1. The **header row** (the line with column names).
|
|
10
|
+
2. Any lines **above** the header (bank name, account details). Replace personal details with fake ones.
|
|
11
|
+
3. How **dates** look, with a made-up example such as `05/11/26`.
|
|
12
|
+
4. How **amounts** are shown: separate Debit and Credit columns, one signed column, or an extra Dr/Cr column.
|
|
13
|
+
|
|
14
|
+
Never share real transactions, names, account numbers or balances.
|
|
15
|
+
|
|
16
|
+
## Step 2: see what already happens
|
|
17
|
+
|
|
18
|
+
Create a tiny fake file with your header row and two invented rows, then run:
|
|
19
|
+
|
|
20
|
+
```python
|
|
21
|
+
from open_finance_toolkit import load_transactions
|
|
22
|
+
df = load_transactions("fake.csv")
|
|
23
|
+
print(df.attrs["layout"])
|
|
24
|
+
print(df)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
If the dates, types and amounts look right, the existing generic layout already works. Tell us in an issue. That is a valuable contribution because it lets us mark the layout verified.
|
|
28
|
+
|
|
29
|
+
## Step 3: add a layout
|
|
30
|
+
|
|
31
|
+
Open `formats.py` and add an entry to `LAYOUTS`, **above** the two `generic-` entries:
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
Layout(
|
|
35
|
+
name="kotak",
|
|
36
|
+
label="Kotak Mahindra Bank (unverified)",
|
|
37
|
+
kind="debit_credit",
|
|
38
|
+
date=("transactiondate",),
|
|
39
|
+
description=("narration",),
|
|
40
|
+
debit=("debitamount",),
|
|
41
|
+
credit=("creditamount",),
|
|
42
|
+
),
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Header names are written **normalised**: lower-case, with everything except letters and digits removed. `Withdrawal Amount (INR )` becomes `withdrawalamountinr`.
|
|
46
|
+
|
|
47
|
+
`kind` is one of:
|
|
48
|
+
|
|
49
|
+
| kind | Amounts look like |
|
|
50
|
+
|---|---|
|
|
51
|
+
| `debit_credit` | Separate Debit and Credit columns |
|
|
52
|
+
| `signed` | One Amount column, negative means money out |
|
|
53
|
+
| `typed` | A Type column says Income or Expense |
|
|
54
|
+
|
|
55
|
+
Leave `verified` off until someone has checked the layout against a real statement. Set `verified=True` only in a pull request that says who checked it, and with what kind of statement (savings, credit card, and so on).
|
|
56
|
+
|
|
57
|
+
## Step 4: add a test
|
|
58
|
+
|
|
59
|
+
In `tests/test_importer.py`, add your header to the `test_other_bank_style_headers` parameter list:
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
("Transaction Date,Narration,Debit Amount,Credit Amount", "kotak"),
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Run `pytest`.
|
|
66
|
+
|
|
67
|
+
## Step 5: open a pull request
|
|
68
|
+
|
|
69
|
+
Mention the bank, the type of statement, and whether you tested a real file. Do not attach the file.
|
|
70
|
+
|
|
71
|
+
## Things we cannot handle yet
|
|
72
|
+
|
|
73
|
+
Help is welcome with these:
|
|
74
|
+
|
|
75
|
+
- Statements where one column holds both the amount and `Dr`/`Cr` (for example `1,250.00 Dr`)
|
|
76
|
+
- Credit card statements that use a different sign convention
|
|
77
|
+
- PDF statements (the library reads CSV only)
|
|
78
|
+
- Statements with several account sections in one file
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Publishing to PyPI (maintainers)
|
|
2
|
+
|
|
3
|
+
PyPI is where `pip install open-finance-toolkit` downloads packages from. This project publishes **automatically from GitHub** using *trusted publishing*, so there are no passwords or tokens to store, and you can do the whole thing from a web browser.
|
|
4
|
+
|
|
5
|
+
> **Important:** a version number on PyPI can never be reused or replaced, even if you delete the release. Always test before releasing.
|
|
6
|
+
|
|
7
|
+
## One-time setup
|
|
8
|
+
|
|
9
|
+
### 1. Create a PyPI account
|
|
10
|
+
1. Register at <https://pypi.org/account/register/> with an email address you control.
|
|
11
|
+
2. Turn on **two-factor authentication** in your account settings. PyPI requires it to publish.
|
|
12
|
+
|
|
13
|
+
### 2. Tell PyPI to trust this repository
|
|
14
|
+
Because the project does not exist on PyPI yet, you register a *pending publisher*:
|
|
15
|
+
|
|
16
|
+
1. On PyPI, open your account menu, then **Your projects**, then **Publishing**.
|
|
17
|
+
2. Under **Add a new pending publisher**, choose **GitHub** and fill in:
|
|
18
|
+
- PyPI project name: `open-finance-toolkit`
|
|
19
|
+
- Owner: `Itz-https`
|
|
20
|
+
- Repository name: `open-finance-toolkit`
|
|
21
|
+
- Workflow name: `publish.yml`
|
|
22
|
+
- Environment name: `pypi`
|
|
23
|
+
3. Save.
|
|
24
|
+
|
|
25
|
+
### 3. Create the matching environment on GitHub
|
|
26
|
+
1. In the repository, open **Settings**, then **Environments**, then **New environment**.
|
|
27
|
+
2. Name it exactly `pypi`.
|
|
28
|
+
3. Optional but recommended: tick **Required reviewers** and add yourself, so a release waits for your approval.
|
|
29
|
+
|
|
30
|
+
## Releasing a version
|
|
31
|
+
|
|
32
|
+
### 1. Prepare
|
|
33
|
+
1. Make sure the **CI** badge on the README is green on `main`.
|
|
34
|
+
2. Edit `src/open_finance_toolkit/__init__.py` and set `__version__` (for example `"0.1.0"`).
|
|
35
|
+
3. In `CHANGELOG.md`, move the items from **Unreleased** into a new version heading with today's date.
|
|
36
|
+
4. Commit these changes to `main` (through a pull request if you prefer).
|
|
37
|
+
|
|
38
|
+
### 2. Publish a GitHub release
|
|
39
|
+
1. Go to **Releases**, then **Draft a new release**.
|
|
40
|
+
2. Click **Choose a tag** and type `v0.1.0` (the version with a `v` in front). Choose **Create new tag**.
|
|
41
|
+
3. Set the title to `v0.1.0` and paste the changelog notes.
|
|
42
|
+
4. Click **Publish release**.
|
|
43
|
+
|
|
44
|
+
### 3. Watch it
|
|
45
|
+
Open the **Actions** tab. The *Publish to PyPI* workflow builds the package and uploads it. It stops with an error if the tag and `__version__` do not match, which protects you from mistakes.
|
|
46
|
+
|
|
47
|
+
### 4. Check
|
|
48
|
+
1. Open <https://pypi.org/project/open-finance-toolkit/>.
|
|
49
|
+
2. In a clean Python environment, run `pip install open-finance-toolkit` and then `open-finance-toolkit --version`.
|
|
50
|
+
3. Add a PyPI badge to the README:
|
|
51
|
+
```markdown
|
|
52
|
+
[](https://pypi.org/project/open-finance-toolkit/)
|
|
53
|
+
```
|
|
54
|
+
4. Update the README install note, since it will no longer need the "not on PyPI yet" warning.
|
|
55
|
+
|
|
56
|
+
## If something goes wrong
|
|
57
|
+
|
|
58
|
+
- **The workflow fails before uploading.** Nothing was published. Fix the problem, delete the release and tag, and publish again.
|
|
59
|
+
- **The name is taken or the publisher is rejected.** Re-check the five values in step 2 of one-time setup. They must match exactly, including the workflow file name.
|
|
60
|
+
- **A bad version went out.** On PyPI, open the release and use **Yank**. Users will stop getting it by default. Then publish a new version with a higher number, such as `0.1.1`.
|
|
61
|
+
|
|
62
|
+
## Version numbers
|
|
63
|
+
|
|
64
|
+
We use [Semantic Versioning](https://semver.org/): `MAJOR.MINOR.PATCH`. While the project is at `0.x`, minor versions may change behaviour. Bug fixes increase the last number.
|