Skip to main content

ISO-8583 toolbox

Project description

ISO-8583

Pure Python ISO-8583 message packing and unpacking. No dependencies.

No dependencies Python Lint Ruff Tests codecov License

Features

  • Pure Python, zero runtime dependencies
  • Pack and unpack ISO-8583 messages
  • Fixed and variable-length fields (LLVAR, LLLVAR)
  • Many field formats: ASCII, BCD, and raw binary
  • Nested subfields, including ASCII TLV and repeatable subfields
  • Partial unpacking that stops at the first error
  • Bring-your-own MTI and LengthType enums

Table of contents

Quick start

from iso_8583.fixed_formats import FieldFormat
from iso_8583.extendable_formats import MTI, LengthType
from iso_8583 import FieldSpec, Message
 
spec = {
    2: FieldSpec(LengthType.LLVAR, FieldFormat.N, 19),
    3: FieldSpec(LengthType.FIXED, FieldFormat.N, 6),
    4: FieldSpec(LengthType.FIXED, FieldFormat.N, 12),
    41: FieldSpec(LengthType.FIXED, FieldFormat.ANSP, 8),
}
 
msg = Message(spec, MTI.AUTHORISATION_REQUEST)
msg[2] = "4242424242424242"
msg[3] = "000000"
msg[4] = "000000001000"
msg[41] = "TERM0001"
 
raw = msg.pack()
msg2 = Message.unpack(spec, raw)
 
print(msg2[2])   # 4242424242424242
print(msg2[41])  # TERM0001

Field formats

Format Characters Wire
A Letters ASCII
B / ANSB Any bytes Raw
N Digits BCD
P Space ASCII
S Punctuation ASCII
Z Digits + D, F BCD
AN Letters + digits ASCII
ANP Letters + digits + space ASCII
ANS Letters + digits + punctuation ASCII
ANSP Letters + digits + punctuation + space ASCII

Length types

Type Prefix Max
FIXED 0 bytes
LLVAR 1 byte 99
LLLVAR 2 bytes 1000

Subfields

from iso_8583.fixed_formats import FieldFormat
from iso_8583.extendable_formats import MTI, LengthType
from iso_8583 import FieldSpec, SubFieldSpec, Message
 
spec = {
    119: FieldSpec(
        LengthType.LLLVAR, FieldFormat.B, 255,
        subfields={
            "0001": SubFieldSpec(LengthType.FIXED, FieldFormat.AN, 1),
            "0009": SubFieldSpec(LengthType.LLVAR, FieldFormat.ANSP, 8),
            "0011": SubFieldSpec(LengthType.LLVAR, FieldFormat.N, 19),
        },
    ),
}
 
msg = Message(spec, MTI.AUTHORISATION_REQUEST)
msg[119] = {"0001": "A", "0009": "HELLO", "0011": "1234567890"}
 
raw = msg.pack()
msg2 = Message.unpack(spec, raw)
print(msg2[119])
# {'0001': 'A', '0009': 'HELLO', '0011': '1234567890'}

For ASCII TLV subfields (tag 2 chars + length 2 chars + value), use TlvFieldSpec:

from iso_8583.fixed_formats import FieldFormat
from iso_8583.extendable_formats import MTI, LengthType
from iso_8583 import TlvFieldSpec, SubFieldSpec, Message
 
spec = {
    47: TlvFieldSpec(
        LengthType.LLVAR, FieldFormat.ANSP, 99,
        subfields={
            "T1": SubFieldSpec(LengthType.LLVAR, FieldFormat.ANSP, 10),
            "T2": SubFieldSpec(LengthType.LLVAR, FieldFormat.N, 8),
        },
    ),
}
 
msg = Message(spec, MTI.AUTHORISATION_REQUEST)
msg[47] = {"T1": "HELLO", "T2": "12345678"}
 
raw = msg.pack()
msg2 = Message.unpack(spec, raw)
print(msg2[47])
# {'T1': 'HELLO', 'T2': '12345678'}

Repeatable subfields accept a list:

from iso_8583.fixed_formats import FieldFormat
from iso_8583.extendable_formats import MTI, LengthType
from iso_8583 import FieldSpec, SubFieldSpec, Message
 
spec = {
    56: FieldSpec(
        LengthType.LLVAR, FieldFormat.B, 99,
        subfields={
            "0001": SubFieldSpec(LengthType.FIXED, FieldFormat.N, 4),
            "0023": SubFieldSpec(
                LengthType.FIXED, FieldFormat.ANSP, 8,
                repeatable=True,
            ),
        },
    ),
}
 
msg = Message(spec, MTI.AUTHORISATION_REQUEST)
msg[56] = {"0001": "1234", "0023": ["ENTRY-01", "ENTRY-02"]}
 
raw = msg.pack()
msg2 = Message.unpack(spec, raw)
print(msg2[56]["0023"])
# ['ENTRY-01', 'ENTRY-02']

Partial unpack

Stops at the first error and returns what was read:

from iso_8583.fixed_formats import FieldFormat
from iso_8583.extendable_formats import MTI, LengthType
from iso_8583 import FieldSpec, Message
 
full_spec = {
    2: FieldSpec(LengthType.LLVAR, FieldFormat.N, 19),
    3: FieldSpec(LengthType.FIXED, FieldFormat.N, 6),
}
partial_spec = {
    2: FieldSpec(LengthType.LLVAR, FieldFormat.N, 19),
}
 
msg = Message(full_spec, MTI.AUTHORISATION_REQUEST)
msg[2] = "4242424242424242"
msg[3] = "000000"
raw = msg.pack()
 
result, error = Message.unpack_partial(partial_spec, raw)
print(result[2])  # 4242424242424242
print(error)      # bit 3: present in bitmap but not in spec

Custom MTI

Pass mti_class to unpack to get the MTI back as your own enum:

from enum import Enum
from iso_8583.fixed_formats import FieldFormat
from iso_8583.extendable_formats import LengthType
from iso_8583 import FieldSpec, Message
 
class MyMTI(int, Enum):
    SALE = 0x0200
    SALE_RESPONSE = 0x0210
    REVERSAL = 0x0400
 
spec = {2: FieldSpec(LengthType.LLVAR, FieldFormat.N, 19)}
 
msg = Message(spec, MyMTI.SALE)
msg[2] = "4242424242424242"
 
raw = msg.pack()
msg2 = Message.unpack(spec, raw, mti_class=MyMTI)
print(msg2._mti)  # MyMTI.SALE

Custom LengthType

from enum import Enum
from iso_8583.fixed_formats import FieldFormat
from iso_8583 import FieldSpec, Message
 
class MyLengthType(Enum):
    FIXED = (0, None)
    LLVAR = (1, 99)
    LLLVAR = (1, 255)
    LL2VAR = (2, 999)
 
    def __init__(self, prefix_bytes, max_field_length):
        self.prefix_bytes = prefix_bytes
        self.max_field_length = max_field_length
 
class MyMTI(int, Enum):
    AUTH = 0x0100
 
spec = {
    2: FieldSpec(MyLengthType.LLVAR, FieldFormat.N, 19),
    60: FieldSpec(MyLengthType.LL2VAR, FieldFormat.ANSP, 999),
}
 
msg = Message(spec, MyMTI.AUTH)
msg[2] = "4242424242424242"
msg[60] = "HELLO WORLD"
 
raw = msg.pack()
msg2 = Message.unpack(spec, raw)
print(msg2[2])   # 4242424242424242
print(msg2[60])  # HELLO WORLD

License

See LICENSE.

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

iso_8583_toolbox-0.1.0.tar.gz (45.4 kB view details)

Uploaded Source

Built Distribution

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

iso_8583_toolbox-0.1.0-py3-none-any.whl (10.5 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: iso_8583_toolbox-0.1.0.tar.gz
  • Upload date:
  • Size: 45.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for iso_8583_toolbox-0.1.0.tar.gz
Algorithm Hash digest
SHA256 895a7fc14bcba0efdd61653dcb5bfae54d91ad391b816a34e61ca7f3fea02cba
MD5 2cbe4efca32fa74ce17db90cd235c099
BLAKE2b-256 1f7f97ed00420bfea4cbfcddfa49e19976fb0d29a738ca3f1848ea79eea6d596

See more details on using hashes here.

Provenance

The following attestation bundles were made for iso_8583_toolbox-0.1.0.tar.gz:

Publisher: publish.yml on Bastien-BO/iso-8583

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

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

File metadata

File hashes

Hashes for iso_8583_toolbox-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a79500db66036da6aad8b2db406d4cf4922205242ac10abb18ca0e742219b37d
MD5 7d34243b6863c7681447e4454581dc35
BLAKE2b-256 0ec9861f1679ec30cbd13262773f0d59cb1a720f73edada4a7b8771c86db8d65

See more details on using hashes here.

Provenance

The following attestation bundles were made for iso_8583_toolbox-0.1.0-py3-none-any.whl:

Publisher: publish.yml on Bastien-BO/iso-8583

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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