aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrián Oliva <adrian.oliva@cimat.mx>2023-05-04 22:32:32 -0600
committerAdrián Oliva <adrian.oliva@cimat.mx>2023-05-04 22:32:32 -0600
commit293212c60ed3744f6613f23fea058f8ba73a6f62 (patch)
tree80b0fe14a11daa8d2a39bca1c04ba71da3830634
parent93320ee7fdfc79695f0fddc66d7933121133fb3c (diff)
downloadLedger.py-293212c60ed3744f6613f23fea058f8ba73a6f62.tar.gz
Ledger.py-293212c60ed3744f6613f23fea058f8ba73a6f62.zip
First attempt at storing ledger entries.
Now we can store the entries in very simple ways and we can even print them!
Diffstat (limited to '')
-rwxr-xr-xledger.py9
-rw-r--r--utils/read_file.py119
2 files changed, 127 insertions, 1 deletions
diff --git a/ledger.py b/ledger.py
index 61eb6a5..a224591 100755
--- a/ledger.py
+++ b/ledger.py
@@ -1,11 +1,18 @@
#!/usr/bin/env python3
from utils.args import get_arguments, test_args
+from utils.read_file import read_ledger
def main():
args = get_arguments()
test_args(args)
- print(args)
+ if args.files:
+ for file in args.files:
+ result = read_ledger(file)
+
+ if args.verb == 'print':
+ for ent in result:
+ print(ent)
if __name__ == '__main__':
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