Multiple fixes on the addition of new raw files

The initialize function has been updated with a new possible option for
a new raw file, where the Last Accessed date changed the content hadn't.
Also removes sort() when using extend() on a list as it doesn't work
correctly.
Categorization code moved to if False statement to add posterior toggle
behaviour.
New transaction print added (.desc()) which prints the description of a
transaction instead of its category to help on the manual
categorization.
Raw files now on raw dir instead of .raw
It now also accepts empty lines and # at the start for comments on data
files. TODO these are overwritten whenever the data files are updated.
This commit is contained in:
Luís Murta 2020-09-09 21:09:51 +01:00
parent ad9bc4a7c4
commit 806bf258e4
Signed by: satprog
GPG Key ID: DDF2EFC6179009DC
3 changed files with 31 additions and 17 deletions

View File

@ -52,7 +52,7 @@ class Categories:
and transaction.category != Travel().name and transaction.category != Travel().name
): ):
new_category = input( new_category = input(
f"{transaction} already has a {transaction.category} assigned. Would you like " f"{transaction.desc()} already has a {transaction.category} assigned. Would you like "
f"to change it to {category.name}? (Y/N) " f"to change it to {category.name}? (Y/N) "
) )
correct_answer = False correct_answer = False

37
main.py
View File

@ -40,11 +40,14 @@ def initialize(raw_dir, data_dir, restart=False):
logging.debug("no .raw.pickle found") logging.debug("no .raw.pickle found")
updated_trs, update = dict(), False updated_trs, update = dict(), False
prompt = " has been modified since last update. Do you want to update the data files? (Yes/No)" prompt = " has been modified since last update. Do you want to update the data files? (Yes/Update/No)"
for rf in Path(raw_dir).iterdir(): for rf in Path(raw_dir).iterdir():
if rf.name in rfs and rfs[rf.name][0] == rf.stat().st_mtime: if rf.name in rfs and rfs[rf.name][0] == rf.stat().st_mtime:
logging.debug(f"{rf.name} hasn't been modified since last access") logging.debug(f"{rf.name} hasn't been modified since last access")
elif rf.name not in rfs or input(f"{rf.name}" + prompt).lower() == "yes": elif (
rf.name not in rfs
or (answer := input(f"{rf.name}" + prompt).lower()) == "yes"
):
trs = Parser.parse_csv(rf) trs = Parser.parse_csv(rf)
updated_trs[rf.name] = trs updated_trs[rf.name] = trs
try: try:
@ -53,6 +56,11 @@ def initialize(raw_dir, data_dir, restart=False):
rfs[rf.name] = [rf.stat().st_mtime, []] rfs[rf.name] = [rf.stat().st_mtime, []]
update = True update = True
logging.info(f"{rf.name} parsed") logging.info(f"{rf.name} parsed")
elif answer == "update":
rfs[rf.name][0] = rf.stat().st_mtime
update = True
else: # prompt = no
update = True
if update: if update:
for rf_name, updated_trs in updated_trs.items(): for rf_name, updated_trs in updated_trs.items():
@ -66,7 +74,8 @@ def initialize(raw_dir, data_dir, restart=False):
rem_trs = [tr for tr in rfs[rf_name][1] if tr not in trs] rem_trs = [tr for tr in rfs[rf_name][1] if tr not in trs]
if new_trs: if new_trs:
dfs[filename].extend(new_trs).sort() dfs[filename].extend(new_trs)
dfs[filename].sort()
for rem in rem_trs: for rem in rem_trs:
dfs[filename].remove(rem) dfs[filename].remove(rem)
@ -95,7 +104,7 @@ def manual_categorization(trs):
trs.sort_by_bank() trs.sort_by_bank()
for i, transaction in enumerate(trs): for i, transaction in enumerate(trs):
if not transaction.category: if not transaction.category:
category = input(f"{transaction} category: ") category = input(f"{transaction.desc()} category: ")
if category == "stop": if category == "stop":
break break
if category: if category:
@ -106,9 +115,9 @@ def manual_categorization(trs):
if __name__ == "__main__": if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG) # logging.basicConfig(level=logging.DEBUG)
datafiles = initialize(".raw", "data", restart=False) datafiles = initialize("raw", "data", restart=False)
transactions = Transactions() transactions = Transactions()
for file in datafiles.values(): for file in datafiles.values():
@ -121,14 +130,14 @@ if __name__ == "__main__":
# if transaction.category in reprocess: # if transaction.category in reprocess:
# transaction.category = '' # transaction.category = ''
# Categories.categorize(transactions) if False:
# Categories.categorize(transactions)
# manual_categorization(transactions) manual_categorization(transactions)
#
# for f, file in datafiles.items(): for f, file in datafiles.items():
# file_transactions = [t for t in transactions if t in file] file_transactions = [t for t in transactions if t in file]
# Tr.write_transactions(Path("data") / f, file_transactions) Tr.write_transactions(Path("data") / f, file_transactions)
#
Tr.write_transactions("transactions.csv", transactions) Tr.write_transactions("transactions.csv", transactions)
monthly_transactions = transactions.get_transactions_by_month( monthly_transactions = transactions.get_transactions_by_month(

View File

@ -37,7 +37,7 @@ class Transaction:
def read_transactions(file, encoding="utf-8"): def read_transactions(file, encoding="utf-8"):
with open(file, newline="", encoding=encoding) as f: with open(file, newline="", encoding=encoding) as f:
r = reader(f, delimiter="\t") r = reader(f, delimiter="\t")
transactions = [Transaction(row) for row in r] transactions = [Transaction(row) for row in r if row and row[0][0] != "#"]
return transactions return transactions
@staticmethod @staticmethod
@ -89,6 +89,11 @@ class Transaction:
def __ge__(self, other): def __ge__(self, other):
return self.date >= other.date return self.date >= other.date
def desc(self):
return "{} {} {}€ ({})".format(
self.date.strftime("%d/%m/%y"), self.description, self.value, self.bank
)
def __repr__(self): def __repr__(self):
return "{} {} {}€ ({})".format( return "{} {} {}€ ({})".format(
self.date.strftime("%d/%m/%y"), self.category, self.value, self.bank self.date.strftime("%d/%m/%y"), self.category, self.value, self.bank