### Install pyiso8583 Source: https://pyiso8583.readthedocs.io/en/latest/_sources/index.rst.txt Command to install the package via pip. ```bash pip install pyiso8583 ``` -------------------------------- ### Define ASCII field configurations Source: https://pyiso8583.readthedocs.io/en/latest/specifications.html Configuration dictionary entries for ISO 8583 fields using ASCII encoding. ```json "124": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 3, "max_len": 999, "desc": "Reserved for Private Use"}, "125": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 3, "max_len": 999, "desc": "Reserved for Private Use"}, "126": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 3, "max_len": 999, "desc": "Reserved for Private Use"}, "127": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 3, "max_len": 999, "desc": "Reserved for Private Use"}, "128": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 16, "desc": "MAC"} } ``` -------------------------------- ### Auto-generate secondary bitmap Source: https://pyiso8583.readthedocs.io/en/latest/howto.html Demonstrates automatic secondary bitmap generation when a field in the 65-128 range is included. ```python >>> import pprint >>> import iso8583 >>> from iso8583.specs import default_ascii as spec >>> decoded = { ... 't': '0200', ... '102': '111111'} >>> encoded_raw, encoded = iso8583.encode(decoded, spec) >>> encoded_raw bytearray(b'02008000000000000000000000000400000006111111') >>> pprint.pp(encoded) {'t': {'len': b'', 'data': b'0200'}, 'p': {'len': b'', 'data': b'8000000000000000'}, '1': {'len': b'', 'data': b'0000000004000000'}, '102': {'len': b'06', 'data': b'111111'}} >>> pprint.pp(decoded) {'t': '0200', '102': '111111', 'p': '8000000000000000', '1': '0000000004000000'} ``` -------------------------------- ### iso8583.pp(doc, spec, desc_width=30, stream=None, line_width=80) Source: https://pyiso8583.readthedocs.io/en/latest/_modules/iso8583/tools.html Pretty prints a Python dictionary containing ISO8583 data to a specified output stream. ```APIDOC ## iso8583.pp ### Description Pretty prints a Python dictionary containing ISO8583 data. It is recommended to call this after decoding or encoding data to ensure the most accurate information is displayed. ### Parameters - **doc** (dict) - Required - The dictionary containing the ISO8583 data. - **spec** (dict) - Required - A Python dictionary defining the ISO8583 specification. - **desc_width** (int) - Optional - Field description width (default 30). Specify 0 to print no descriptions. - **stream** (TextIO) - Optional - An output stream. If not specified, defaults to sys.stdout. - **line_width** (int) - Optional - The attempted maximum width of the output line (default 80). ``` -------------------------------- ### Add and Remove Fields in ISO8583 Messages Source: https://pyiso8583.readthedocs.io/en/latest/_sources/howto.rst.txt Shows how to add fields by key and remove them using standard dictionary methods before re-encoding. ```python >>> decoded['2'] = 'cardholder PAN' >>> decoded['3'] = '111111' >>> decoded['21'] = '021' >>> >>> encoded_raw, encoded = iso8583.encode(decoded, spec) >>> encoded_raw bytearray(b'0200600008000000000014cardholder PAN111111021') >>> pprint.pp(encoded) {'t': {'len': b'', 'data': b'0200'}, 'p': {'len': b'', 'data': b'6000080000000000'}, '2': {'len': b'14', 'data': b'cardholder PAN'}, '3': {'len': b'', 'data': b'111111'}, '21': {'len': b'', 'data': b'021'}} >>> pprint.pp(decoded) {'t': '0200', 'p': '6000080000000000', '2': 'cardholder PAN', '3': '111111', '21': '021'} ``` ```python >>> decoded.pop('2', None) 'cardholder PAN' >>> decoded.pop('3', None) '111111' >>> >>> encoded_raw, encoded = iso8583.encode(decoded, spec) >>> encoded_raw bytearray(b'02000000080000000000021') >>> pprint.pp(encoded) {'t': {'len': b'', 'data': b'0200'}, 'p': {'len': b'', 'data': b'0000080000000000'}, '21': {'len': b'', 'data': b'021'}} >>> pprint.pp(decoded) {'t': '0200', 'p': '0000080000000000', '21': '021'} ``` -------------------------------- ### Default ASCII Field Definitions Source: https://pyiso8583.readthedocs.io/en/latest/specifications.html A comprehensive dictionary mapping ISO 8583 fields to their ASCII encoding specifications. ```json default_ascii = { "h": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 0, "desc": "Message Header"}, "t": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 4, "desc": "Message Type"}, "p": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 16, "desc": "Bitmap, Primary"}, "1": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 16, "desc": "Bitmap, Secondary"}, "2": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 2, "max_len": 19, "desc": "Primary Account Number (PAN)"}, "3": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 6, "desc": "Processing Code"}, "4": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 12, "desc": "Amount, Transaction"}, "5": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 12, "desc": "Amount, Settlement"}, "6": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 12, "desc": "Amount, Cardholder Billing"}, "7": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 10, "desc": "Transmission Date and Time"}, "8": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 8, "desc": "Amount, Cardholder Billing Fee"}, "9": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 8, "desc": "Conversion Rate, Settlement"}, "10": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 8, "desc": "Conversion Rate, Cardholder Billing"}, "11": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 6, "desc": "System Trace Audit Number"}, "12": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 6, "desc": "Time, Local Transaction"}, "13": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 4, "desc": "Date, Local Transaction"}, "14": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 4, "desc": "Date, Expiration"}, "15": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 4, "desc": "Date, Settlement"}, "16": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 4, "desc": "Date, Conversion"}, "17": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 4, "desc": "Date, Capture"}, "18": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 4, "desc": "Merchant Type"}, "19": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 3, "desc": "Acquiring Institution Country Code"}, "20": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 3, "desc": "PAN Country Code"}, "21": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 3, "desc": "Forwarding Institution Country Code"}, "22": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 3, "desc": "Point-of-Service Entry Mode"}, "23": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 3, "desc": "PAN Sequence Number"}, "24": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 3, "desc": "Network International ID (NII)"}, "25": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 2, "desc": "Point-of-Service Condition Code"}, "26": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 2, "desc": "Point-of-Service Capture Code"}, "27": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 1, "desc": "Authorizing ID Response Length"}, "28": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 9, "desc": "Amount, Transaction Fee"}, "29": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 9, "desc": "Amount, Settlement Fee"}, "30": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 9, "desc": "Amount, Transaction Processing Fee"}, "31": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 9, "desc": "Amount, Settlement Processing Fee"}, "32": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 2, "max_len": 11, "desc": "Acquiring Institution ID Code"}, "33": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 2, "max_len": 11, "desc": "Forwarding Institution ID Code"}, "34": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 2, "max_len": 28, "desc": "Primary Account Number, Extended"}, "35": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 2, "max_len": 37, "desc": "Track 2 Data"}, "36": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 3, "max_len": 104, "desc": "Track 3 Data"} } ``` -------------------------------- ### Encode a Basic ISO8583 Message Source: https://pyiso8583.readthedocs.io/en/latest/_sources/howto.rst.txt Demonstrates the minimum requirement of a message type key 't' to encode a dictionary into a bytearray. ```python >>> import pprint >>> import iso8583 >>> from iso8583.specs import default_ascii as spec >>> decoded = {'t': '0200'} >>> encoded_raw, encoded = iso8583.encode(decoded, spec) >>> encoded_raw bytearray(b'02000000000000000000') >>> pprint.pp(encoded) {'t': {'len': b'', 'data': b'0200'}, 'p': {'len': b'', 'data': b'0000000000000000'}} >>> pprint.pp(decoded) {'t': '0200', 'p': '0000000000000000'} ``` -------------------------------- ### Add fields to an ISO8583 message Source: https://pyiso8583.readthedocs.io/en/latest/howto.html Shows how to include additional data fields in the message dictionary before re-encoding. ```python >>> decoded['2'] = 'cardholder PAN' >>> decoded['3'] = '111111' >>> decoded['21'] = '021' >>> >>> encoded_raw, encoded = iso8583.encode(decoded, spec) >>> encoded_raw bytearray(b'0200600008000000000014cardholder PAN111111021') >>> pprint.pp(encoded) {'t': {'len': b'', 'data': b'0200'}, 'p': {'len': b'', 'data': b'6000080000000000'}, '2': {'len': b'14', 'data': b'cardholder PAN'}, '3': {'len': b'', 'data': b'111111'}, '21': {'len': b'', 'data': b'021'}} >>> pprint.pp(decoded) {'t': '0200', 'p': '6000080000000000', '2': 'cardholder PAN', '3': '111111', '21': '021'} ``` -------------------------------- ### Send Binary Data Source: https://pyiso8583.readthedocs.io/en/latest/_sources/howto.rst.txt Configure field specifications dynamically to handle binary data, such as EMV fields, by setting encoding types. ```python >>> import iso8583 >>> from iso8583.specs import default_ascii as spec >>> decoded = { ... 't': '0200', ... '55': '9F02060000000123455F340102'} ``` ```python >>> spec['55']['data_enc'] = 'b' >>> spec['55']['len_enc'] = 'ascii' >>> spec['55']['len_type'] = 3 >>> spec['55']['max_len'] = 999 ``` ```python >>> encoded_raw, encoded = iso8583.encode(decoded, spec) >>> encoded_raw bytearray(b'02000000000000000200013\x9f\x02\x06\x00\x00\x00\x01#E_4\x01\x02') ``` -------------------------------- ### Send Binary Coded Decimal (BCD) Data Source: https://pyiso8583.readthedocs.io/en/latest/_sources/howto.rst.txt Handle BCD fields by configuring nibble-based length counting and padding for odd-length data. ```python >>> import iso8583 >>> from iso8583.specs import default_ascii as spec >>> decoded = { ... 't': '0200', ... '2': '121200000002121'} ``` ```python >>> spec['2']['data_enc'] = 'b' >>> spec['2']['len_enc'] = 'b' >>> spec['2']['len_type'] = 1 >>> spec['2']['max_len'] = 19 >>> spec['2']['len_count'] = 'nibbles' >>> spec['2']['right_pad'] = '0' ``` ```python >>> encoded_raw, encoded = iso8583.encode(decoded, spec) >>> encoded_raw bytearray(b'02004000000000000000\x15\x12\x12\x00\x00\x00\x02\x12\x10') ``` -------------------------------- ### Pad BCD or Hex Fields Source: https://pyiso8583.readthedocs.io/en/latest/_modules/iso8583/encoder.html Pads a field from the left or right based on the provided field specification. ```python def _add_pad_field( field_data: str, field_spec: _FieldSpecDict, ) -> str: r"""Pad a BCD or hex field from the left or right. Parameters ---------- doc_dec : dict Dict containing decoded ISO8583 data field_data : str Field data to encode field_key : str Field ID to pad field_spec : dict A Python dict defining ISO8583 specification for this field. See :mod:`iso8583.specs` module for examples. Returns ------- str Padded field data """ pad: str = field_spec.get("left_pad", "")[:1] if len(pad) > 0: return pad + field_data pad = field_spec.get("right_pad", "")[:1] if len(pad) > 0: return field_data + pad return field_data ``` -------------------------------- ### Define ISO 8583 Message Specification Dictionary Source: https://pyiso8583.readthedocs.io/en/latest/specifications.html A sample dictionary configuration for ISO 8583 message fields, specifying encoding and length constraints for various data elements. ```python default = { "h": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 0, "desc": "Message Header"}, "t": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 4, "desc": "Message Type"}, "p": {"data_enc": "b", "len_enc": "ascii", "len_type": 0, "max_len": 8, "desc": "Bitmap, Primary"}, "1": {"data_enc": "b", "len_enc": "ascii", "len_type": 0, "max_len": 8, "desc": "Bitmap, Secondary"}, "2": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 2, "max_len": 19, "desc": "Primary Account Number (PAN)"}, "3": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 6, "desc": "Processing Code"}, "4": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 12, "desc": "Amount, Transaction"}, "5": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 12, "desc": "Amount, Settlement"}, "6": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 12, "desc": "Amount, Cardholder Billing"}, "7": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 10, "desc": "Transmission Date and Time"}, "8": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 8, "desc": "Amount, Cardholder Billing Fee"}, "9": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 8, "desc": "Conversion Rate, Settlement"}, "10": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 8, "desc": "Conversion Rate, Cardholder Billing"}, "11": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 6, "desc": "System Trace Audit Number"}, "12": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 6, "desc": "Time, Local Transaction"}, "13": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 4, "desc": "Date, Local Transaction"}, "14": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 4, "desc": "Date, Expiration"}, "15": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 4, "desc": "Date, Settlement"}, "16": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 4, "desc": "Date, Conversion"}, "17": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 4, "desc": "Date, Capture"}, "18": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 4, "desc": "Merchant Type"}, "19": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 3, "desc": "Acquiring Institution Country Code"}, "20": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 3, "desc": "PAN Country Code"}, "21": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 3, "desc": "Forwarding Institution Country Code"}, "22": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 3, "desc": "Point-of-Service Entry Mode"}, "23": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 3, "desc": "PAN Sequence Number"}, "24": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 3, "desc": "Network International ID (NII)"}, "25": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 2, "desc": "Point-of-Service Condition Code"}, "26": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 2, "desc": "Point-of-Service Capture Code"}, "27": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 1, "desc": "Authorizing ID Response Length"}, "28": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 9, "desc": "Amount, Transaction Fee"}, "29": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 9, "desc": "Amount, Settlement Fee"}, "30": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 9, "desc": "Amount, Transaction Processing Fee"}, "31": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 9, "desc": "Amount, Settlement Processing Fee"}, "32": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 2, "max_len": 11, "desc": "Acquiring Institution ID Code"}, "33": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 2, "max_len": 11, "desc": "Forwarding Institution ID Code"}, "34": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 2, "max_len": 28, "desc": "Primary Account Number, Extended"}, "35": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 2, "max_len": 37, "desc": "Track 2 Data"}, "36": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 3, "max_len": 104, "desc": "Track 3 Data"}, "37": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 12, "desc": "Retrieval Reference Number"}, "38": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 6, "desc": "Authorization ID Response"}, "39": {"data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 2, "desc": "Response Code"} ``` -------------------------------- ### Manage Secondary Bitmaps Source: https://pyiso8583.readthedocs.io/en/latest/_sources/howto.rst.txt Explains that secondary bitmaps are auto-generated when fields 65-128 are present and that manual bitmap values are overwritten. ```python >>> import pprint >>> import iso8583 >>> from iso8583.specs import default_ascii as spec >>> decoded = { ... 't': '0200', ... '102': '111111'} >>> encoded_raw, encoded = iso8583.encode(decoded, spec) >>> encoded_raw bytearray(b'02008000000000000000000000000400000006111111') >>> pprint.pp(encoded) {'t': {'len': b'', 'data': b'0200'}, 'p': {'len': b'', 'data': b'8000000000000000'}, '1': {'len': b'', 'data': b'0000000004000000'}, '102': {'len': b'06', 'data': b'111111'}} >>> pprint.pp(decoded) {'t': '0200', '102': '111111', 'p': '8000000000000000', '1': '0000000004000000'} ``` ```python >>> decoded = { ... 't': '0200', ... 'p': 'spam', ... '1': 'eggs', ... '102': '111111'} >>> encoded_raw, encoded = iso8583.encode(decoded, spec) >>> encoded_raw bytearray(b'02008000000000000000000000000400000006111111') >>> pprint.pp(encoded) {'t': {'len': b'', 'data': b'0200'}, 'p': {'len': b'', 'data': b'8000000000000000'}, '1': {'len': b'', 'data': b'0000000004000000'}, '102': {'len': b'06', 'data': b'111111'}} >>> pprint.pp(decoded) {'t': '0200', 'p': '8000000000000000', '102': '111111', '1': '0000000004000000'} ``` ```python >>> decoded = { ... 't': '0200', ... 'p': 'spam', ... '1': 'eggs', ... '21': '051'} >>> encoded_raw, encoded = iso8583.encode(decoded, spec) >>> encoded_raw bytearray(b'02000000080000000000051') >>> pprint.pp(encoded) {'t': {'len': b'', 'data': b'0200'}, 'p': {'len': b'', 'data': b'0000080000000000'}, '21': {'len': b'', 'data': b'051'}} >>> pprint.pp(decoded) {'t': '0200', 'p': '0000080000000000', '21': '051'} ``` -------------------------------- ### Pretty print ISO8583 messages Source: https://pyiso8583.readthedocs.io/en/latest/intro.html Use iso8583.pp to display decoded or encoded messages in a human-readable format. ```python >>> import iso8583 >>> from iso8583.specs import default_ascii as spec >>> encoded_raw = b'02004000000000000000101234567890' >>> decoded, encoded = iso8583.decode(encoded_raw, spec) >>> iso8583.pp(decoded, spec) t Message Type : '0200' p Bitmap, Primary : '4000000000000000' 2 Primary Account Number (PAN) : '1234567890' >>> iso8583.pp(encoded, spec) t Message Type : b'0200' p Bitmap, Primary : b'4000000000000000' 2 Primary Account Number (PAN) : b'10' b'1234567890' ``` -------------------------------- ### Convert ISO8583 Data to JSON Source: https://pyiso8583.readthedocs.io/en/latest/howto.html Serialize decoded ISO8583 message dictionaries into JSON strings using the standard json library. ```python >>> import json >>> import pprint >>> import iso8583 >>> from iso8583.specs import default_ascii as spec >>> encoded_raw = b'0200600008000000000014cardholder PAN111111021' >>> decoded, encoded = iso8583.decode(encoded_raw, spec) >>> pprint.pp(decoded) {'t': '0200', 'p': '6000080000000000', '2': 'cardholder PAN', '3': '111111', '21': '021'} >>> decoded_json = json.dumps(decoded) >>> decoded_json '{"t": "0200", "p": "6000080000000000", "2": "cardholder PAN", "3": "111111", "21": "021"}' ``` -------------------------------- ### Define DecodeError Exception Source: https://pyiso8583.readthedocs.io/en/latest/_modules/iso8583/decoder.html Custom exception class for ISO8583 decoding errors, capturing state information like position and field name. ```python class DecodeError(ValueError): r"""Subclass of ValueError that describes ISO8583 decoding error. Attributes ---------- msg : str The unformatted error message s : bytes or bytearray The ISO8583 bytes instance being parsed doc_dec : dict Dict containing partially decoded ISO8583 data doc_enc : dict Dict containing partially encoded ISO8583 data pos : int The start index where ISO8583 bytes data failed parsing field : str The ISO8583 field where parsing failed """ def __init__( self, msg: str, s: Union[bytes, bytearray], doc_dec: DecodedDict, doc_enc: EncodedDict, pos: int, field: str, ): errmsg = f"{msg}: field {field} pos {pos}" ValueError.__init__(self, errmsg) self.msg = msg self.s = s self.doc_dec = doc_dec self.doc_enc = doc_enc self.field = field self.pos = pos def __reduce__( self, ) -> Tuple[ Type["DecodeError"], Tuple[str, Union[bytes, bytearray], DecodedDict, EncodedDict, int, str], ]: return ( self.__class__, (self.msg, self.s, self.doc_dec, self.doc_enc, self.pos, self.field), ) ``` -------------------------------- ### iso8583.pp Source: https://pyiso8583.readthedocs.io/en/latest/_sources/functions.rst.txt Helper function to pretty-print ISO 8583 messages. ```APIDOC ## iso8583.pp(data) ### Description Prints a human-readable representation of an ISO 8583 message. ### Parameters - **data** (dict/str) - The message to format and print. ``` -------------------------------- ### Define ASCII Field with Binary Length Source: https://pyiso8583.readthedocs.io/en/latest/specifications.html Configures a 16-byte ASCII field that uses binary length encoding. ```python specification["2"] = { "data_enc": "ascii", "len_enc": "b", "len_type": 1, "max_len": 16, "desc": "ASCII field with binary length, e.g. \x101234567890123456" } ``` -------------------------------- ### Field Length and Data Parsing Logic Source: https://pyiso8583.readthedocs.io/en/latest/_modules/iso8583/decoder.html Handles conversion between nibbles and bytes for field length and extracts raw data from the byte array. ```python # Encoded field length can be in bytes or half bytes (nibbles) # Convert nibbles to bytes if needed if len_count == "nibbles": if enc_field_len & 1: byte_field_len = (enc_field_len + 1) // 2 else: byte_field_len = enc_field_len // 2 else: byte_field_len = enc_field_len # Parse field data doc_enc[field_key]["data"] = bytes(s[idx : idx + byte_field_len]) if len(doc_enc[field_key]["data"]) != byte_field_len: if len_count == "nibbles": actual_field_len = len(doc_enc[field_key]["data"]) * 2 else: actual_field_len = len(doc_enc[field_key]["data"]) raise DecodeError( f"Field data is {actual_field_len} {len_count}, expecting {enc_field_len}", s, doc_dec, doc_enc, idx, field_key, ) if field_spec["data_enc"] == "b": doc_dec[field_key] = doc_enc[field_key]["data"].hex().upper() if len_count == "nibbles" and enc_field_len & 1: doc_dec[field_key] = _remove_pad_field( s, idx, doc_dec, doc_enc, field_key, field_spec, enc_field_len, ) else: doc_dec[field_key] = _decode_text_data( s, doc_enc[field_key]["data"], idx, doc_dec, doc_enc, field_key, field_spec, ) return idx + byte_field_len ``` -------------------------------- ### Define Binary Primary Bitmap Field Source: https://pyiso8583.readthedocs.io/en/latest/specifications.html Configures a binary primary bitmap field with a fixed length of 8 bytes. ```python specification["p"] = { "data_enc": "b", "len_enc": "ascii", "len_type": 0, "max_len": 8, "desc": "Binary bitmap, e.g. \x12\x34\x56\x78\x90\xAB\xCD\xEF" } ``` -------------------------------- ### Overwrite existing bitmap Source: https://pyiso8583.readthedocs.io/en/latest/howto.html Shows that manually specified primary or secondary bitmaps are automatically overwritten with the correct values during encoding. ```python >>> decoded = { ... 't': '0200', ... 'p': 'spam', ... '1': 'eggs', ... '102': '111111'} >>> encoded_raw, encoded = iso8583.encode(decoded, spec) >>> encoded_raw bytearray(b'02008000000000000000000000000400000006111111') >>> pprint.pp(encoded) {'t': {'len': b'', 'data': b'0200'}, 'p': {'len': b'', 'data': b'8000000000000000'}, '1': {'len': b'', 'data': b'0000000004000000'}, '102': {'len': b'06', 'data': b'111111'}} >>> pprint.pp(decoded) {'t': '0200', 'p': '8000000000000000', '102': '111111', '1': '0000000004000000'} ``` -------------------------------- ### Convert JSON back to ISO8583 Source: https://pyiso8583.readthedocs.io/en/latest/howto.html Deserialize JSON strings back into dictionaries for encoding into ISO8583 raw bytes. ```python >>> encoded_raw, encoded = iso8583.encode(json.loads(decoded_json), spec) >>> encoded_raw bytearray(b'0200600008000000000014cardholder PAN111111021') ``` -------------------------------- ### Define Hex String Primary Bitmap Field Source: https://pyiso8583.readthedocs.io/en/latest/specifications.html Configures a hex string primary bitmap field with a fixed length of 16 bytes. ```python specification["p"] = { "data_enc": "ascii", "len_enc": "ascii", "len_type": 0, "max_len": 16, "desc": "Hex string bitmap, e.g 1234567890ABCDEF" } ``` -------------------------------- ### Convert ISO8583 to and from JSON Source: https://pyiso8583.readthedocs.io/en/latest/_sources/howto.rst.txt Serialize decoded ISO8583 messages to JSON strings and reconstruct them for encoding. Specifications can also be serialized to JSON for portability. ```python >>> import json >>> import pprint >>> import iso8583 >>> from iso8583.specs import default_ascii as spec >>> encoded_raw = b'0200600008000000000014cardholder PAN111111021' >>> decoded, encoded = iso8583.decode(encoded_raw, spec) >>> pprint.pp(decoded) {'t': '0200', 'p': '6000080000000000', '2': 'cardholder PAN', '3': '111111', '21': '021'} >>> decoded_json = json.dumps(decoded) >>> decoded_json '{"t": "0200", "p": "6000080000000000", "2": "cardholder PAN", "3": "111111", "21": "021"}' ``` ```python >>> encoded_raw, encoded = iso8583.encode(json.loads(decoded_json), spec) >>> encoded_raw bytearray(b'0200600008000000000014cardholder PAN111111021') ``` ```python >>> import json >>> import pprint >>> import iso8583 >>> from iso8583.specs import default_ascii as spec >>> spec_json = json.dumps(spec) >>> decoded = { ... 't': '0200', ... '2': 'PAN'} >>> encoded_raw, encoded = iso8583.encode(decoded, json.loads(spec_json)) >>> encoded_raw bytearray(b'0200400000000000000003PAN') >>> pprint.pp(encoded) {'t': {'len': b'', 'data': b'0200'}, 'p': {'len': b'', 'data': b'4000000000000000'}, '2': {'len': b'03', 'data': b'PAN'}} >>> pprint.pp(decoded) {'t': '0200', '2': 'PAN', 'p': '4000000000000000'} ``` -------------------------------- ### Encode Text Fields Source: https://pyiso8583.readthedocs.io/en/latest/_modules/iso8583/encoder.html Encodes an individual ISO8583 field using the specified character encoding. ```python def _encode_text_field( doc_dec: DecodedDict, doc_enc: EncodedDict, field_data: str, field_key: str, field_spec: _FieldSpecDict, len_count: str, ) -> Tuple[bytes, int]: r"""Encode ISO8583 individual field. Parameters ---------- doc_dec : dict Dict containing decoded ISO8583 data doc_enc : dict Dict containing encoded ISO8583 data field_data : str Field data to encode field_key : str Field ID to be encoded field_spec : dict A Python dict defining ISO8583 specification for this field. See :mod:`iso8583.specs` module for examples. Returns ------- tuple(bytes, int) Encoded data and length of the encoded ISO8583 field data. The length is either nibbles or bytes. Raises ------ EncodeError An error encoding ISO8583 bytearray. """ try: encoded_data = field_data.encode(field_spec["data_enc"]) except LookupError: raise EncodeError( "Failed to encode field, unknown encoding specified", doc_dec, doc_enc, field_key, ) from None except Exception: raise EncodeError( "Failed to encode field, invalid data", doc_dec, doc_enc, field_key, ) from None # Encoded field length can be in bytes or half bytes (nibbles) # Encoded nibble length directly corresponds to the count of received nibbles. if len_count == "nibbles": return (encoded_data, len(encoded_data) * 2) else: return (encoded_data, len(encoded_data)) ``` -------------------------------- ### Define Fixed Length Binary or BCD Field Source: https://pyiso8583.readthedocs.io/en/latest/specifications.html Configures a 10-byte fixed length field using binary or BCD encoding. ```python specification["2"] = { "data_enc": "b", "len_enc": "ascii", "len_type": 0, "max_len": 10, "desc": "Binary or BCD fixed field" } ``` -------------------------------- ### Define Nibble-based LLVAR Field with Padding Source: https://pyiso8583.readthedocs.io/en/latest/specifications.html Configures a binary or BCD LLVAR field measured in nibbles, including left-padding with '0'. ```python specification["5"] = { "data_enc": "b", "len_enc": "bcd", "len_type": 1, "len_count": "nibbles", "left_pad": "0", "max_len": 20, "desc": "Binary or BCD LLVAR field measured in nibbles, e.g. \x03\x01\x11" } ``` -------------------------------- ### Define Fixed Length Nibble Field with Right Padding Source: https://pyiso8583.readthedocs.io/en/latest/specifications.html Configures a 3-nibble fixed length field with right-padding using '0'. ```python specification["6"] = { "data_enc": "b", "len_enc": "ascii", "len_type": 0, "len_count": "nibbles", "right_pad": "0", "max_len": 3, "desc": "Binary or BCD fixed field measured in nibbles, e.g. \x11\x10" } ``` -------------------------------- ### iso8583.encode(doc_dec, spec) Source: https://pyiso8583.readthedocs.io/en/latest/functions.html Serialize a Python dictionary containing ISO8583 data into a bytearray. ```APIDOC ## iso8583.encode(doc_dec, spec) ### Description Serialize Python dict containing ISO8583 data to a bytearray. ### Parameters - **doc_dec** (dict) - Required - Dict containing decoded ISO8583 data - **spec** (dict) - Required - A Python dict defining ISO8583 specification. ### Returns - **s** (bytearray) - Encoded ISO8583 data - **doc_enc** (dict) - Dict containing encoded ISO8583 data ### Raises - **EncodeError** - An error encoding ISO8583 bytearray - **TypeError** - doc_dec must be a dict instance ``` -------------------------------- ### Serialize ISO8583 Specifications to JSON Source: https://pyiso8583.readthedocs.io/en/latest/howto.html ISO8583 specification objects are JSON compatible, allowing them to be serialized and reloaded for encoding operations. ```python >>> import json >>> import pprint >>> import iso8583 >>> from iso8583.specs import default_ascii as spec >>> spec_json = json.dumps(spec) >>> decoded = { ... 't': '0200', ... '2': 'PAN'} >>> encoded_raw, encoded = iso8583.encode(decoded, json.loads(spec_json)) >>> encoded_raw bytearray(b'0200400000000000000003PAN') >>> pprint.pp(encoded) {'t': {'len': b'', 'data': b'0200'}, 'p': {'len': b'', 'data': b'4000000000000000'}, '2': {'len': b'03', 'data': b'PAN'}} >>> pprint.pp(decoded) {'t': '0200', '2': 'PAN', 'p': '4000000000000000'} ``` -------------------------------- ### Define ASCII LLVAR Field Source: https://pyiso8583.readthedocs.io/en/latest/specifications.html Configures an ASCII LLVAR field with a maximum length of 20 bytes. ```python specification["3"] = { "data_enc": "ascii", "len_enc": "ascii", "len_type": 2, "max_len": 20, "desc": "ASCII LLVAR field" } ```