@property
def error(self) -> str:
"""Return error if registered on attempt to parse into BookingLine."""
- return self.booking_line.error if self.booking_line else ''
+ return '; '.join(self.booking_line.errors) if self.booking_line else ''
@property
def questionable(self) -> bool:
"""Parsed code part of a DatLine belonging to a Booking."""
def __init__(self, booking: 'Booking') -> None:
- self.error = ''
+ self.errors: list[str] = []
self.booking = booking
def __init__(self, booking: 'Booking', code: str) -> None:
super().__init__(booking)
if code[0].isspace():
- self.error = 'intro line indented'
+ self.errors += ['intro line indented']
toks = code.lstrip().split(maxsplit=1)
if len(toks) != 2:
- self.error = 'illegal number of tokens'
+ self.errors += ['illegal number of tokens']
+ if len(toks) < 1:
return
try:
dt_date.fromisoformat(toks[0])
except ValueError:
- self.error = 'not starting with properly formatted legal date'
+ self.errors += [f'not properly formatted legal date: {toks[0]}']
class TransferLine(BookingLine):
def __init__(self, booking: 'Booking', code: str) -> None:
super().__init__(booking)
if not code[0].isspace():
- self.error = 'transfer line not indented'
- return
+ self.errors += ['transfer line not indented']
toks = code.lstrip().split()
self.account = toks[0]
self.amount: Optional[Decimal] = None
if 1 == len(toks):
self.currency = ''
- elif 3 == len(toks):
+ elif 3 <= len(toks):
self.currency = toks[2]
try:
self.amount = Decimal(toks[1])
except DecimalInvalidOperation:
- self.error = 'improper amount value'
- else:
- self.error = 'illegal number of tokens'
+ self.errors += [f'improper amount value: {toks[1]}']
+ if len(toks) not in {1, 3}:
+ self.errors += ['illegal number of tokens']
@property
def amount_short(self) -> str:
def __init__(self, id_: int, dat_lines: list[DatLine]) -> None:
self.id_ = id_
- self.dat_lines = dat_lines
- self.dat_lines[0].booking_line = IntroLine(self,
- self.dat_lines[0].code)
- for dat_line in self.dat_lines[1:]:
+ dat_lines[0].booking_line = IntroLine(self, dat_lines[0].code)
+ intro_line = dat_lines[0].booking_line
+ transfer_lines = []
+ for dat_line in dat_lines[1:]:
dat_line.booking_line = TransferLine(self, dat_line.code)
+ transfer_lines += [dat_line.booking_line]
self.account_changes: dict[str, Wealth] = {}
self.sink_account = None
changes = Wealth()
- for transfer_line in [dl.booking_line for dl in self.dat_lines[1:]]:
- assert isinstance(transfer_line, TransferLine)
+ for transfer_line in [tl for tl in transfer_lines if not tl.errors]:
if transfer_line.account not in self.account_changes:
self.account_changes[transfer_line.account] = Wealth()
if transfer_line.amount is None:
if self.sink_account:
- transfer_line.error = 'too many sinks'
- break
+ transfer_line.errors += ['too many sinks']
self.sink_account = transfer_line.account
continue
change = Wealth({transfer_line.currency: transfer_line.amount})
self.account_changes[transfer_line.account] += change
changes += change
- self.questionable = False
if self.sink_account:
self.account_changes[self.sink_account] += changes.as_sink
elif not changes.sink_empty:
- assert self.dat_lines[-1].booking_line is not None
- self.dat_lines[-1].booking_line.error = 'needed sink missing'
- for dat_line in [dl for dl in self.dat_lines if dl.error]:
+ transfer_lines[-1].errors += ['needed sink missing']
+ self.questionable = False
+ for _ in [bl for bl in [intro_line] + transfer_lines if bl.errors]:
self.questionable = True
break