Skip to main content

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

Project description

OpenPurse Logo

OpenPurse

The Ultra-Lightweight, Production-Grade Engine for ISO 20022 and SWIFT MT Financial Messaging.

PyPI version License Python Versions Ruff


⚡️ The OpenPurse Mission

Financial messaging is transitioning from archaic, line-based SWIFT MT to deeply nested, namespace-heavy ISO 20022 (MX) XML. Engineers are often caught in the middle, forced to deal with massive XML schemas, fragmented versions, and complex reconciliation logic.

OpenPurse solves this by providing a unified, zero-bloat API that flattens this complexity into clean, structured Python objects.

  • 🚀 Performance-First: Built with C-optimized lxml for lightning-fast parsing even under heavy load.
  • 🛡️ Production-Hardened: Strict validation for IBANs (Modulo-97) and BICs (ISO 9362).
  • 🔌 Schema-Dynamic: Not just one version. OpenPurse dynamically detects and supports 770+ ISO namespaces across Cash Management, Payments Initiation, and Securities.
  • 📦 Zero-Dependency Core: No pandas, no pydantic. Just pure, native Python @dataclasses.

🏗️ Technical Philosophy: The @dataclass Way

Most financial libraries overwhelm you with nested dictionaries or heavy ORM-like objects. OpenPurse uses the Uniform Data Model (UDM) philosophy:

  1. Flattening: We extract only the most critical fields needed for reconciliation and payment processing.
  2. Immutability: Once parsed, messages are stored in lightweight, typed @dataclasses.
  3. Lossless-Ready: While we flatten for convenience, we preserve raw data integrity (e.g., keeping amounts as str to avoid floating-point errors).

🛠️ Feature Deep Dive

1. The Unified Parser

One caller to rule them all. Whether your file starts with <?xml or {1:, the OpenPurseParser handles the routing.

import openpurse

# Parses MT103, MT202, pacs.008, camt.053, pain.001, etc.
raw_data = get_incoming_payload()
parser = openpurse.OpenPurseParser(raw_data)
msg = parser.parse()

print(f"Ref: {msg.message_id} | Amt: {msg.amount} {msg.currency}")

The Uniform Data Model (UDM)

Every parsed message returns a PaymentMessage object (or an extended subclass like Pacs008Message) with these standardized attributes:

Attribute Description
message_id Unique ID from Group Header (:20: in MT)
end_to_end_id Original e2e reference (EndToEndId)
amount Transaction value (stored as string for precision)
currency ISO 3-letter currency code (e.g. USD, EUR)
sender_bic / receiver_bic Validated 8/11 char BIC codes
debtor_name / creditor_name Party names
debtor_account / creditor_account IBAN or local account identifiers
uetr SWIFT gpi Unique Transaction Reference

2. Bidirectional Translator

Move between MX (ISO 20022) and MT legacy formats without losing precision.

from openpurse.translator import Translator

# Convert a parsed message object to a legacy MT103 block
mt_payload = Translator.to_mt(msg, mt_type="103")

3. Smart PII Anonymizer

Essential for testing in staging environments with real data. OpenPurse scrubs names and addresses while keeping IBAN checksums valid, so your downstream systems don't reject the files.

from openpurse.anonymizer import Anonymizer

anonymized_xml = Anonymizer().anonymize_xml(raw_xml_bytes)

4. Lifecycle Reconciler

The "Holy Grail" of treasury engineering: linking fragmented messages into a single payment lifecycle (e.g., linking a pain.001 to its pain.002 status report and final camt.054 notification).

from openpurse.reconciler import Reconciler

# Trace the entire life of a payment across your message history
timeline = Reconciler.trace_lifecycle(seed_msg, message_pool)

📊 Capability Matrix

Format Category Supported Message Types
ISO 20022 (MX) Payments pacs.008, pacs.009, pacs.004
Cash Mgmt camt.052, camt.053, camt.054, camt.004
Initiation pain.001, pain.002, pain.008
SWIFT MT Customer MT101, MT103
Financial MT202
Reporting MT900, MT910, MT940, MT942, MT950

🚦 Dual-Tier Validation Engine

OpenPurse doesn't just extract data; it actively defends your downstream systems against corrupted financial payloads using a two-tier validation engine.

Tier 1: Deep Structural Validation

Instantly checks the raw payload syntax before you even attempt to parse it.

  • XML (MX): Automatically evaluates the raw bytes against the precise matching lxml compiled XSD definition from the 770+ ISO schemas in the library.
  • SWIFT MT: Enforces rigorous Regex structural checks ensuring Block 1-5 definitions, proper :tag: spacing, and correct termination syntax are met.
from openpurse.validator import Validator

raw_payload = b"{1:F01BANKUS33XXX0000000000}{2:I103BANKGB22XXXN}{4:\n:20:REF123\n-}"
report = Validator.validate_schema(raw_payload)
if not report.is_valid:
    print(report.errors) # Caught malformed block 4 before parsing

Tier 2: Logical Field Validation

Validates the actual extracted business values of a parsed PaymentMessage.

  • IBAN: Full Modulo-97 checksum execution across all supported country formats.
  • BIC: Strict ISO 9362 8- or 11-character alphanumeric check for Senders/Receivers.
  • UETR: Strict UUIDv4 checking for SWIFT gpi tracking strings.
parsed_msg = parser.parse()
logic_report = Validator.validate(parsed_msg)
if not logic_report.is_valid:
    print(f"Critical Business Error: {logic_report.errors}")

🔍 Exporter: Automated API Specs

Instantly sync your internal financial models with your REST API documentation. Exporter generates OpenAPI 3.0 / JSON Schema definitions directly from the codebase.

# Generate openapi.json for your web team
python3 scripts/export_schema.py --output docs/api_spec.json

⚖️ Performance Benchmarks (Qualitative)

OpenPurse is optimized for high-throughput reconciliation pipelines. By leveraging lxml's C-bindings for XML traversal and specialized RegEx engines for MT parsing, OpenPurse can process:

  • Small Messages: ~0.001s / message.
  • Large Statements (CAMT.053/MT940): Typically < 0.05s for statement blocks with 5,000+ entries.

🤝 Contributing

OpenPurse is a community project for financial engineers. We welcome PRs for:

  • New ISO version mappings.
  • New MT block pattern regex improvements.
  • Performance optimizations.
# Setup for development
pip install -e ".[dev]"
pytest tests/

📜 License

OpenPurse is released under the MIT License. Build something great.

Built with ❤️ for modern financial engineering by the OpenPurse team.

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.11.tar.gz (3.6 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.11-py3-none-any.whl (30.2 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: openpurse-0.1.11.tar.gz
  • Upload date:
  • Size: 3.6 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.11.tar.gz
Algorithm Hash digest
SHA256 3e4e2a3865936030620c52a5c11f5d9bcd7c4f3157b3fc1f3c4e2162578138e9
MD5 01184287e54eb13d9d40fe5c1f7bffd4
BLAKE2b-256 187f80aa363ea1b40447bcdbe7a2d23e0187e99a37d361d32808a53c7eec7491

See more details on using hashes here.

File details

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

File metadata

  • Download URL: openpurse-0.1.11-py3-none-any.whl
  • Upload date:
  • Size: 30.2 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.11-py3-none-any.whl
Algorithm Hash digest
SHA256 1a401c344a950e938970bfc81784cc20eeb166c69cf410333c2a84b7358d4037
MD5 a318ebb6b4dbf17dca34ad76d2f6c2e2
BLAKE2b-256 5047ba1dcffdc99401f8dc61f208178b5c434cbd2c60a51d16143bc569875bca

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