home
·
contact
·
privacy
projects
/
ledgplom
/ commitdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
| commitdiff |
tree
raw
|
patch
|
inline
| side by side (parent:
971202f
)
Optimize performance by caching some values.
master
author
Christian Heller
<c.heller@plomlompom.de>
Mon, 2 Feb 2026 19:44:11 +0000
(20:44 +0100)
committer
Christian Heller
<c.heller@plomlompom.de>
Mon, 2 Feb 2026 19:44:11 +0000
(20:44 +0100)
src/ledgplom/ledger.py
patch
|
blob
|
history
diff --git
a/src/ledgplom/ledger.py
b/src/ledgplom/ledger.py
index 2a1ee5915e1efeac1ec23d3409e333c72b74750b..27624985e063369ec4f95ed6b949b5acb8ae33b2 100644
(file)
--- a/
src/ledgplom/ledger.py
+++ b/
src/ledgplom/ledger.py
@@
-4,7
+4,7
@@
from abc import ABC, abstractmethod
from datetime import date as dt_date
from decimal import Decimal, InvalidOperation as DecimalInvalidOperation
from pathlib import Path
from datetime import date as dt_date
from decimal import Decimal, InvalidOperation as DecimalInvalidOperation
from pathlib import Path
-from typing import Any, Iterator, Optional, Self
+from typing import Any,
Callable,
Iterator, Optional, Self
SPACE = ' '
SPACE = ' '
@@
-284,27
+284,46
@@
class _TransferLine(_BookingLine):
class _LinesBlock:
class _LinesBlock:
- _lines: list[_DatLine]
+ _lines: tuple[_DatLine, ...] = tuple()
+ _cached_id = -1
+ _cached: dict[str, Any]
def __init__(self) -> None:
def __init__(self) -> None:
- self._lines = []
+ self._cached = {}
+
+ @staticmethod
+ def _cache(key_cached: str) -> Callable:
+ def decorator(f: Callable) -> Callable:
+ def wrapper(self):
+ # pylint: disable=protected-access
+ if key_cached not in self._cached:
+ self._cached[key_cached] = f(self)
+ return self._cached[key_cached]
+ return wrapper
+ return decorator
@property
def lines(self) -> tuple[_DatLine, ...]:
'Return collected lines.'
@property
def lines(self) -> tuple[_DatLine, ...]:
'Return collected lines.'
- return tuple(self._lines)
+ return self._lines
+
+ @lines.setter
+ def lines(self, new_lines: tuple[_DatLine, ...]) -> None:
+ self._lines = new_lines
+ self._cached.clear()
def add(self, lines: tuple[_DatLine, ...], at_end=True) -> None:
'Grow block downwards by this one DatLine.'
if at_end:
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 += lines
else:
else:
- self.
_lines[0:0] = list(lines)
+ self.
lines = lines + self.lines
class _Booking(_LinesBlock):
@property
class _Booking(_LinesBlock):
@property
+ @_LinesBlock._cache('_sink_account')
def _sink_account(self) -> str:
for tf_line in [tl for tl in self.transfer_lines
if tl.amount is None and not tl.errors]:
def _sink_account(self) -> str:
for tf_line in [tl for tl in self.transfer_lines
if tl.amount is None and not tl.errors]:
@@
-312,8
+331,8
@@
class _Booking(_LinesBlock):
return ''
@property
return ''
@property
- def lines(self) -> tuple[_BookingLine, ...]:
- '
Return collected
lines.'
+ def
booking_
lines(self) -> tuple[_BookingLine, ...]:
+ '
Sequence of .intro_line and .transfer_
lines.'
return (self.intro_line, ) + self.transfer_lines
@property
return (self.intro_line, ) + self.transfer_lines
@property
@@
-336,6
+355,7
@@
class _Booking(_LinesBlock):
return {acc: diff for acc, diff in self._diffs_targeted.items() if acc}
@property
return {acc: diff for acc, diff in self._diffs_targeted.items() if acc}
@property
+ @_LinesBlock._cache('sink_error')
def sink_error(self) -> str:
'Message on error, if any, regarding sink calculation/placement.'
for _ in [tl for tl in self.transfer_lines
def sink_error(self) -> str:
'Message on error, if any, regarding sink calculation/placement.'
for _ in [tl for tl in self.transfer_lines
@@
-362,12
+382,13
@@
class _Booking(_LinesBlock):
@property
def intro_line(self) -> _IntroLine:
'Return collected _IntroLine.'
@property
def intro_line(self) -> _IntroLine:
'Return collected _IntroLine.'
- return _IntroLine(self.
_
lines[0].raw)
+ return _IntroLine(self.lines[0].raw)
@property
@property
+ @_LinesBlock._cache('transfer_lines')
def transfer_lines(self) -> tuple[_TransferLine, ...]:
'Any lines past the first with .code.'
def transfer_lines(self) -> tuple[_TransferLine, ...]:
'Any lines past the first with .code.'
- return tuple(_TransferLine(line.raw) for line in self.
_
lines[1:]
+ return tuple(_TransferLine(line.raw) for line in self.lines[1:]
if line.code)
@property
if line.code)
@property
@@
-405,6
+426,7
@@
class _DatBlock(_LinesBlock):
return bool([line for line in self.lines if line.len_indent])
@property
return bool([line for line in self.lines if line.len_indent])
@property
+ @_LinesBlock._cache('gap_lines')
def gap_lines(self) -> tuple[_DatLine, ...]:
'Sequence of all included DatLines without code and indent.'
return tuple(line for line in self.lines
def gap_lines(self) -> tuple[_DatLine, ...]:
'Sequence of all included DatLines without code and indent.'
return tuple(line for line in self.lines
@@
-426,10
+448,11
@@
class _DatBlock(_LinesBlock):
def remove_redundant_empty_lines(self):
'From self remove .redundant_empty_lines.'
def remove_redundant_empty_lines(self):
'From self remove .redundant_empty_lines.'
- for line in self.redundant_empty_lines:
-
self._lines.remove(line
)
+ self.lines = tuple(line for line in self.lines
+
if line not in self.redundant_empty_lines
)
@property
@property
+ @_LinesBlock._cache('booking')
def booking(self) -> Optional[_Booking]:
'Booking made from lines indented or with code.'
booking_lines = tuple(_DatLine(line.raw) for line in self.lines
def booking(self) -> Optional[_Booking]:
'Booking made from lines indented or with code.'
booking_lines = tuple(_DatLine(line.raw) for line in self.lines
@@
-617,7
+640,7
@@
class Ledger:
if block.booking:
if block.booking.sink_error:
return False
if block.booking:
if block.booking.sink_error:
return False
- if [
line for line in block.booking.lines if line
.errors]:
+ if [
bl for bl in block.booking.booking_lines if bl
.errors]:
return False
if block.date_error:
return False
return False
if block.date_error:
return False
@@
-693,7
+716,7
@@
class Ledger:
if lines:
return {'raw_gap_lines': [dl.raw for dl in block.gap_lines],
'booking_lines': ([line.as_dict
if lines:
return {'raw_gap_lines': [dl.raw for dl in block.gap_lines],
'booking_lines': ([line.as_dict
- for line in block.booking.lines]
+ for line in block.booking.
booking_
lines]
if block.booking else tuple())}
accounts = self._calc_accounts()
roots: list[dict[str, Any]] = []
if block.booking else tuple())}
accounts = self._calc_accounts()
roots: list[dict[str, Any]] = []