From 493d49614d5784c83ee055a1321b19b2a2e130a3 Mon Sep 17 00:00:00 2001 From: Tal Wrii Date: Sun, 31 Jan 2016 16:25:10 +0000 Subject: [PATCH 1/2] my editors opinions of your trailing whitespace --- fixofx.py | 68 +++++++++++++++++----------------- lib/ofxtools/qif_converter.py | 8 ++-- test/ofxtools_qif_converter.py | 64 ++++++++++++++++---------------- 3 files changed, 69 insertions(+), 71 deletions(-) diff --git a/fixofx.py b/fixofx.py index 0ebbb2a..fbfce66 100755 --- a/fixofx.py +++ b/fixofx.py @@ -1,13 +1,13 @@ #!/usr/bin/env python # Copyright 2005-2010 Wesabe, Inc. -# +# # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at -# +# # http://www.apache.org/licenses/LICENSE-2.0 -# +# # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -57,67 +57,67 @@ def fixpath(filename): pass -def convert(text, filetype, verbose=False, fid="UNKNOWN", org="UNKNOWN", +def convert(text, filetype, verbose=False, fid="UNKNOWN", org="UNKNOWN", bankid="UNKNOWN", accttype="UNKNOWN", acctid="UNKNOWN", - balance="UNKNOWN", curdef=None, lang="ENG", dayfirst=False, + balance="UNKNOWN", curdef=None, lang="ENG", dayfirst=False, debug=False): - + # This finishes a verbosity message started by the caller, where the # caller explains the source command-line option and this explains the # source format. - if verbose: + if verbose: sys.stderr.write("Converting from %s format.\n" % filetype) if options.debug and (filetype in ["OFC", "QIF"] or filetype.startswith("OFX")): sys.stderr.write("Starting work on raw text:\n") sys.stderr.write(rawtext + "\n\n") - + if filetype.startswith("OFX/2"): if verbose: sys.stderr.write("No conversion needed; returning unmodified.\n") - + # The file is already OFX 2 -- return it unaltered, ignoring # any of the parameters passed to this method. return text - + elif filetype.startswith("OFX"): if verbose: sys.stderr.write("Converting to OFX/2.0...\n") - + # This will throw a ParseException if it is unable to recognize # the source format. - response = ofx.Response(text, debug=debug) + response = ofx.Response(text, debug=debug) return response.as_xml(original_format=filetype) - + elif filetype == "OFC": if verbose: sys.stderr.write("Beginning OFC conversion...\n") converter = ofxtools.OfcConverter(text, fid=fid, org=org, curdef=curdef, lang=lang, debug=debug) - + # This will throw a ParseException if it is unable to recognize # the source format. - if verbose: + if verbose: sys.stderr.write("Converting to OFX/1.02...\n\n%s\n\n" % converter.to_ofx102()) sys.stderr.write("Converting to OFX/2.0...\n") - + return converter.to_xml() - + elif filetype == "QIF": if verbose: sys.stderr.write("Beginning QIF conversion...\n") converter = ofxtools.QifConverter(text, fid=fid, org=org, - bankid=bankid, accttype=accttype, - acctid=acctid, balance=balance, + bankid=bankid, accttype=accttype, + acctid=acctid, balance=balance, curdef=curdef, lang=lang, dayfirst=dayfirst, debug=debug) - + # This will throw a ParseException if it is unable to recognize # the source format. - if verbose: + if verbose: sys.stderr.write("Converting to OFX/1.02...\n\n%s\n\n" % converter.to_ofx102()) sys.stderr.write("Converting to OFX/2.0...\n") - + return converter.to_xml() - + else: raise TypeError("Unable to convert source format '%s'." % filetype) @@ -168,9 +168,9 @@ def convert(text, filetype, verbose=False, fid="UNKNOWN", org="UNKNOWN", if options.filename: if os.path.isfile(options.filename): - if options.verbose: + if options.verbose: sys.stderr.write("Reading from '%s'\n." % options.filename) - + try: srcfile = open(options.filename, 'rU') rawtext = srcfile.read() @@ -180,19 +180,19 @@ def convert(text, filetype, verbose=False, fid="UNKNOWN", org="UNKNOWN", print "Exiting." sys.stderr.write("fixofx failed with error code 1\n") sys.exit(1) - + else: print "'%s' does not appear to be a file. Try --help." % options.filename sys.stderr.write("fixofx failed with error code 2\n") sys.exit(2) else: - if options.verbose: + if options.verbose: sys.stderr.write("Reading from standard input.\n") - + stdin_universal = os.fdopen(os.dup(sys.stdin.fileno()), "rU") rawtext = stdin_universal.read() - + if rawtext == "" or rawtext is None: print "No input. Pipe a file to convert to the script,\n" + \ "or call with -f. Call with --help for more info." @@ -208,16 +208,16 @@ def convert(text, filetype, verbose=False, fid="UNKNOWN", org="UNKNOWN", # rather than parsing the file to make sure. (Parsing will fail # below if the guess is wrong on OFX/1 and QIF.) filetype = ofx.FileTyper(rawtext).trust() - + if options.type: print "Input file type is %s." % filetype sys.exit(0) elif options.debug: sys.stderr.write("Input file type is %s.\n" % filetype) - - converted = convert(rawtext, filetype, verbose=options.verbose, - fid=options.fid, org=options.org, bankid=options.bankid, - accttype=options.accttype, acctid=options.acctid, + + converted = convert(rawtext, filetype, verbose=options.verbose, + fid=options.fid, org=options.org, bankid=options.bankid, + accttype=options.accttype, acctid=options.acctid, balance=options.balance, curdef=options.curdef, lang=options.lang, dayfirst=options.dayfirst, debug=options.debug) diff --git a/lib/ofxtools/qif_converter.py b/lib/ofxtools/qif_converter.py index 25251e2..9cc500f 100644 --- a/lib/ofxtools/qif_converter.py +++ b/lib/ofxtools/qif_converter.py @@ -1,11 +1,11 @@ # Copyright 2005-2010 Wesabe, Inc. -# +# # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at -# +# # http://www.apache.org/licenses/LICENSE-2.0 -# +# # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -630,5 +630,3 @@ def _ofx_txn(self, txn): def _check_field(self, key, txn): return txn.has_key(key) and txn[key].strip() != "" - - diff --git a/test/ofxtools_qif_converter.py b/test/ofxtools_qif_converter.py index ac00261..e67ec65 100644 --- a/test/ofxtools_qif_converter.py +++ b/test/ofxtools_qif_converter.py @@ -1,11 +1,11 @@ # Copyright 2005-2010 Wesabe, Inc. -# +# # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at -# +# # http://www.apache.org/licenses/LICENSE-2.0 -# +# # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -25,7 +25,7 @@ class QifConverterTests(unittest.TestCase): def setUp(self): pass - + def test_bank_stmttype(self): qiftext = textwrap.dedent('''\ !Type:Bank @@ -34,7 +34,7 @@ def test_bank_stmttype(self): ''') converter = ofxtools.QifConverter(qiftext) self.assertEqual(converter.accttype, "CHECKING") - + def test_ccard_stmttype(self): qiftext = textwrap.dedent('''\ !Type:CCard @@ -43,7 +43,7 @@ def test_ccard_stmttype(self): ''') converter = ofxtools.QifConverter(qiftext) self.assertEqual(converter.accttype, "CREDITCARD") - + def test_no_stmttype(self): qiftext = textwrap.dedent('''\ D01/13/2005 @@ -51,7 +51,7 @@ def test_no_stmttype(self): ''') converter = ofxtools.QifConverter(qiftext) self.assertEqual(converter.accttype, "CHECKING") - + def test_no_txns(self): qiftext = textwrap.dedent('''\ !Type:Bank @@ -60,7 +60,7 @@ def test_no_txns(self): converter = ofxtools.QifConverter(qiftext) self.assertEqual(converter.start_date, today) self.assertEqual(converter.end_date, today) - + def test_us_date(self): qiftext = textwrap.dedent('''\ !Type:Bank @@ -69,7 +69,7 @@ def test_us_date(self): ''') converter = ofxtools.QifConverter(qiftext) self.assertTrue(converter.txns_by_date.has_key("20050113")) - + def test_uk_date(self): qiftext = textwrap.dedent('''\ !Type:Bank @@ -78,7 +78,7 @@ def test_uk_date(self): ''') converter = ofxtools.QifConverter(qiftext) self.assertTrue(converter.txns_by_date.has_key("20050113")) - + def test_ambiguous_date(self): qiftext = textwrap.dedent('''\ !Type:Bank @@ -87,7 +87,7 @@ def test_ambiguous_date(self): ''') converter = ofxtools.QifConverter(qiftext) self.assertTrue(converter.txns_by_date.has_key("20051201")) - + def test_mixed_us_dates(self): qiftext = textwrap.dedent('''\ !Type:Bank @@ -99,7 +99,7 @@ def test_mixed_us_dates(self): converter = ofxtools.QifConverter(qiftext) self.assertTrue(converter.txns_by_date.has_key("20050112")) self.assertTrue(converter.txns_by_date.has_key("20050113")) - + def test_mixed_uk_dates(self): qiftext = textwrap.dedent('''\ !Type:Bank @@ -111,7 +111,7 @@ def test_mixed_uk_dates(self): converter = ofxtools.QifConverter(qiftext) self.assertTrue(converter.txns_by_date.has_key("20050112")) self.assertTrue(converter.txns_by_date.has_key("20050113")) - + def test_slashfree_date(self): qiftext = textwrap.dedent('''\ !Type:Bank @@ -120,7 +120,7 @@ def test_slashfree_date(self): ''') converter = ofxtools.QifConverter(qiftext) self.assertTrue(converter.txns_by_date.has_key("20051201")) - + def test_unparseable_date(self): qiftext = textwrap.dedent('''\ !Type:Bank @@ -128,7 +128,7 @@ def test_unparseable_date(self): ^ ''') self.assertRaises(ValueError, ofxtools.QifConverter, qiftext) - + def test_len_eight_no_int_date(self): qiftext = textwrap.dedent('''\ !Type:Bank @@ -136,7 +136,7 @@ def test_len_eight_no_int_date(self): ^ ''') self.assertRaises(ValueError, ofxtools.QifConverter, qiftext) - + def test_asc_dates(self): qiftext = textwrap.dedent('''\ !Type:Bank @@ -147,7 +147,7 @@ def test_asc_dates(self): D02/01/2005 ^ D02/01/2005 - ^ + ^ D02/13/2005 ^ ''') @@ -155,7 +155,7 @@ def test_asc_dates(self): self.assertEqual(converter.start_date, "20050113") self.assertEqual(converter.end_date, "20050213") self.assertEqual(len(converter.txns_by_date.keys()), 4) - + def test_desc_dates(self): qiftext = textwrap.dedent('''\ !Type:Bank @@ -164,7 +164,7 @@ def test_desc_dates(self): D02/01/2005 ^ D02/01/2005 - ^ + ^ D01/27/2005 ^ D01/13/2005 @@ -174,7 +174,7 @@ def test_desc_dates(self): self.assertEqual(converter.start_date, "20050113") self.assertEqual(converter.end_date, "20050213") self.assertEqual(len(converter.txns_by_date.keys()), 4) - + def test_mixed_dates(self): qiftext = textwrap.dedent('''\ !Type:Bank @@ -185,7 +185,7 @@ def test_mixed_dates(self): D01/13/2005 ^ D02/01/2005 - ^ + ^ D01/27/2005 ^ ''') @@ -193,7 +193,7 @@ def test_mixed_dates(self): self.assertEqual(converter.start_date, "20050113") self.assertEqual(converter.end_date, "20050213") self.assertEqual(len(converter.txns_by_date.keys()), 4) - + def test_default_currency(self): qiftext = textwrap.dedent('''\ !Type:Bank @@ -204,7 +204,7 @@ def test_default_currency(self): converter = ofxtools.QifConverter(qiftext) ofx102 = converter.to_ofx102() self.assertTrue(ofx102.find('USD') != -1) - + def test_found_currency(self): qiftext = textwrap.dedent('''\ !Type:Bank @@ -215,7 +215,7 @@ def test_found_currency(self): converter = ofxtools.QifConverter(qiftext) ofx102 = converter.to_ofx102() self.assertTrue(ofx102.find('EUR') != -1) - + def test_explicit_currency(self): qiftext = textwrap.dedent('''\ !Type:Bank @@ -226,7 +226,7 @@ def test_explicit_currency(self): converter = ofxtools.QifConverter(qiftext, curdef='GBP') ofx102 = converter.to_ofx102() self.assertTrue(ofx102.find('GBP') != -1) - + def test_amount2(self): qiftext = textwrap.dedent('''\ !Type:Bank @@ -237,7 +237,7 @@ def test_amount2(self): converter = ofxtools.QifConverter(qiftext) txn = converter.txns_by_date["20050201"][0] self.assertEqual(txn["Amount"], "25.42") - + def test_bad_amount_precision(self): qiftext = textwrap.dedent('''\ !Type:Bank @@ -248,7 +248,7 @@ def test_bad_amount_precision(self): converter = ofxtools.QifConverter(qiftext) txn = converter.txns_by_date["20070125"][0] self.assertEqual(txn["Amount"], "417.93") - + def test_dash_amount(self): qiftext = textwrap.dedent('''\ !Type:Bank @@ -275,7 +275,7 @@ def test_trailing_minus(self): converter = ofxtools.QifConverter(qiftext) txn = converter.txns_by_date["20080806"][0] self.assertEqual(txn["Amount"], "-26.24") - + def test_n_a_number(self): qiftext = textwrap.dedent('''\ !Type:Bank @@ -287,7 +287,7 @@ def test_n_a_number(self): converter = ofxtools.QifConverter(qiftext) txn = converter.txns_by_date["20070125"][0] self.assertEqual(txn.has_key("Number"), False) - + def test_creditcard_number(self): qiftext = textwrap.dedent('''\ !Type:Bank @@ -299,7 +299,7 @@ def test_creditcard_number(self): converter = ofxtools.QifConverter(qiftext) txn = converter.txns_by_date["20070125"][0] self.assertEqual(txn.has_key("Number"), False) - + def test_creditcard_stmt_number(self): qiftext = textwrap.dedent('''\ !Type:CCard @@ -311,7 +311,7 @@ def test_creditcard_stmt_number(self): converter = ofxtools.QifConverter(qiftext) txn = converter.txns_by_date["20070125"][0] self.assertEqual(txn.has_key("Number"), False) - + def test_check_stmt_number(self): qiftext = textwrap.dedent('''\ !Type:Bank @@ -323,7 +323,7 @@ def test_check_stmt_number(self): converter = ofxtools.QifConverter(qiftext) txn = converter.txns_by_date["20070125"][0] self.assertEqual(txn.get("Type"), "CHECK") - + def test_usaa_check(self): qiftext = textwrap.dedent('''\ !Type:Bank From ad9df33ba926108a09faa6d00c6956a0f6d0dd3d Mon Sep 17 00:00:00 2001 From: Tal Wrii Date: Sun, 31 Jan 2016 16:25:47 +0000 Subject: [PATCH 2/2] Deal with different currency signs In transaction amount --- lib/ofxtools/qif_converter.py | 16 ++++++++++++++-- test/ofxtools_qif_converter.py | 28 +++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/lib/ofxtools/qif_converter.py b/lib/ofxtools/qif_converter.py index 9cc500f..cac7c2b 100644 --- a/lib/ofxtools/qif_converter.py +++ b/lib/ofxtools/qif_converter.py @@ -318,8 +318,20 @@ def _clean_txn_amount(self, txn): # Okay, now strip out whitespace padding. txn_amount = txn_amount.strip() - # Some QIF files have dollar signs in the amount. Hey, why not? - txn_amount = txn_amount.replace('$', '', 1) + # Some QIF files have dollar signs in the amount + # Some QIF files have sterling signs in the amount (in latin1 encoding :/ ) + # Let's assume this is going to be true in lots of places + for currency_sign in ( + '$', # USD and other currencies in + # most places and most encodings + '\xa3', # GBP latin1 + '\xc2\xa3', # GBP utf-8 + '\xe2\x82\xac', # Euro utf8 + '\xc2\xa5', # Yuan utf8 + '\x810\x846', # Yuan Guobiao + '\xa2D', # Yuan Big5 + ): + txn_amount = txn_amount.replace(currency_sign, '', 1) # Some QIF files (usually from non-US banks) put the minus sign at # the end of the amount, rather than at the beginning. Let's fix that. diff --git a/test/ofxtools_qif_converter.py b/test/ofxtools_qif_converter.py index e67ec65..8f0fd45 100644 --- a/test/ofxtools_qif_converter.py +++ b/test/ofxtools_qif_converter.py @@ -264,7 +264,33 @@ def test_dash_amount(self): self.assertEqual(len(txn_list), 1) txn = txn_list[0] self.assertEqual(txn["Amount"], "25.42") - + + def test_dollar_amount(self): + qiftext = textwrap.dedent('''\ + !Type:Bank + D02/01/2005 + T$26.42 + ^ + ''') + converter = ofxtools.QifConverter(qiftext) + txn_list = converter.txns_by_date["20050201"] + self.assertEqual(len(txn_list), 1) + txn = txn_list[0] + self.assertEqual(txn["Amount"], "26.42") + + def test_pound_amount(self): + qiftext = textwrap.dedent('''\ + !Type:Bank + D02/01/2005 + T-\xa326.42 + ^ + ''') + converter = ofxtools.QifConverter(qiftext) + txn_list = converter.txns_by_date["20050201"] + self.assertEqual(len(txn_list), 1) + txn = txn_list[0] + self.assertEqual(txn["Amount"], "-26.42") + def test_trailing_minus(self): qiftext = textwrap.dedent('''\ !Type:Bank