Skip to main content

A lightweight Python package to flatten complex ISO 20022 XML messages into usable data.

Project description

OpenPurse

OpenPurse is a lightweight, open-source Python package that parses and flattens deeply nested ISO 20022 XML financial messages into highly usable, flat Python dictionaries (which can be easily dumped to JSON).

Features

  • Universal Support: Dynamically determines the message format. It fully supports both XML-based ISO 20022 schemas and legacy block-based SWIFT MT formats (like MT103 and MT202).
  • Structured Schema: Extracts all major variables into a standard Python PaymentMessage @dataclass (with robust flatten() dictionary dumps available as well).
  • Robust and Fast Parsing: Built on top of lxml with robust error handling, regular expressions for non-XML data, and graceful degradation for missing optional fields.
  • Zero Bloat: Only requires lxml. No heavy dependencies like pandas or pydantic are needed.

Installation

You can install openpurse locally:

git clone https://github.com/yourusername/openpurse.git
cd openpurse
pip install .

To install development dependencies (for running tests):

pip install -e .[dev]

Usage

You can extract standard standard fields strictly into a structured dataclass or loosely into a dictionary:

from openpurse.parser import OpenPurseParser

# Your raw ISO 20022 XML data (or MT bytes)
xml_data = b'''<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.008.001.08">
    <FIToFICstmrCdtTrf>
        <GrpHdr>
            <MsgId>MSG12345</MsgId>
            ...
        </GrpHdr>
        <CdtTrfTxInf>
            <IntrBkSttlmAmt Ccy="USD">1000.50</IntrBkSttlmAmt>
        </CdtTrfTxInf>
    </FIToFICstmrCdtTrf>
</Document>'''

# Initialize the parser
parser = OpenPurseParser(xml_data)

# 1. Parse into a structured PaymentMessage dataclass (Recommended)
msg_struct = parser.parse()
print(f"ID is {msg_struct.message_id} sending {msg_struct.amount} {msg_struct.currency}")

# 2. Flatten directly into a dictionary
flat_dict = parser.flatten()
print(flat_dict)
# Output:
# {
#     "message_id": "MSG12345",
#     "end_to_end_id": None,
#     "amount": "1000.50",
#     "currency": "USD",
#     "sender_bic": None,
#     "receiver_bic": None,
#     "debtor_name": None,
#     "creditor_name": None
# }

# Or parse legacy SWIFT MT formats without changing any logic!
mt_data = b'''{1:F01BANKUS33AXXX0000000000}{2:I103BANKGB22XXXXN}{4:
:20:MT103MSG
:32A:231024EUR50000,00
-}'''

# Output: {"message_id": "MT103MSG", "amount": "50000.00", "currency": "EUR"... }

# 3. Translate between MT and MX formats
from openpurse.translator import Translator

msg_struct = parser.parse()

# Convert to MT103 byte string
mt_bytes = Translator.to_mt(msg_struct, "103")

# Convert to ISO 20022 XML (e.g. pacs.008, camt.004)
mx_bytes = Translator.to_mx(msg_struct, "camt.004")

Supported Fields

Whether you call .parse() (which yields a PaymentMessage dataclass instance) or .flatten() (which yields a dict), the parser standardizes the following fields across all schemas:

  • message_id: GrpHdr/MsgId (XML) or Block 4 :20: (MT)
  • end_to_end_id: EndToEndId (XML)
  • amount: Extracted value preserving decimal notation
  • currency: 3-Letter currency code
  • sender_bic: InstgAgt/BICFI (XML) or Header Block 1 (MT)
  • receiver_bic: InstdAgt/BICFI (XML) or Header Block 2 (MT)
  • debtor_name: Dbtr/Nm (XML) or :50K: tags (MT)
  • creditor_name: Cdtr/Nm (XML) or :59: tags (MT)

Missing or optional fields gracefully return None.

Tests

Testing is done using pytest. Currently, coverage includes mock definitions for basic pacs and camt schemas, validating graceful degradation when schemas don't provide creditor/debtor names.

pytest tests/

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

openpurse-0.1.0.tar.gz (3.5 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

openpurse-0.1.0-py3-none-any.whl (8.3 kB view details)

Uploaded Python 3

File details

Details for the file openpurse-0.1.0.tar.gz.

File metadata

  • Download URL: openpurse-0.1.0.tar.gz
  • Upload date:
  • Size: 3.5 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.6

File hashes

Hashes for openpurse-0.1.0.tar.gz
Algorithm Hash digest
SHA256 14a802116ad53055652c4db9e50b59c4d77a53273c384ace11b4afe337376a8b
MD5 e7230c6d5f300006e786d237855c0bfe
BLAKE2b-256 400077aff3f41236fafc49fb07216409ef8b8d2779aa5c71d619392964a44b6f

See more details on using hashes here.

File details

Details for the file openpurse-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: openpurse-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 8.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.6

File hashes

Hashes for openpurse-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8d9e663e573fd4181550feaf94805f3d7857ef0da607a20b226b65710a2767b2
MD5 d64c6e3f67fb314c6277b9f3be34671b
BLAKE2b-256 144bea4d74ebc75f4f26ff93b5911ef71f97a22d37c4906edc020575cee2dc41

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page