summary history files

web/penny/common/filetypes.py
import csv
from io import StringIO
from ofxparse import OfxParser
from ofxparse.ofxparse import OfxParserException
from bs4 import BeautifulSoup
import tempfile
import os


class FileTypesError(Exception):
    pass


def is_csv(csv_file):
    with open(csv_file, "r") as fh:
        data = csv.DictReader(fh)
    for row in data:
        field_names = ["date", "memo", "debit", "credit"]
        for field in row:
            if field.strip() not in field_names:
                raise FileTypesError(
                    "unknown csv field; field={}".format(field.strip())
                )
            else:
                field_names.remove(field.strip())
    if len(field_names) >= 1:
        missing = "".join("field=%s" % "".join(f) for f in field_names)
        raise FileTypesError("missing csv field; {}".format(missing))
    else:
        return True


def is_ofx(ofx_file):
    ofx = None

    with open(ofx_file, "r") as fh:
        try:
            ofx = OfxParser.parse(fh, fail_fast=False)
        except (OfxParserException, TypeError):
            raise FileTypesError("failed to import ofx file")

    if ofx is None:
        raise FileTypesError("unable to read ofx file")
    elif not hasattr(ofx, "account"):
        raise FileTypesError("unable to read ofx file")
    else:
        return True


def ofx2bs4(ofx_file):
    """Run ofx through bs4 and save to a tmp file."""
    tmpfile = tempfile.mkstemp()
    soup = BeautifulSoup(open(ofx_file), "html.parser")
    with open(tmpfile[1], "wb") as fh:
        fh.write(soup.prettify("utf-8"))
    return tmpfile


def get_bankaccount_number_from_ofx(ofx_file):
    "Return the bankaccount number from an OFX file."
    _ofx = ofx2bs4(ofx_file)
    with open(_ofx[1]) as fh:
        ofx = OfxParser.parse(fh, fail_fast=False)
    os.unlink(_ofx[1])
    return "{}{}".format(ofx.account.routing_number, ofx.account.number)