aboutsummaryrefslogtreecommitdiff
path: root/utils/read_file.py
diff options
context:
space:
mode:
Diffstat (limited to 'utils/read_file.py')
-rw-r--r--utils/read_file.py119
1 files changed, 119 insertions, 0 deletions
diff --git a/utils/read_file.py b/utils/read_file.py
new file mode 100644
index 0000000..1906fc7
--- /dev/null
+++ b/utils/read_file.py
@@ -0,0 +1,119 @@
+from datetime import date, datetime
+import re
+import os
+
+
+VALID_DATES_FORMAT = r'\d{4}[-./]\d{1,2}[-./]\d{1,2}'
+VALID_DATES_SEP = '[-./]'
+
+
+class entry:
+ def __init__(self, date: str, comment: str, transactions: list) -> None:
+ self.date = self.__date_from_str(date)
+ self.comment = comment
+ self.transactions = transactions
+
+
+ def __date_from_str(self, date_str: str):
+ """
+ Searches for a valid date on a string and transforms it into ISO
+ format. (YYYY-MM-DD)
+ """
+ my_date = re.findall(VALID_DATES_FORMAT, date_str)[0]
+ year, month, day = re.split(VALID_DATES_SEP, my_date)
+
+ return datetime.fromisoformat(f'{int(year)}-{int(month):02}-{int(day):02}')
+
+
+ def __str__(self) -> str:
+ result = self.date.strftime('%Y/%m/%d')
+ result += " " + self.comment + "\n"
+
+ for trans in self.transactions:
+ if len(trans) == 2:
+ # TODO: `price` must have a specific format!
+ account, price = trans
+ else:
+ account = trans[0]
+ price = ""
+
+ result += f" {account:<35} {price:>12}\n"
+
+ return result
+
+
+def give_me_file_contents(path: str):
+ line_comments = ";#%|*"
+ try:
+ with open(path, 'r', encoding='utf8') as fp:
+ result = fp.readlines()
+
+ for line in result:
+ # If line is just empty spaces or empty, ignore it.
+ if len(line.lstrip()) == 0:
+ continue
+
+ # If first character of line is a line comment, ignore it.
+ first_char = line.lstrip()[0]
+ if first_char in line_comments:
+ continue
+
+ yield line.strip()
+
+ except:
+ raise Exception(f"Error while trying to read {path} file.")
+
+
+def is_new_entry(line: str):
+ """
+ Returns `True` if the line contains at least one valid date. This means
+ we're looking at a new transaction.
+ """
+ return re.search(VALID_DATES_FORMAT, line) is not None
+
+
+def read_ledger(path: str):
+ files_to_read = [path]
+ date = None
+ comment = None
+ transactions = None
+
+ results = []
+
+ while files_to_read:
+ current_file = files_to_read.pop()
+
+ for line in give_me_file_contents(current_file):
+ if line.startswith('!include'):
+ file_path = line.split()[-1]
+ base_dir = os.path.dirname(current_file)
+ files_to_read.append(
+ os.path.join(base_dir, file_path)
+ )
+
+ continue
+
+ if is_new_entry(line) and date is not None:
+ results.append(
+ entry(date, comment, transactions)
+ )
+
+ if is_new_entry(line):
+ date, comment = line.split(maxsplit=1)
+ transactions = []
+ else:
+ # The line is a new transaction
+ tabs_to_spaces = line.replace('\t', ' ')
+ transactions.append(
+ re.split(r'\s{2,}', tabs_to_spaces)
+ )
+
+ if date is not None:
+ results.append(
+ entry(date, comment, transactions)
+ )
+ date = None
+ comment = None
+ transactions = None
+
+ return results