'Actual ledger classes.'
# standard libs
-from abc import ABC
+from abc import ABC, abstractmethod
from datetime import date as dt_date
from decimal import Decimal, InvalidOperation as DecimalInvalidOperation
from pathlib import Path
-from typing import Any, Generic, Iterator, Optional, Self, TypeVar
-
-
-_TypeDatLine = TypeVar('_TypeDatLine', bound='_DatLine')
+from typing import Any, Iterator, Optional, Self
_INDENT_CHARS = {' ', '\t'}
for idx in range(maxsplit))
@property
+ @abstractmethod
def errors(self) -> tuple[str, ...]:
'Whatever is wrong with the respective line.'
- return tuple(f'{name} empty' for name in self._field_names
- if not getattr(self, name))
class _IntroLine(_BookingLine):
@property
def errors(self) -> tuple[str, ...]:
- errors = list(super().errors)
+ errors = [f'{name} empty' for name in self._field_names
+ if not getattr(self, name)]
if self.indent:
errors += ['intro line indented']
try:
@property
def errors(self) -> tuple[str, ...]:
- errors = list(super().errors)
+ errors = []
# if not self.indent:
# errors += ['transfer line not indented']
+ if not self.account:
+ errors += ['account missing']
if isinstance(self.amount, str):
errors += [f'improper amount value: {self.amount}']
if len(self.currency.split()) > 1:
return ''
-class _LinesBlock(Generic[_TypeDatLine]):
- _lines: list[_TypeDatLine]
+class _LinesBlock:
+ _lines: list[_DatLine]
def __init__(self) -> None:
self._lines = []
@property
- def lines(self) -> tuple[_TypeDatLine, ...]:
+ def lines(self) -> tuple[_DatLine, ...]:
'Return collected lines.'
return tuple(self._lines)
- def add(self, lines: tuple[_TypeDatLine, ...], at_end=True) -> None:
+ def add(self, lines: tuple[_DatLine, ...], at_end=True) -> None:
'Grow block downwards by this one DatLine.'
if at_end:
self._lines += lines
self._lines[0:0] = list(lines)
-class _Booking(_LinesBlock[_BookingLine]):
+class _Booking(_LinesBlock):
@property
def _sink_account(self) -> str:
return self.intro_line.target
-class _DatBlock(_LinesBlock[_DatLine]):
+class _DatBlock(_LinesBlock):
'Unit of lines with optional .booking, and (possibly zero) .gap_lines.'
_prev: Optional[Self] = None
_next: Optional[Self] = None
@property
def booking(self) -> Optional[_Booking]:
'Booking made from lines indented or with code.'
- booking_lines = tuple(_BookingLine(line.raw) for line in self.lines
+ booking_lines = tuple(_DatLine(line.raw) for line in self.lines
if line.indent or line.code)
if not booking_lines:
return None