ofxparse-0.14/ 0000775 0001750 0001750 00000000000 12210373440 015017 5 ustar jseutter jseutter 0000000 0000000 ofxparse-0.14/setup.cfg 0000644 0001750 0001750 00000000160 12210373440 016633 0 ustar jseutter jseutter 0000000 0000000 [egg_info]
tag_svn_revision = 0
tag_build =
tag_date = 0
[aliases]
release = register sdist bdist_egg upload
ofxparse-0.14/PKG-INFO 0000664 0001750 0001750 00000007464 12210373440 016127 0 ustar jseutter jseutter 0000000 0000000 Metadata-Version: 1.1
Name: ofxparse
Version: 0.14
Summary: Tools for working with the OFX (Open Financial Exchange) file format
Home-page: http://sites.google.com/site/ofxparse
Author: Jerry Seutter
Author-email: jseutter.ofxparse@gmail.com
License: MIT License
Description: ofxparse
========
ofxparse is a parser for Open Financial Exchange (.ofx) format files. OFX
files are available from almost any online banking site, so they work well
if you want to pull together your finances from multiple sources. Online
trading accounts also provide account statements in OFX files.
There are three different types of OFX files, called BankAccount,
CreditAccount and InvestmentAccount files. This library has been tested with
real-world samples of all three types. If you find a file that does not work
with this library, please consider contributing the file so ofxparse can be
improved. See the Help! section below for directions on how to do this.
Example Usage
=============
Here's a sample program::
from ofxparse import OfxParser
ofx = OfxParser.parse(file('file.ofx'))
ofx.accounts # An account with information
ofx.account.number # The account number
ofx.account.routing_number # The transit id (sometimes called branch number)
ofx.account.statement # Account information for a period of time
ofx.account.statement.start_date # The start date of the transactions
ofx.account.statement.end_date # The end date of the transactions
ofx.account.statement.transactions # A list of account activities
ofx.account.statement.balance # The money in the account as of the statement date
ofx.account.statement.available_balance # The money available from the account as of the statement date
Help!
=====
Sample .ofx files are very useful. If you want to help us out, please edit
all identifying information from the file and then email it to jseutter dot
ofxparse at gmail dot com.
Development
===========
Prerequisites::
(Ubuntu) sudo apt-get install python-beautifulsoup python-nose python-coverage-test-runner
(pip) pip install BeautifulSoup nose coverage
Tests::
Simply running the "nose" command should run the tests. If you don't have nose
installed, the following might also work:
python -m unittest tests.test_parse
Test Coverage Report::
coverage run -m unittest tests.test_parse
coverage html
firefox htmlcov/index.html
Homepage
========
http://sites.google.com/site/ofxparse
License
=======
ofxparse is released under an MIT license. See the LICENSE file for the actual
license text. The basic idea is that if you can use Python to do what you are
doing, you can also use this library.
Keywords: ofx,Open Financial Exchange,file formats
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Natural Language :: English
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 2.5
Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Utilities
Classifier: License :: OSI Approved :: MIT License
ofxparse-0.14/tests/ 0000775 0001750 0001750 00000000000 12210373440 016161 5 ustar jseutter jseutter 0000000 0000000 ofxparse-0.14/tests/__init__.py 0000664 0001750 0001750 00000000000 12116146620 020263 0 ustar jseutter jseutter 0000000 0000000 ofxparse-0.14/tests/test_write.py 0000664 0001750 0001750 00000000647 12176230107 020736 0 ustar jseutter jseutter 0000000 0000000 from __future__ import absolute_import
from ofxparse import OfxParser as op
from unittest import TestCase
import sys
sys.path.append('..')
from .support import open_file
class TestOfxWrite(TestCase):
def test_write(self):
test_file = open_file('fidelity.ofx')
ofx_doc = op.parse(test_file)
self.assertEqual(str(ofx_doc), "")
if __name__ == "__main__":
import unittest
unittest.main()
ofxparse-0.14/tests/test_parse.py 0000664 0001750 0001750 00000053716 12176230107 020723 0 ustar jseutter jseutter 0000000 0000000 from __future__ import absolute_import
from ofxparse.ofxparse import soup_maker
from datetime import datetime, timedelta
from decimal import Decimal
from unittest import TestCase
import sys
sys.path.append('..')
import six
from .support import open_file
from ofxparse import OfxParser, AccountType, Account, Statement, Transaction
from ofxparse.ofxparse import OfxFile, OfxPreprocessedFile, OfxParserException
class TestOfxPreprocessedFile(TestCase):
def testPreprocess(self):
fh = six.BytesIO(six.b("""OFXHEADER:100
DATA:OFXSGML
VERSION:102
SECURITY:NONE
ENCODING:USASCII
CHARSET:1252
COMPRESSION:NONE
OLDFILEUID:NONE
NEWFILEUID:NONE
abNet2222Gross3333
"""))
expect = """OFXHEADER:100
DATA:OFXSGML
VERSION:102
SECURITY:NONE
ENCODING:USASCII
CHARSET:1252
COMPRESSION:NONE
OLDFILEUID:NONE
NEWFILEUID:NONE
abNet2222Gross3333
"""
ofx_file = OfxPreprocessedFile(fh)
data = ofx_file.fh.read()
self.assertEqual(data,expect)
def testHeaders(self):
expect = {"OFXHEADER": six.u("100"),
"DATA": six.u("OFXSGML"),
"VERSION": six.u("102"),
"SECURITY": None,
"ENCODING": six.u("USASCII"),
"CHARSET": six.u("1252"),
"COMPRESSION": None,
"OLDFILEUID": None,
"NEWFILEUID": None,
}
ofx = OfxParser.parse(open_file('bank_medium.ofx'))
self.assertEquals(expect, ofx.headers)
def testUTF8(self):
fh = six.BytesIO(six.b("""OFXHEADER:100
DATA:OFXSGML
VERSION:102
SECURITY:NONE
ENCODING:UNICODE
COMPRESSION:NONE
OLDFILEUID:NONE
NEWFILEUID:NONE
"""))
ofx_file = OfxPreprocessedFile(fh)
headers = ofx_file.headers
data = ofx_file.fh.read()
self.assertTrue(type(data) is six.text_type)
for key, value in six.iteritems(headers):
self.assertTrue(type(key) is six.text_type)
self.assertTrue(type(value) is not six.binary_type)
def testCP1252(self):
fh = six.BytesIO(six.b("""OFXHEADER:100
DATA:OFXSGML
VERSION:102
SECURITY:NONE
ENCODING:USASCII
CHARSET: 1252
COMPRESSION:NONE
OLDFILEUID:NONE
NEWFILEUID:NONE
"""))
ofx_file = OfxPreprocessedFile(fh)
headers = ofx_file.headers
result = ofx_file.fh.read()
self.assertTrue(type(result) is six.text_type)
for key, value in six.iteritems(headers):
self.assertTrue(type(key) is six.text_type)
self.assertTrue(type(value) is not six.binary_type)
def testUTF8Japanese(self):
fh = six.BytesIO(six.b("""OFXHEADER:100
DATA:OFXSGML
VERSION:102
SECURITY:NONE
ENCODING:UTF-8
CHARSET:CSUNICODE
COMPRESSION:NONE
OLDFILEUID:NONE
NEWFILEUID:NONE
"""))
ofx_file = OfxPreprocessedFile(fh)
headers = ofx_file.headers
result = ofx_file.fh.read()
self.assertTrue(type(result) is six.text_type)
for key, value in six.iteritems(headers):
self.assertTrue(type(key) is six.text_type)
self.assertTrue(type(value) is not six.binary_type)
def testBrokenLineEndings(self):
fh = six.BytesIO(six.b("OFXHEADER:100\rDATA:OFXSGML\r"))
ofx_file = OfxPreprocessedFile(fh)
self.assertEquals(len(ofx_file.headers.keys()), 2)
class TestOfxFile(TestCase):
def testHeaders(self):
expect = {"OFXHEADER": six.u("100"),
"DATA": six.u("OFXSGML"),
"VERSION": six.u("102"),
"SECURITY": None,
"ENCODING": six.u("USASCII"),
"CHARSET": six.u("1252"),
"COMPRESSION": None,
"OLDFILEUID": None,
"NEWFILEUID": None,
}
ofx = OfxParser.parse(open_file('bank_medium.ofx'))
self.assertEquals(expect, ofx.headers)
def testUTF8(self):
fh = six.BytesIO(six.b("""OFXHEADER:100
DATA:OFXSGML
VERSION:102
SECURITY:NONE
ENCODING:UNICODE
COMPRESSION:NONE
OLDFILEUID:NONE
NEWFILEUID:NONE
"""))
ofx_file = OfxFile(fh)
headers = ofx_file.headers
data = ofx_file.fh.read()
self.assertTrue(type(data) is six.text_type)
for key, value in six.iteritems(headers):
self.assertTrue(type(key) is six.text_type)
self.assertTrue(type(value) is not six.binary_type)
def testCP1252(self):
fh = six.BytesIO(six.b("""OFXHEADER:100
DATA:OFXSGML
VERSION:102
SECURITY:NONE
ENCODING:USASCII
CHARSET: 1252
COMPRESSION:NONE
OLDFILEUID:NONE
NEWFILEUID:NONE
"""))
ofx_file = OfxFile(fh)
headers = ofx_file.headers
result = ofx_file.fh.read()
self.assertTrue(type(result) is six.text_type)
for key, value in six.iteritems(headers):
self.assertTrue(type(key) is six.text_type)
self.assertTrue(type(value) is not six.binary_type)
def testUTF8Japanese(self):
fh = six.BytesIO(six.b("""OFXHEADER:100
DATA:OFXSGML
VERSION:102
SECURITY:NONE
ENCODING:UTF-8
CHARSET:CSUNICODE
COMPRESSION:NONE
OLDFILEUID:NONE
NEWFILEUID:NONE
"""))
ofx_file = OfxFile(fh)
headers = ofx_file.headers
result = ofx_file.fh.read()
self.assertTrue(type(result) is six.text_type)
for key, value in six.iteritems(headers):
self.assertTrue(type(key) is six.text_type)
self.assertTrue(type(value) is not six.binary_type)
def testBrokenLineEndings(self):
fh = six.BytesIO(six.b("OFXHEADER:100\rDATA:OFXSGML\r"))
ofx_file = OfxFile(fh)
self.assertEquals(len(ofx_file.headers.keys()), 2)
class TestParse(TestCase):
def testEmptyFile(self):
fh = six.BytesIO(six.b(""))
self.assertRaises(OfxParserException, OfxParser.parse, fh)
def testThatParseWorksWithoutErrors(self):
OfxParser.parse(open_file('bank_medium.ofx'))
def testThatParseFailsIfNothingToParse(self):
self.assertRaises(TypeError, OfxParser.parse, None)
def testThatParseFailsIfAPathIsPassedIn(self):
# A file handle should be passed in, not the path.
self.assertRaises(RuntimeError, OfxParser.parse, '/foo/bar')
def testThatParseReturnsAResultWithABankAccount(self):
ofx = OfxParser.parse(open_file('bank_medium.ofx'))
self.assertTrue(ofx.account is not None)
def testEverything(self):
ofx = OfxParser.parse(open_file('bank_medium.ofx'))
self.assertEquals('12300 000012345678', ofx.account.number)
self.assertEquals('160000100', ofx.account.routing_number)
self.assertEquals('00', ofx.account.branch_id)
self.assertEquals('CHECKING', ofx.account.account_type)
self.assertEquals(Decimal('382.34'), ofx.account.statement.balance)
# Todo: support values in decimal or int form.
# self.assertEquals('15',
# ofx.bank_account.statement.balance_in_pennies)
self.assertEquals(
Decimal('682.34'), ofx.account.statement.available_balance)
self.assertEquals(
datetime(2009, 4, 1), ofx.account.statement.start_date)
self.assertEquals(
datetime(2009, 5, 23, 12, 20, 17), ofx.account.statement.end_date)
self.assertEquals(3, len(ofx.account.statement.transactions))
transaction = ofx.account.statement.transactions[0]
self.assertEquals("MCDONALD'S #112", transaction.payee)
self.assertEquals('pos', transaction.type)
self.assertEquals(Decimal('-6.60'), transaction.amount)
# Todo: support values in decimal or int form.
# self.assertEquals('15', transaction.amount_in_pennies)
def testMultipleAccounts(self):
ofx = OfxParser.parse(open_file('multiple_accounts2.ofx'))
self.assertEquals(2, len(ofx.accounts))
self.assertEquals('9100', ofx.accounts[0].number)
self.assertEquals('9200', ofx.accounts[1].number)
self.assertEquals('123', ofx.accounts[0].routing_number)
self.assertEquals('123', ofx.accounts[1].routing_number)
self.assertEquals('CHECKING', ofx.accounts[0].account_type)
self.assertEquals('SAVINGS', ofx.accounts[1].account_type)
class TestStringToDate(TestCase):
''' Test the string to date parser '''
def test_bad_format(self):
''' A poorly formatted string should throw a ValueError '''
bad_string = 'abcdLOL!'
self.assertRaises(ValueError, OfxParser.parseOfxDateTime, bad_string)
bad_but_close_string = '881103'
self.assertRaises(ValueError, OfxParser.parseOfxDateTime, bad_string)
no_month_string = '19881301'
self.assertRaises(ValueError, OfxParser.parseOfxDateTime, bad_string)
def test_parses_correct_time(self):
'''Test whether it can parse correct time for some valid time fields'''
self.assertEquals(OfxParser.parseOfxDateTime('19881201'),
datetime(1988, 12, 1, 0, 0))
self.assertEquals(OfxParser.parseOfxDateTime('19881201230100'),
datetime(1988, 12, 1, 23, 1))
self.assertEquals(OfxParser.parseOfxDateTime('20120229230100'),
datetime(2012, 2, 29, 23, 1))
def test_parses_time_offset(self):
''' Test that we handle GMT offset '''
self.assertEquals(OfxParser.parseOfxDateTime('20001201120000 [0:GMT]'),
datetime(2000, 12, 1, 12, 0))
self.assertEquals(OfxParser.parseOfxDateTime('19991201120000 [1:ITT]'),
datetime(1999, 12, 1, 11, 0))
self.assertEquals(
OfxParser.parseOfxDateTime('19881201230100 [-5:EST]'),
datetime(1988, 12, 2, 4, 1))
self.assertEquals(
OfxParser.parseOfxDateTime('20120229230100 [-6:CAT]'),
datetime(2012, 3, 1, 5, 1))
self.assertEquals(
OfxParser.parseOfxDateTime('20120412120000 [-5.5:XXX]'),
datetime(2012, 4, 12, 17, 30))
self.assertEquals(
OfxParser.parseOfxDateTime('20120412120000 [-5:XXX]'),
datetime(2012, 4, 12, 17))
self.assertEquals(
OfxParser.parseOfxDateTime('20120922230000 [+9:JST]'),
datetime(2012, 9, 22, 14, 0))
class TestParseStmtrs(TestCase):
input = '''
CAD16000010012300 000012345678CHECKING
2009040120090523122017
POS20090401122017.000[-5:EST]-6.600000123456782009040100001MCDONALD'S #112POS MERCHANDISE;MCDONALD'S #112
382.3420090523122017682.3420090523122017
'''
def testThatParseStmtrsReturnsAnAccount(self):
stmtrs = soup_maker(self.input)
account = OfxParser.parseStmtrs(
stmtrs.find('stmtrs'), AccountType.Bank)[0]
self.assertEquals('12300 000012345678', account.number)
self.assertEquals('160000100', account.routing_number)
self.assertEquals('CHECKING', account.account_type)
def testThatReturnedAccountAlsoHasAStatement(self):
stmtrs = soup_maker(self.input)
account = OfxParser.parseStmtrs(
stmtrs.find('stmtrs'), AccountType.Bank)[0]
self.assertTrue(hasattr(account, 'statement'))
class TestAccount(TestCase):
def testThatANewAccountIsValid(self):
account = Account()
self.assertEquals('', account.number)
self.assertEquals('', account.routing_number)
self.assertEquals('', account.account_type)
self.assertEquals(None, account.statement)
class TestParseStatement(TestCase):
def testThatParseStatementReturnsAStatement(self):
input = '''
20090523122017
0
INFO
OK
CAD
160000100
12300 000012345678
CHECKING
20090401
20090523122017
POS
20090401122017.000[-5:EST]
-6.60
0000123456782009040100001
MCDONALD'S #112
POS MERCHANDISE;MCDONALD'S #112
382.34
20090523122017
682.34
20090523122017
'''
txn = soup_maker(input)
statement = OfxParser.parseStatement(txn.find('stmttrnrs'))
self.assertEquals(datetime(2009, 4, 1), statement.start_date)
self.assertEquals(
datetime(2009, 5, 23, 12, 20, 17), statement.end_date)
self.assertEquals(1, len(statement.transactions))
self.assertEquals(Decimal('382.34'), statement.balance)
self.assertEquals(Decimal('682.34'), statement.available_balance)
class TestStatement(TestCase):
def testThatANewStatementIsValid(self):
statement = Statement()
self.assertEquals('', statement.start_date)
self.assertEquals('', statement.end_date)
self.assertEquals(0, len(statement.transactions))
class TestParseTransaction(TestCase):
def testThatParseTransactionReturnsATransaction(self):
input = '''
POS
20090401122017.000[-5:EST]
-6.60
0000123456782009040100001
MCDONALD'S #112
POS MERCHANDISE;MCDONALD'S #112
'''
txn = soup_maker(input)
transaction = OfxParser.parseTransaction(txn.find('stmttrn'))
self.assertEquals('pos', transaction.type)
self.assertEquals(datetime(
2009, 4, 1, 12, 20, 17) - timedelta(hours=-5), transaction.date)
self.assertEquals(Decimal('-6.60'), transaction.amount)
self.assertEquals('0000123456782009040100001', transaction.id)
self.assertEquals("MCDONALD'S #112", transaction.payee)
self.assertEquals("POS MERCHANDISE;MCDONALD'S #112", transaction.memo)
def testThatParseTransactionWithFieldCheckNum(self):
input = '''
DEP
20130306
1000.00
2013030601009100
700
DEPOSITO ONLINE
'''
txn = soup_maker(input)
transaction = OfxParser.parseTransaction(txn.find('stmttrn'))
self.assertEquals('700', transaction.checknum)
class TestTransaction(TestCase):
def testThatAnEmptyTransactionIsValid(self):
t = Transaction()
self.assertEquals('', t.payee)
self.assertEquals('', t.type)
self.assertEquals(None, t.date)
self.assertEquals(None, t.amount)
self.assertEquals('', t.id)
self.assertEquals('', t.memo)
self.assertEquals('', t.checknum)
class TestInvestmentAccount(TestCase):
sample = '''
38737714201101012011062420110624
0
INFO
'''
def testThatParseCanCreateAnInvestmentAccount(self):
OfxParser.parse(six.BytesIO(six.b(self.sample)))
# Success!
class TestVanguardInvestmentStatement(TestCase):
def testForUnclosedTags(self):
ofx = OfxParser.parse(open_file('vanguard.ofx'))
self.assertTrue(hasattr(ofx, 'account'))
self.assertTrue(hasattr(ofx.account, 'statement'))
self.assertTrue(hasattr(ofx.account.statement, 'transactions'))
self.assertEquals(len(ofx.account.statement.transactions), 1)
self.assertEquals(ofx.account.statement.transactions[0].id,
'01234567890.0123.07152011.0')
self.assertEquals(ofx.account.statement.transactions[0]
.tradeDate, datetime(2011, 7, 15, 21))
self.assertEquals(ofx.account.statement.transactions[0]
.settleDate, datetime(2011, 7, 15, 21))
self.assertTrue(hasattr(ofx.account.statement, 'positions'))
self.assertEquals(len(ofx.account.statement.positions), 2)
self.assertEquals(
ofx.account.statement.positions[0].units, Decimal('102.0'))
def testSecurityListSuccess(self):
ofx = OfxParser.parse(open_file('vanguard.ofx'))
self.assertEquals(len(ofx.security_list), 2)
class TestFidelityInvestmentStatement(TestCase):
def testForUnclosedTags(self):
ofx = OfxParser.parse(open_file('fidelity.ofx'))
self.assertTrue(hasattr(ofx.account.statement, 'positions'))
self.assertEquals(len(ofx.account.statement.positions), 6)
self.assertEquals(
ofx.account.statement.positions[0].units, Decimal('128.0'))
def testSecurityListSuccess(self):
ofx = OfxParser.parse(open_file('fidelity.ofx'))
self.assertEquals(len(ofx.security_list), 7)
class TestAccountInfoAggregation(TestCase):
def testForFourAccounts(self):
ofx = OfxParser.parse(open_file('account_listing_aggregation.ofx'))
self.assertTrue(hasattr(ofx, 'accounts'))
self.assertEquals(len(ofx.accounts), 4)
# first account
account = ofx.accounts[0]
self.assertEquals(account.account_type, 'SAVINGS')
self.assertEquals(account.desc, 'USAA SAVINGS')
self.assertEquals(account.institution.organization, 'USAA')
self.assertEquals(account.number, '0000000001')
self.assertEquals(account.routing_number, '314074269')
# second
account = ofx.accounts[1]
self.assertEquals(account.account_type, 'CHECKING')
self.assertEquals(account.desc, 'FOUR STAR CHECKING')
self.assertEquals(account.institution.organization, 'USAA')
self.assertEquals(account.number, '0000000002')
self.assertEquals(account.routing_number, '314074269')
# third
account = ofx.accounts[2]
self.assertEquals(account.account_type, 'CREDITLINE')
self.assertEquals(account.desc, 'LINE OF CREDIT')
self.assertEquals(account.institution.organization, 'USAA')
self.assertEquals(account.number, '00000000000003')
self.assertEquals(account.routing_number, '314074269')
# fourth
account = ofx.accounts[3]
self.assertEquals(account.account_type, '')
self.assertEquals(account.desc, 'MY CREDIT CARD')
self.assertEquals(account.institution.organization, 'USAA')
self.assertEquals(account.number, '4111111111111111')
class TestGracefulFailures(TestCase):
''' Test that when fail_fast is False, failures are returned to the
caller as warnings and discarded entries in the Statement class.
'''
def testDateFieldMissing(self):
''' The test file contains three transactions in a single
statement.
They fail due to:
1) No date
2) Empty date
3) Invalid date
'''
ofx = OfxParser.parse(open_file('fail_nice/date_missing.ofx'), False)
self.assertEquals(len(ofx.account.statement.transactions), 0)
self.assertEquals(len(ofx.account.statement.discarded_entries), 3)
self.assertEquals(len(ofx.account.statement.warnings), 0)
# Test that it raises an error otherwise.
self.assertRaises(OfxParserException, OfxParser.parse,
open_file('fail_nice/date_missing.ofx'))
def testDecimalConversionError(self):
''' The test file contains a transaction that has a poorly formatted
decimal number ($20). Test that we catch this.
'''
ofx = OfxParser.parse(open_file('fail_nice/decimal_error.ofx'), False)
self.assertEquals(len(ofx.account.statement.transactions), 0)
self.assertEquals(len(ofx.account.statement.discarded_entries), 1)
# Test that it raises an error otherwise.
self.assertRaises(OfxParserException, OfxParser.parse,
open_file('fail_nice/decimal_error.ofx'))
def testEmptyBalance(self):
''' The test file contains empty or blank strings in the balance
fields. Fail nicely on those.
'''
ofx = OfxParser.parse(open_file('fail_nice/empty_balance.ofx'), False)
self.assertEquals(len(ofx.account.statement.transactions), 1)
self.assertEquals(len(ofx.account.statement.discarded_entries), 0)
self.assertFalse(hasattr(ofx.account.statement, 'balance'))
self.assertFalse(hasattr(ofx.account.statement, 'available_balance'))
# Test that it raises an error otherwise.
self.assertRaises(OfxParserException, OfxParser.parse,
open_file('fail_nice/empty_balance.ofx'))
class TestParseSonrs(TestCase):
def testSuccess(self):
ofx = OfxParser.parse(open_file('signon_success.ofx'), True)
self.assertTrue(ofx.signon.success)
self.assertEquals(ofx.signon.code, 0)
self.assertEquals(ofx.signon.severity, 'INFO')
self.assertEquals(ofx.signon.message, 'Login successful')
ofx = OfxParser.parse(open_file('signon_success_no_message.ofx'), True)
self.assertTrue(ofx.signon.success)
self.assertEquals(ofx.signon.code, 0)
self.assertEquals(ofx.signon.severity, 'INFO')
self.assertEquals(ofx.signon.message, '')
def testFailure(self):
ofx = OfxParser.parse(open_file('signon_fail.ofx'), True)
self.assertFalse(ofx.signon.success)
self.assertEquals(ofx.signon.code, 15500)
self.assertEquals(ofx.signon.severity, 'ERROR')
self.assertEquals(ofx.signon.message, 'Your request could not be processed because you supplied an invalid identification code or your password was incorrect')
if __name__ == "__main__":
import unittest
unittest.main()
ofxparse-0.14/tests/fixtures/ 0000775 0001750 0001750 00000000000 12210373440 020032 5 ustar jseutter jseutter 0000000 0000000 ofxparse-0.14/tests/fixtures/signon_fail.ofx 0000664 0001750 0001750 00000000776 12140626070 023054 0 ustar jseutter jseutter 0000000 0000000 OFXHEADER:100
DATA:OFXSGML
VERSION:102
SECURITY:NONE
ENCODING:USASCII
CHARSET:1252
COMPRESSION:NONE
OLDFILEUID:NONE
NEWFILEUID:0e1a88e56fc548a1ba2e83bce6323bb6
15500ERRORYour request could not be processed because you supplied an invalid identification code or your password was incorrect
20130325211209.350[-7:MST]ENGAMEX31012013032521120915500
ofxparse-0.14/tests/fixtures/signon_success_no_message.ofx 0000664 0001750 0001750 00000000572 12140626070 026003 0 ustar jseutter jseutter 0000000 0000000 OFXHEADER:100
DATA:OFXSGML
VERSION:102
SECURITY:NONE
ENCODING:USASCII
CHARSET:1252
COMPRESSION:NONE
OLDFILEUID:NONE
NEWFILEUID:3bb6707632b64da196722ef312e6376d
0INFO
20130325211405.187[-7:MST]ENGAMEX310120130325211405FMPWeb
ofxparse-0.14/tests/fixtures/multiple_accounts2.ofx 0000664 0001750 0001750 00000003066 12116146620 024374 0 ustar jseutter jseutter 0000000 0000000
0
INFO
The operation succeeded.
20120603203135.547[-7:PDT]
ENG
blah
1000
1001
0
INFO
USD
123
00
9100
CHECKING
111
20120603133220.000[-7:PDT]
1002
0
INFO
USD
123
00
9200
SAVINGS
222
20120603133220.000[-7:PDT]
ofxparse-0.14/tests/fixtures/fidelity.ofx 0000664 0001750 0001750 00000034314 12032735501 022370 0 ustar jseutter jseutter 0000000 0000000 OFXHEADER:100
DATA:OFXSGML
VERSION:102
SECURITY:NONE
ENCODING:USASCII
CHARSET:1252
COMPRESSION:NONE
OLDFILEUID:NONE
NEWFILEUID:a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0
0INFOSUCCESS
20120908190849.317[-4:EDT]ENGfidelity.com7776a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a00INFOSUCCESS
20120908033034.000[-4:EDT]USDfidelity.com0123456789020120710000000.000[-4:EDT]20120908190849.555[-4:EDT]012345678902020112012072020120720000000.000[-4:EDT]YOU BOUGHT458140100CUSIP+0000000000100.00000000000025.635000000+00000000000007.9500+00000000000000.0000-00000000002571.45001.00USDCASHCASHBUY 012345678902090112012072720120727000000.000[-4:EDT]YOU BOUGHTG7945E105CUSIP+0000000000128.00000000000039.390900000+00000000000007.9500+00000000000000.0000-00000000005049.99001.00USDCASHCASHBUY 012345678902090122012072720120727000000.000[-4:EDT]YOU BOUGHT431571108CUSIP+0000000000115.00000000000017.250000000+00000000000007.9500+00000000000000.0000-00000000001991.70001.00USDCASHCASHBUY 012345678902130112012073120120731000000.000[-4:EDT]YOU BOUGHT19421R200CUSIP+0000000000069.00000000000014.469900000+00000000000007.9500+00000000000000.0000-00000000001006.37001.00USDCASHCASHBUY 012345678902130162012073120120731000000.000[-4:EDT]YOU BOUGHT98417P105CUSIP+0000000000386.00000000000002.588700000+00000000000007.9500+00000000000000.0000-00000000001007.19001.00USDCASHCASHBUY 012345678902350122012082020120820000000.000[-4:EDT]REINVESTMENT98417P105CUSIP+0000000000004.90900000000002.947400000+00000000000000.0000+00000000000000.0000-00000000000014.47001.00USDCASHCASHBUY 012345678902440112012083120120831000000.000[-4:EDT]REINVESTMENT19421R200CUSIP+0000000000001.57300000000014.257000000+00000000000000.0000+00000000000000.0000-00000000000022.43001.00USDCASHCASHBUY 012345678902480112012090120120901000000.000[-4:EDT]REINVESTMENT458140100CUSIP+0000000000000.91100000000024.705500000+00000000000000.0000+00000000000000.0000-00000000000022.50001.00USDCASHCASHBUY 012345678902130152012073120120731000000.000[-4:EDT]DIVIDEND RECEIVED78462F103CUSIPDIV+00000000000005.5300CASHCASH1.00USD 012345678902350132012082020120820000000.000[-4:EDT]DIVIDEND RECEIVED98417P105CUSIPDIV+00000000000015.4400CASHCASH1.00USD 012345678902440122012083120120831000000.000[-4:EDT]DIVIDEND RECEIVED19421R200CUSIPDIV+00000000000022.4300CASHCASH1.00USD 012345678902480122012090120120901000000.000[-4:EDT]DIVIDEND RECEIVED458140100CUSIPDIV+00000000000022.5000CASHCASH1.00USD 012345678902090132012072720120727000000.000[-4:EDT]YOU SOLD78462F103CUSIP-0000000000008.00000000000137.160000000+00000000000007.9500+00000000000000.0000+00000000001089.30001.00USDCASHCASHSELL 012345678902140142012080120120801000000.000[-4:EDT]IN LIEU OF FRX SHARE78462F103CUSIP-0000000000000.03500000000137.142857143+00000000000000.0000+00000000000000.0000+00000000000004.80001.00USDCASHCASHSELL DEP20120731000000.000[-4:EDT]+00000000000000.24000123456789021301320120731INTEREST EARNEDINTEREST EARNED1.00USD CASH OTHER20120820000000.000[-4:EDT]-00000000000000.97000123456789023501120120820LATE SETTLEMENT FEELATE SETTLEMENT FEE1.00USD CASH DEP20120831000000.000[-4:EDT]+00000000000000.16000123456789024401420120831INTEREST EARNEDINTEREST EARNED1.00USD CASH G7945E105CUSIPCASHLONG128.0000040.8700000+00000005231.3620120908033034.000[-4:EDT]1.0USD19421R200CUSIPCASHLONG70.5730014.3200000+00000001010.6020120908033034.000[-4:EDT]1.0USD431571108CUSIPCASHLONG115.0000018.9300000+00000002176.9520120908033034.000[-4:EDT]1.0USD458140100CUSIPCASHLONG100.9110024.1900000+00000002441.0320120908033034.000[-4:EDT]1.0USD756577102CUSIPCASHLONG50.0000059.1500000+00000002957.5020120908033034.000[-4:EDT]1.0USD98417P105CUSIPCASHLONG390.909002.8200000+00000001102.3620120908033034.000[-4:EDT]1.0USD18073.98+00000000000.00+00000000000.00+00000000000.00NetworthThe net market value of all long and short positions in the accountDOLLAR32993.7920120908033034.000[-4:EDT]1.000USDMargin EquityThe margin market value less any margin debit balanceDOLLAR0.020120908033034.000[-4:EDT]1.000USDMargin Equity PercentageMargin equity / market value of long and short positionsPERCENT0.020120908033034.000[-4:EDT]1.000USDCash Debit BalanceCash Debit BalanceDOLLAR0.020120908033034.000[-4:EDT]1.000USDTotal Money MarketsThe total value of all money market positions in the cash accountDOLLAR18073.9820120908033034.000[-4:EDT]1.000USDHouse SurplusEquity amount above house requirementsDOLLAR0.020120908033034.000[-4:EDT]1.000USDNYSE SurplusEquity amount above exchange requirementsDOLLAR0.020120908033034.000[-4:EDT]1.000USDFederal SurplusAmount above federal requirementsDOLLAR0.020120908033034.000[-4:EDT]1.000USDBuying Power - EquitiesAmount of equities you can buy on margin without generating a margin callDOLLAR0.020120908033034.000[-4:EDT]1.000USDBuying Power - Municipal BondsAmount of municipal bonds you can buy on margin without generating a margin callDOLLAR0.020120908033034.000[-4:EDT]1.000USDBuying Power - Government BondsAmount of government bonds you can buy on margin without generating a margin calDOLLAR0.020120908033034.000[-4:EDT]1.000USDBuying Power - Corporate BondsAmount you can buy of corporate bonds on margin with no margin callDOLLAR0.020120908033034.000[-4:EDT]1.000USDOption Market ValueThe market value of all options in the accountDOLLAR0.020120908033034.000[-4:EDT]1.000USDOption In The Money AmountThe in-the-money amount on covered optionsDOLLAR0.020120908033034.000[-4:EDT]1.000USDCash Market valueTotal value of all cash account positionsDOLLAR14919.820120908033034.000[-4:EDT]1.000USDMargin Market ValueTotal value of positions in margin less in-the-money amount of covered optionsDOLLAR0.020120908033034.000[-4:EDT]1.000USDShort Market ValueTotal value of short positions less in-the-money amount of covered put optionsDOLLAR0.020120908033034.000[-4:EDT]1.000USDAvailable to BorrowCash amount that can be borrowed without generating a margin callDOLLAR0.020120908033034.000[-4:EDT]1.000USDG7945E105CUSIPSEADRILL LTD USD2SDRL20120908033034.000[-4:EDT]1.000USD COMMON20120908033034.000[-4:EDT]19421R200CUSIPCOLLECTORS UNIVERSE INCCLCT20120908033034.000[-4:EDT]1.000USD COMMON20120908033034.000[-4:EDT]431571108CUSIPHILLENBRAND INC COMHI20120908033034.000[-4:EDT]1.000USD COMMON20120908033034.000[-4:EDT]458140100CUSIPINTEL CORPINTC20120908033034.000[-4:EDT]1.000USD COMMON20120908033034.000[-4:EDT]756577102CUSIPRED HAT INCRHT20120908033034.000[-4:EDT]1.000USD COMMON20120908033034.000[-4:EDT]98417P105CUSIPXINYUAN REAL ESTATE ADR EACH REPR 2 ORD SHSXIN20120908033034.000[-4:EDT]1.000USD COMMON20120908033034.000[-4:EDT]78462F103CUSIPSPDR S&P 500 ETF TRUST UNIT SER 1 S&PSPY20120908033034.000[-4:EDT]1.000USD COMMON20120908033034.000[-4:EDT]
ofxparse-0.14/tests/fixtures/fail_nice/ 0000775 0001750 0001750 00000000000 12210373440 021743 5 ustar jseutter jseutter 0000000 0000000 ofxparse-0.14/tests/fixtures/fail_nice/decimal_error.ofx 0000664 0001750 0001750 00000002562 11751467417 025316 0 ustar jseutter jseutter 0000000 0000000
0
INFO
20110614
1
0
INFO
CAD
123845030
192639749
CHECKING
20110412
20110614
OTHER
201120000000
$120
2000957249
Fail1
0
20110614
ofxparse-0.14/tests/fixtures/fail_nice/empty_balance.ofx 0000664 0001750 0001750 00000002634 12116147424 025277 0 ustar jseutter jseutter 0000000 0000000
0
INFO
20110614
1
0
INFO
CAD
123845030
192639749
CHECKING
20110412
20110614
OTHER
20110308020000
120
2000957249
Foobar
20110614
20110614
ofxparse-0.14/tests/fixtures/fail_nice/date_missing.ofx 0000664 0001750 0001750 00000003607 11751467417 025156 0 ustar jseutter jseutter 0000000 0000000
0
INFO
20110614
1
0
INFO
USD
123845030
192639749
CHECKING
20110412
20110614
OTHER
-80.00
184997056
TestFail1
OTHER
200.00
2000957249
TestFail2
OTHER
20120231
200.00
2000957249
TestFail2
0
20110614
ofxparse-0.14/tests/fixtures/signon_success.ofx 0000664 0001750 0001750 00000000623 12140626070 023600 0 ustar jseutter jseutter 0000000 0000000 OFXHEADER:100
DATA:OFXSGML
VERSION:102
SECURITY:NONE
ENCODING:USASCII
CHARSET:1252
COMPRESSION:NONE
OLDFILEUID:NONE
NEWFILEUID:3bb6707632b64da196722ef312e6376d
0INFOLogin successful
20130325211405.187[-7:MST]ENGAMEX310120130325211405FMPWeb
ofxparse-0.14/tests/fixtures/checking.ofx 0000664 0001750 0001750 00000003336 12175537210 022337 0 ustar jseutter jseutter 0000000 0000000 OFXHEADER:100
DATA:OFXSGML
VERSION:102
SECURITY:NONE
ENCODING:USASCII
CHARSET:1252
COMPRESSION:NONE
OLDFILEUID:NONE
NEWFILEUID:NONE
0
INFO
20130525225731.258
ENG
20050531060000.000
FAKE
1101
51123
9774652
0
0
INFO
USD
5472369148
1452687~7
CHECKING
20000101070000.000
20130525060000.000
CREDIT
20110331120000.000
0.01
0000486
DIVIDEND EARNED FOR PERIOD OF 03
DIVIDEND EARNED FOR PERIOD OF 03/01/2011 THROUGH 03/31/2011 ANNUAL PERCENTAGE YIELD EARNED IS 0.05%
DEBIT
20110405120000.000
-34.51
0000487
AUTOMATIC WITHDRAWAL, ELECTRIC BILL
AUTOMATIC WITHDRAWAL, ELECTRIC BILL WEB(S )
CHECK
20110407120000.000
-25.00
0000488
319
RETURNED CHECK FEE, CHECK # 319
RETURNED CHECK FEE, CHECK # 319 FOR $45.33 ON 04/07/11
100.99
20130525225731.258
75.99
20130525225731.258