{"id":10000,"library":"ofxparse","title":"OFXParse","description":"OFXParse (version 0.21) is a Python library designed for parsing and working with the Open Financial Exchange (OFX) file format. It extracts data such as transactions, account information, and balance statements from OFX files, making it easier to integrate financial data into applications. The library is actively maintained with a generally stable release cadence.","status":"active","version":"0.21","language":"en","source_language":"en","source_url":"https://github.com/jc-h-r/ofxparse","tags":["finance","ofx","parser","banking"],"install":[{"cmd":"pip install ofxparse","lang":"bash","label":"Install stable version"}],"dependencies":[],"imports":[{"symbol":"OfxParser","correct":"from ofxparse import OfxParser"}],"quickstart":{"code":"import os\nfrom ofxparse import OfxParser\n\n# Create a dummy OFX file for demonstration\nofx_content_simple = \"\"\"\nOFXHEADER:100\nDATA:OFXSGML\nAOFX:V1\n<OFX>\n    <BANKMSGSRQV1>\n        <STMTTRNRS>\n            <TRNUID>0</TRNUID>\n            <STATUS><CODE>0</CODE><SEVERITY>INFO</SEVERITY></STATUS>\n            <STMTRS>\n                <CURDEF>USD</CURDEF>\n                <BANKACCTFROM>\n                    <BANKID>123456789</BANKID>\n                    <ACCTID>0000000000</ACCTID>\n                    <ACCTTYPE>CHECKING</ACCTTYPE>\n                </BANKACCTFROM>\n                <BANKTRANLIST>\n                    <DTSTART>20230101000000</DTSTART>\n                    <DTEND>20230131000000</DTEND>\n                    <STMTTRN>\n                        <TRNTYPE>DEBIT</TRNTYPE>\n                        <DTPOSTED>20230105000000</DTPOSTED>\n                        <TRNAMT>-50.00</TRNAMT>\n                        <FITID>12345</FITID>\n                        <NAME>Grocery Store</NAME>\n                        <MEMO>Weekly groceries</MEMO>\n                    </STMTTRN>\n                    <STMTTRN>\n                        <TRNTYPE>CREDIT</TRNTYPE>\n                        <DTPOSTED>20230110000000</DTPOSTED>\n                        <TRNAMT>1000.00</TRNAMT>\n                        <FITID>67890</FITID>\n                        <NAME>Payroll</NAME>\n                        <MEMO>Monthly salary</MEMO>\n                    </STMTTRN>\n                </BANKTRANLIST>\n                <LEDGERBAL>\n                    <BALAMT>1500.00</BALAMT>\n                    <DTASOF>20230131000000</DTASOF>\n                </LEDGERBAL>\n            </STMTRS>\n        </STMTTRNRS>\n    </BANKMSGSRQV1>\n</OFX>\n    \"\"\"\n    \nfile_path = \"example.ofx\"\nwith open(file_path, \"w\", encoding=\"utf-8\") as f:\n    f.write(ofx_content_simple)\n\ntry:\n    # Always open OFX files in binary read mode ('rb')\n    with open(file_path, \"rb\") as f:\n        ofx = OfxParser.parse(f)\n\n    if ofx.accounts:\n        account = ofx.accounts[0]\n        print(f\"Bank ID: {account.bank_id}\")\n        print(f\"Account ID: {account.account_id}\")\n        print(f\"Account Type: {account.account_type}\")\n        \n        if account.transactions:\n            print(\"\\nTransactions:\")\n            for transaction in account.transactions:\n                print(f\"  Date: {transaction.date.strftime('%Y-%m-%d')}, Amount: {transaction.amount}, Description: {getattr(transaction, 'memo', 'N/A')}\")\n        else:\n            print(\"\\nNo transactions found.\")\n\n        if account.ledger_balance:\n            print(f\"\\nLedger Balance: {account.ledger_balance}\")\n        else:\n            print(\"\\nNo ledger balance found.\")\n    else:\n        print(\"No accounts found in OFX file.\")\n\nexcept Exception as e:\n    print(f\"Error parsing OFX: {e}\")\nfinally:\n    # Clean up the dummy file\n    if os.path.exists(file_path):\n        os.remove(file_path)\n","lang":"python","description":"This quickstart demonstrates how to parse a simple OFX file. It creates a temporary OFX file, parses it using `OfxParser.parse()`, and then prints out basic account and transaction information. Note the use of `\"rb\"` (binary read mode) for opening the file."},"warnings":[{"fix":"Always check for attribute existence using `if hasattr(obj, 'attr_name')` or `getattr(obj, 'attr_name', default_value)` before access. For lists (e.g., `accounts`, `transactions`), check if the list is non-empty before indexing.","message":"OFX files can have varying structures, encodings, and optional tags. Directly accessing attributes like `transaction.memo` or `ofx.accounts[0].balance` without checking for their existence can lead to `AttributeError`.","severity":"gotcha","affected_versions":"All"},{"fix":"Ensure you open your `.ofx` files using `open(file_path, \"rb\")` and pass the binary file handle to `OfxParser.parse()`. If you have OFX content as a string, encode it to bytes first (e.g., `ofx_string.encode('utf-8')`) or save it to a temporary file and open it in binary mode.","message":"The library expects OFX files to be opened in binary read mode (`\"rb\"`). Opening in text mode (`\"r\"`) without explicit encoding, or attempting to parse a plain string directly, can lead to `UnicodeDecodeError` or `lxml.etree.XMLSyntaxError`.","severity":"gotcha","affected_versions":"All"},{"fix":"Inspect the problematic OFX file for XML validity. Sometimes minor manual cleanup (e.g., removing BOM, correcting invalid characters, ensuring proper closing tags) is required before parsing. Consider using `errors='ignore'` with `.decode()` if manually converting to string before `lxml` processing (though binary mode is preferred).","message":"Parsing malformed or non-standard OFX files can lead to `lxml.etree.XMLSyntaxError` (e.g., 'Premature end of data', 'Document is empty') or incomplete data extraction. This is common with files generated by less compliant financial institutions.","severity":"gotcha","affected_versions":"All"}],"env_vars":null,"last_verified":"2026-04-17T00:00:00.000Z","next_check":"2026-07-16T00:00:00.000Z","problems":[{"fix":"Always open OFX files in binary read mode (`\"rb\"`) and pass the file handle directly to `OfxParser.parse()`. The library is designed to handle various encodings when given a binary stream.","cause":"The OFX file contains characters not compatible with the default UTF-8 decoding, and the file was opened in text mode or processed as a string without specifying the correct encoding, or not handled as binary.","error":"UnicodeDecodeError: 'utf-8' codec can't decode byte 0x__ in position __: invalid start byte"},{"fix":"Verify the content of your OFX file. Ensure it contains actual OFX data and is not zero-bytes. If generating the file, ensure proper content is written. If downloading, try re-downloading the file.","cause":"The input file is empty or `OfxParser.parse()` received an empty or invalid stream/string. This often indicates a corrupted or improperly generated OFX file.","error":"lxml.etree.XMLSyntaxError: Document is empty, line 1, column 1"},{"fix":"Before accessing `ofx.accounts[0].transactions`, check if `ofx.accounts` exists and if `ofx.accounts[0].transactions` is not empty. Example: `if ofx.accounts and ofx.accounts[0].transactions:`","cause":"The specific OFX file being parsed does not contain any transaction data for the account, or the `BANKTRANLIST` section is missing or empty.","error":"AttributeError: 'OfxAccount' object has no attribute 'transactions'"}]}