home · contact · privacy
Minor refactoring. master
authorChristian Heller <c.heller@plomlompom.de>
Sun, 2 Feb 2025 20:34:00 +0000 (21:34 +0100)
committerChristian Heller <c.heller@plomlompom.de>
Sun, 2 Feb 2025 20:34:00 +0000 (21:34 +0100)
ledger.py

index dcf1c4da5b130ccecefec69246bc7b6d3bb70cdf..fb2abcfa2ccd1701d99da09933bacb57cd5343b6 100755 (executable)
--- a/ledger.py
+++ b/ledger.py
@@ -1,5 +1,6 @@
 #!/usr/bin/env python3
 """Viewer for ledger .dat files."""
+from abc import ABC, abstractmethod
 from datetime import date as dt_date
 from decimal import Decimal, InvalidOperation as DecimalInvalidOperation
 from os import environ
@@ -78,7 +79,16 @@ class Account:
         return total
 
 
-class DatLine:
+class Line(ABC):
+    """Line abstraction featuring .as_dict property."""
+
+    @property
+    @abstractmethod
+    def as_dict(self) -> dict:
+        """Return as JSON-ready dict."""
+
+
+class DatLine(Line):
     """Line of .dat file parsed into comments and machine-readable data."""
 
     def __init__(self, line: str) -> None:
@@ -90,8 +100,7 @@ class DatLine:
 
     @property
     def as_dict(self) -> dict:
-        """Return as JSON-ready dict."""
-        assert isinstance(self.booking_line, (IntroLine, TransferLine))
+        assert self.booking_line is not None
         return {'comment': self.comment, 'code': self.code,
                 'is_intro': self.is_intro, 'error': self.error,
                 'booking_line': self.booking_line.as_dict}
@@ -135,7 +144,7 @@ class DatLine:
         return self.raw.replace(' ', '&nbsp;')
 
 
-class BookingLine:
+class BookingLine(Line):
     """Parsed code part of a DatLine belonging to a Booking."""
 
     def __init__(self, booking: 'Booking') -> None:
@@ -163,7 +172,6 @@ class IntroLine(BookingLine):
 
     @property
     def as_dict(self) -> dict:
-        """Return as JSON-ready dict."""
         return {'date': self.date, 'target': self.target}
 
 
@@ -199,7 +207,6 @@ class TransferLine(BookingLine):
 
     @property
     def as_dict(self) -> dict:
-        """Return as JSON-ready dict."""
         return {'account': self.account, 'currency': self.currency,
                 'amount': str(self.amount)}
 
@@ -409,23 +416,6 @@ class Server(PlomHttpServer):
             DatLine(line)
             for line in self._path_dat.read_text(encoding='utf8').splitlines()]
         self.last_save_hash = self._hash_dat_lines()
-        self._load_bookings()
-
-    def save(self) -> None:
-        """Save current state to ._path_dat."""
-        self._path_dat.write_text(
-            '\n'.join([line.raw for line in self.dat_lines]), encoding='utf8')
-        self.load()
-
-    def _hash_dat_lines(self) -> int:
-        return hash(tuple(dl.raw for dl in self.dat_lines))
-
-    @property
-    def tainted(self) -> bool:
-        """If .dat_lines different to those of last .load()."""
-        return self._hash_dat_lines() != self.last_save_hash
-
-    def _load_bookings(self) -> None:
         booked_lines: list[DatLine] = []
         gap_lines: list[DatLine] = []
         booking: Optional[Booking] = None
@@ -455,6 +445,20 @@ class Server(PlomHttpServer):
         if booking:
             booking.gap_lines = gap_lines[:-1]
 
+    def save(self) -> None:
+        """Save current state to ._path_dat."""
+        self._path_dat.write_text(
+            '\n'.join([line.raw for line in self.dat_lines]), encoding='utf8')
+        self.load()
+
+    def _hash_dat_lines(self) -> int:
+        return hash(tuple(dl.raw for dl in self.dat_lines))
+
+    @property
+    def tainted(self) -> bool:
+        """If .dat_lines different to those of last .load()."""
+        return self._hash_dat_lines() != self.last_save_hash
+
     def _recalc_dat_lines(self) -> None:
         self.dat_lines = self.initial_gap_lines[:]
         for booking in self.bookings: