saransh-workflows
Python parsers for Indian financial statement PDFs — CAMS Consolidated Account Statement, CDSL CAS, and NSDL e-CAS. Each parser extracts text from the PDF using pypdf and returns a fully structured JSON object.
Installation
From PyPI (once published)
pip install saransh-workflows
From source (development)
git clone https://github.com/sagarchandagarwal/saransh-workflows.git
cd saransh-workflows
pip install -e .
CLI Usage
After installation three commands are available on your PATH:
# CAMS parser
parse-cams path/to/cams_statement.pdf
parse-cams path/to/cams_statement.pdf --pretty -o output.json
parse-cams path/to/cams_statement.pdf --password your_pdf_password --pretty
# CDSL parser
parse-cdsl path/to/cdsl_cas.pdf
parse-cdsl path/to/cdsl_cas.pdf --pretty -o output.json
parse-cdsl path/to/cdsl_cas.pdf --password your_pdf_password --pretty
# NSDL parser
parse-nsdl path/to/nsdl_ecas.pdf
parse-nsdl path/to/nsdl_ecas.pdf --pretty -o output.json
parse-nsdl path/to/nsdl_ecas.pdf --password your_pdf_password --pretty
All three commands accept the same flags:
| Flag | Description |
|---|---|
input_pdf |
Path to the source PDF (required) |
-o / --output |
Output JSON path (default: same name as PDF with .json suffix) |
--pretty |
Pretty-print JSON with 2-space indentation |
--password |
Password for encrypted/password-protected PDF files |
Python API
from pathlib import Path
from saransh_workflows import parse_cams_pdf, parse_cdsl_pdf, parse_nsdl_pdf
cams_data = parse_cams_pdf(Path("cams_statement.pdf"))
cdsl_data = parse_cdsl_pdf(Path("cdsl_cas.pdf"))
nsdl_data = parse_nsdl_pdf(Path("nsdl_ecas.pdf"))
# Encrypted PDFs
nsdl_encrypted = parse_nsdl_pdf(Path("nsdl_ecas.pdf"), password="your_pdf_password")
All three functions return a plain dict that can be serialised with json.dumps.
Output JSON Schemas
CAMS
{
"source_file": str,
"statement_period": {"from": str, "to": str} | null,
"investor": {
"email": str | null,
"name": str | null,
"address": [str],
"phone_res": str | null,
"mobile": str | null
},
"portfolio_summary": [
{"fund_house": str, "cost_value_inr": float, "market_value_inr": float}
],
"folios": [
{
"fund_house": str,
"folio_no": str | null,
"pan": str | null,
"kyc": str | null,
"holder_name": str | null,
"scheme_code": str | null,
"scheme_name": str | null,
"isin": str | null,
"registrar": str | null,
"nominees": [str],
"opening_unit_balance": float | null,
"transactions": [
{
"date": str,
"transaction": str,
"amount_inr": float | null,
"units": float | null,
"price_inr": float | null,
"unit_balance": float | null,
"charges": [{"date": str, "amount_inr": float}]
}
],
"closing_unit_balance": float | null,
"nav": {"date": str, "value_inr": float} | null,
"total_cost_value_inr": float | null,
"market_value": {"date": str, "value_inr": float} | null,
"notes": [str]
}
],
"warnings": [str]
}
CDSL
{
"source_file": str,
"cas_id": str | null,
"statement_period": {"from": str, "to": str} | null,
"investor": {"name": str, "pan": str, "address": [str]},
"summary": {
"accounts": [...],
"total_portfolio_value_inr": float | null,
"grand_total_inr": float | null,
"monthly_portfolio_valuation": [...],
"asset_allocation": [...]
},
"cdsl_accounts": [
{
"bo_id": str,
"dp_name": str,
"transactions": [...],
"holdings": [...],
"holding_sections": [...],
"no_transaction": bool,
"nil_holding": bool,
"portfolio_values": [float]
}
],
"nsdl_accounts": [...],
"mutual_fund_folios": [
{
"amc_name": str,
"scheme_name": str,
"scheme_code": str,
"folio_no": str | null,
"isin": str | null,
"opening_balance": float | null,
"closing_balance": float | null,
"transactions": [...]
}
]
}
NSDL
{
"source_file": str,
"nsdl_id": str | null,
"statement_period": {"from": str, "to": str} | null,
"investor": {
"name": str | null,
"pan": str | null,
"address": [str],
"portfolio_value_inr": float | null
},
"summary": {
"accounts": [...],
"total_inr": float | null,
"grand_total_inr": float | null,
"portfolio_trend": [
{
"month": str,
"portfolio_value_inr": float | null,
"change_inr": float | null,
"change_percent": float | null,
"remark": str | null
}
],
"asset_composition": [
{"asset_class": str, "value_inr": float, "percent": float}
]
},
"holdings": {
"account": {...},
"securities": [
{
"isin": str,
"security": str,
"current_balance": float,
"free_balance": float,
"value_inr": float,
...
}
]
},
"transactions": {
"account": {...},
"isin_sections": [
{
"isin": str,
"security": str,
"opening_balance": float | null,
"closing_balance": float | null,
"transactions": [...]
}
]
}
}
Project Structure
saransh-workflows/
├── saransh_workflows/ # Installable Python package
│ ├── __init__.py # Public API re-exports
│ ├── cams.py # CAMS parser
│ ├── cdsl.py # CDSL parser
│ └── nsdl.py # NSDL parser
├── cams-parser/
│ ├── parse_cams_pdf.py # Standalone script (standalone usage)
│ └── requirements.txt
├── cdsl-parser/
│ ├── parse_cdsl_pdf.py # Standalone script
│ └── requirements.txt
├── nsdl-parser/
│ ├── parse_nsdl_pdf.py # Standalone script
│ └── requirements.txt
├── pyproject.toml # Package metadata & build config
├── README.md
└── AGENTS.md # Development log & change history
Publishing to PyPI
pip install build twine
python -m build
twine upload dist/*
Requirements
- Python ≥ 3.11
- pypdf ≥ 6.0.0
- cryptography ≥ 3.1 (required for AES-encrypted PDFs)
License
MIT
Metadata
Release files for saransh-workflows 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| saransh_workflows-0.1.0.tar.gz | 25.6 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| saransh_workflows-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 43.5 kB
Release files / saransh_workflows-0.1.0.tar.gz
| Download URL | saransh_workflows-0.1.0.tar.gz |
|---|---|
| Size | 25.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
72dcfedc3f991f0934658f8485690502f9982245fee65f9bcf5e093a5b4a1790
|
|
BLAKE2b-256 checksum How to use checksums |
5af4fb86a0baefbc8e87eff11d5e3973740a6a32add5435ec226fb9bc454e6eb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.15
|
Release files / saransh_workflows-0.1.0-py3-none-any.whl
| Download URL | saransh_workflows-0.1.0-py3-none-any.whl |
|---|---|
| Size | 18.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
840633e9cf29157ce56be4f1aa6029353699bbf974db2c00467a4907e0d227d8
|
|
BLAKE2b-256 checksum How to use checksums |
5294c4aa878e7ea875165c9a1e06a30a5248ad2292bf68f7774915a4b501289a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.15
|
Security for saransh-workflows 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.