From: Christian Heller Date: Mon, 20 Jan 2025 21:47:01 +0000 (+0100) Subject: Extend BookingLine validations, differentiate class into two cases. X-Git-Url: https://plomlompom.com/repos/%7B%7B%20web_path%20%7D%7D/static/%7B%7Bprefix%7D%7D/edit?a=commitdiff_plain;h=3dfdc1f581aae00dadbdfa3262589a1760e73e1b;p=plomledger Extend BookingLine validations, differentiate class into two cases. --- diff --git a/ledger.py b/ledger.py index 8c2d48b..6085397 100755 --- a/ledger.py +++ b/ledger.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 """Viewer for ledger .dat files.""" -from decimal import Decimal +from datetime import date as dt_date +from decimal import Decimal, InvalidOperation as DecimalInvalidOperation from os import environ from pathlib import Path from sys import exit as sys_exit @@ -27,7 +28,7 @@ class DatLine: @property def is_intro(self) -> bool: """Return if intro line of a Booking.""" - return self.booking_line.is_intro if self.booking_line else False + return isinstance(self.booking_line, IntroLine) @property def booking_id(self) -> int: @@ -55,15 +56,33 @@ class DatLine: class BookingLine: """Parsed code part of a DatLine belonging to a Booking.""" - def __init__(self, booking_id: int, code: str, as_intro: bool = False - ) -> None: + def __init__(self, booking_id: int) -> None: self.error = '' self.booking_id = booking_id - self.is_intro = as_intro - if self.is_intro: - if code[0].isspace(): - self.error = 'intro line indented' + + +class IntroLine(BookingLine): + """First line of a Booking, expected to carry date etc.""" + + def __init__(self, booking_id: int, code: str) -> None: + super().__init__(booking_id) + if code[0].isspace(): + self.error = 'intro line indented' + toks = code.lstrip().split(maxsplit=1) + if len(toks) != 2: + self.error = 'illegal number of tokens' return + try: + dt_date.fromisoformat(toks[0]) + except ValueError: + self.error = 'not starting with properly formatted legal date' + + +class TransactionLine(BookingLine): + """Non-first Booking line, expected to carry value movement.""" + + def __init__(self, booking_id: int, code: str) -> None: + super().__init__(booking_id) self.acc, self.amt, self.curr = '', '', '' if not code[0].isspace(): self.error = 'non-intro line not indented' @@ -74,7 +93,11 @@ class BookingLine: self.error = 'illegal number of tokens' return if 3 == len(toks): - amt_dec = Decimal(toks[1]) + try: + amt_dec = Decimal(toks[1]) + except DecimalInvalidOperation: + self.error = 'improper amount value' + return exp = amt_dec.as_tuple().exponent assert isinstance(exp, int) self.amt = (f'{amt_dec:.1f}…' if exp < -2 @@ -89,10 +112,10 @@ class Booking: def __init__(self, id_: int, dat_lines: list[DatLine]) -> None: self.id_ = id_ self.dat_lines = dat_lines - self.dat_lines[0].booking_line = BookingLine( - self.id_, self.dat_lines[0].code, as_intro=True) + self.dat_lines[0].booking_line = IntroLine(self.id_, + self.dat_lines[0].code) for dat_line in self.dat_lines[1:]: - dat_line.booking_line = BookingLine(self.id_, dat_line.code) + dat_line.booking_line = TransactionLine(self.id_, dat_line.code) class Handler(PlomHttpHandler):