Welcome, guest | Sign In | My Account | Store | Cart

A simple class to represent a Quicken (QIF) file, and a parser to load a QIF file into a sequence of those classes.

It's enough to be useful for writing conversions.

Python, 102 lines
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
#!/usr/bin/python
"""
A simple class to represent a Quicken (QIF) file, and a parser to
load a QIF file into a sequence of those classes.

It's enough to be useful for writing conversions.
"""

import sys
 
class QifItem:
    def __init__(self):
        self.order = ['date', 'amount', 'cleared', 'num', 'payee', 'memo', 'address', 'category', 'categoryInSplit', 'memoInSplit', 'amountOfSplit']
        self.date = None
        self.amount = None
        self.cleared = None
        self.num = None
        self.payee = None
        self.memo = None
        self.address = None
        self.category = None
        self.categoryInSplit = None
        self.memoInSplit = None
        self.amountOfSplit = None

    def show(self):
        pass
    
    def __repr__(self):
        titles = ','.join(self.order)
        tmpstring = ','.join( [str(self.__dict__[field]) for field in self.order] )
        tmpstring = tmpstring.replace('None', '')
        return titles + "," + tmpstring

    def dataString(self):
        """
        Returns the data of this QIF without a header row
        """
        tmpstring = ','.join( [str(self.__dict__[field]) for field in self.order] )
        tmpstring = tmpstring.replace('None', '')
        return tmpstring
    
def parseQif(infile):
    """
    Parse a qif file and return a list of entries.
    infile should be open file-like object (supporting readline() ).
    """

    inItem = False

    items = []
    curItem = QifItem()
    line = infile.readline()
    while line != '':
        if line[0] == '\n': # blank line
            pass
        elif line[0] == '^': # end of item
            # save the item
            items.append(curItem)
            curItem = QifItem()
        elif line[0] == 'D':
            curItem.date = line[1:-1]
        elif line[0] == 'T':
            curItem.amount = line[1:-1]
        elif line[0] == 'C':
            curItem.cleared = line[1:-1]
        elif line[0] == 'P':
            curItem.payee = line[1:-1]
        elif line[0] == 'M':
            curItem.memo = line[1:-1]
        elif line[0] == 'A':
            curItem.address = line[1:-1]
        elif line[0] == 'L':
            curItem.category = line[1:-1]
        elif line[0] == 'S':
            try:
                curItem.categoryInSplit.append(";" + line[1:-1])
            except AttributeError:
                curItem.categoryInSplit = line[1:-1]
        elif line[0] == 'E':
            try:
                curItem.memoInSplit.append(";" + line[1:-1])
            except AttributeError:
                curItem.memoInSplit = line[1:-1]
        elif line[0] == '$':
            try:
                curItem.amountInSplit.append(";" + line[1:-1])
            except AttributeError:
                curItem.amountInSplit = line[1:-1]
        else:
            # don't recognise this line; ignore it
            print >> sys.stderr, "Skipping unknown line:\n", line

        line = infile.readline()
    return items

if __name__ == "__main__":
    # read from stdin and write CSV to stdout
    items = parseQif(sys.stdin)
    print repr(items[0])
    for item in items[1:]:
        print item.dataString()

Financial institutions don't provide customers' data in particularly useful formats, so this module contains a representation of the QIF file item, a parser to load a QIF file, and an example qif2csv program.

3 comments

Brian G (author) 19 years, 6 months ago  # | flag

format spec. This is based upon the format spec:

http://www.respmech.com/mym2qifw/qif_new.htm

William (Bill) Trenker 19 years, 2 months ago  # | flag

Thanks and a possible change. First, thanks Brian for this. Google found it for me just like that.

Also, in the __repr__ method don't titles and tmpstring need to be joined by a newline, not a comma? Something like:

return titles + "\n" + tmpstring  #changed "," to "\n"

Cheers, Bill

Randall W 17 years, 2 months ago  # | flag

Small Issue with splits. I found I had to change 'AttributeError' to 'TypeError' to get the split parsing to work properly eg

try
   curItem.categoryInSplit.append(";" + line[1:-1])
except TypeError:
   curItem.categoryInSplit = line[1:-1]
<pre>

</pre>

Created by Brian G on Mon, 27 Sep 2004 (PSF)
Python recipes (4591)
Brian G's recipes (1)

Required Modules

Other Information and Tasks