Skip to content

Commit

Permalink
;examples: csv: add an example python converter script
Browse files Browse the repository at this point in the history
  • Loading branch information
simonmichael committed Oct 10, 2024
1 parent a6542e6 commit 7a88130
Showing 1 changed file with 87 additions and 0 deletions.
87 changes: 87 additions & 0 deletions examples/csv/csv-hledger-1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#!/usr/bin/env python3
# An example of using Python to convert a certain CSV to hledger journal entries.
# This won't work as-is (unless you have this particular kind of CSV);
# use it for inspiration. hledger's own CSV rules are not used at all here.


__version__ = "1.0"
__author__ = "Simon Michael"

VERSION = "%prog " + __version__
USAGE = """%prog [options] [CSVFILE [JOURNALFILE]]
Reads a [certain kind of] CSV, writes a hledger journal.
Journal entries will be in the same order as the CSV records.
Requirements: python 3.
"""

# from pprint import pprint as pp
import csv
import datetime
import optparse
import re
import subprocess
import sys
import tempfile
# import warnings

def parse_options():
parser = optparse.OptionParser(usage=USAGE, version=VERSION)
opts, args = parser.parse_args()
if len(args) > 2:
parser.print_help()
sys.exit()
return opts, args

def single_space(ms):
if ms is not None: ms = re.sub(r' +',' ',ms)
return ms

# Join two strings with the give separator, but omit the separator
# if either string is empty.
def intercalate2(sep,astr,bstr):
if astr and bstr:
return astr + sep + bstr
else:
return astr + bstr

def main():
opts, args = parse_options()
out = open(args[1],'w') if len(args) > 1 else sys.stdout
with open(args[0],'r') if len(args) > 0 else sys.stdin as csvfile:

# Process CSV records, and generate a hledger journal entry for each transaction.

for r in csv.reader(csvfile):

# skip headings (record containing no numbers)
if all(map(lambda v: not any(c.isdigit() for c in v), r)): continue

# hledger doesn't like records with only one field
if len(r) < 2: continue

# skip non-transaction records
if re.match(r'^(Starting Balance|Net Change|Total|)$',r[0]): continue

# write a hledger journal entry
property_,date_,payee_payer_,type_,reference_,debit_,credit_,balance_,description_,gl_account_ = r
date = datetime.datetime.strptime(date_,"%m/%d/%Y").date().isoformat()
code = f" ({reference_})" if reference_ else ""
description = intercalate2(' | ', payee_payer_, intercalate2(' ', description_, type_))
amount1 = f"${debit_}" if debit_ else ""
amount2 = f"${credit_}" if credit_ else ""
balance1 = balance_
account1 = f"Properties:{property_}"
if gl_account_[0].isdigit():
account2 = f"{gl_account_[0]}xxx:{gl_account_}"
else:
account2 = f"{gl_account_}"
account1, account2 = single_space(account1), single_space(account2)
out.write(f"""\
{date}{code} {description}
{account1} {amount1} ; = {balance1}
{account2} {amount2}
""")

if __name__ == "__main__": main()

0 comments on commit 7a88130

Please sign in to comment.