changeset 9:28548158a325 default tip

Some minor improvements/fixes This will eventually evolve to something more generic, since I have re-used the same design, and some of the parts here, to write a plugin for Charles Schwab.
author Louis Opter <louis@opter.org>
date Thu, 09 Mar 2017 22:55:02 -0800
parents 164da24a2997
children
files .hgignore README.rst setup.py src/ofxstatement/plugins/us_hsbc/plugin.py
diffstat 4 files changed, 32 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Thu Dec 01 17:14:11 2016 -0800
+++ b/.hgignore	Thu Mar 09 22:55:02 2017 -0800
@@ -2,3 +2,4 @@
 .*\.py[co]$
 .*\.egg-info$
 .*\.ofx$
+Session.vim$
--- a/README.rst	Thu Dec 01 17:14:11 2016 -0800
+++ b/README.rst	Thu Mar 09 22:55:02 2017 -0800
@@ -3,7 +3,8 @@
 
 This only supports the ``ExportData.csv`` file you can download from the "money
 management" tool found within their online banking interface (`accessible
-here`_).
+here`_). Note that access to this tool requires an advanced or premier account
+with HSBC.
 
 ofxstatement can only process one account at a time, so make sure you export
 each account separately into different files.
--- a/setup.py	Thu Dec 01 17:14:11 2016 -0800
+++ b/setup.py	Thu Mar 09 22:55:02 2017 -0800
@@ -27,7 +27,7 @@
     version=version,
     author="Louis Opter",
     author_email="louis@opter.org",
-    url="https://github.com/lopter/ofxstatement",
+    url="https://github.com/lopter/ofxstatement-us-hsbc",
     description=("HSBC (USA) plugin for ofxstatement"),
     long_description=long_description,
     license="GPLv3",
@@ -57,6 +57,7 @@
         "dev": [
             "flake8",
             "mypy-lang",
+            "typed-ast",
             "ipython",
             "pdbpp",
             "pep8",
--- a/src/ofxstatement/plugins/us_hsbc/plugin.py	Thu Dec 01 17:14:11 2016 -0800
+++ b/src/ofxstatement/plugins/us_hsbc/plugin.py	Thu Mar 09 22:55:02 2017 -0800
@@ -18,7 +18,6 @@
 import contextlib
 import csv
 import datetime
-import enum
 import locale
 import logging
 import pdb
@@ -28,7 +27,7 @@
 from ofxstatement.parser import CsvStatementParser
 from ofxstatement.plugin import Plugin
 from ofxstatement.statement import StatementLine, generate_transaction_id
-from typing import Any, Dict, Iterable, List
+from typing import Dict, Generator, Iterable, List
 from typing.io import TextIO
 
 from .record import CsvIndexes, Record
@@ -39,13 +38,31 @@
 
 
 @contextlib.contextmanager
-def _override_locale(category, value):
+def _override_locale(category: int, value: str) -> Generator[None, None, None]:
     save = locale.getlocale(category)
     locale.setlocale(category, value)
     yield
     locale.setlocale(category, save)
 
 
+class _spawn_debugger_on_exception:
+
+    def __init__(self, errmsg: str) -> None:
+        self._errmsg = errmsg
+
+    def __enter__(self) -> None:
+        pass
+
+    def __exit__(self, exc_type, exc_value, exc_tb) -> bool:
+        if exc_value is not None:
+            logger.exception(self._errmsg)
+            logger.info("Press {} to exit the debugger".format(
+                "^Z" if sys.platform.startswith("win32") else "^D"
+            ))
+            pdb.post_mortem()
+            sys.exit(1)
+
+
 class Parser(CsvStatementParser):
 
     date_format = "%m/%d/%Y"
@@ -65,6 +82,7 @@
         "CASH CONCENTRATION VENMO": "XFER",
         "DEPOSIT FROM": "DIRECTDEP",
         "DEPOSIT": "DEP",
+        "HSBC SECURITIES": "XFER",
         "INTEREST EARNED AND PAID": "INT",
         "ONLINE PAYMENT TO": "PAYMENT",
         "PAY TO": "PAYMENT",
@@ -106,7 +124,7 @@
             logger.info("Skipping row: {}".format(row))
             return None  # skip (all) the csv headers
 
-        try:
+        with _spawn_debugger_on_exception("Parsing failed:"):
             sl = super(Parser, self).parse_record(row)
             record = Record(row)
 
@@ -123,13 +141,6 @@
 
             self.statement.start_date = min(sl.date, self.statement.start_date)
             self.statement.end_date = max(sl.date, self.statement.end_date)
-        except Exception:
-            logger.exception("Parsing failed:")
-            logger.info("Press {} to exit the debugger".format(
-                "^Z" if sys.platform.startswith("win32") else "^D"
-            ))
-            pdb.post_mortem()
-            sys.exit(1)
 
         return sl
 
@@ -148,9 +159,9 @@
         # XXX: how does this gets closed?
         fin = open(filename, "r", encoding=encoding)
 
-        parser = Parser(fin)
-        parser.statement.bank_id = self.settings.get("routing_number")
-        parser.statement.account_id = self.settings.get("account_number")
-        parser.statement.account_type = self.settings.get("account_type", "CHECKING")
+        p = Parser(fin)
+        p.statement.bank_id = self.settings.get("routing_number")
+        p.statement.account_id = self.settings.get("account_number")
+        p.statement.account_type = self.settings.get("account_type", "CHECKING")
 
-        return parser
+        return p