reports: Balance has built-in tolerance for zero comparisons.
This commit is contained in:
parent
f8f57428aa
commit
4cba2b2681
2 changed files with 26 additions and 8 deletions
|
@ -80,10 +80,17 @@ class Balance(Mapping[str, data.Amount]):
|
|||
Each key is a Beancount currency string, and each value represents the
|
||||
balance in that currency.
|
||||
"""
|
||||
__slots__ = ('_currency_map',)
|
||||
__slots__ = ('_currency_map', 'tolerance')
|
||||
TOLERANCE = Decimal('0.01')
|
||||
|
||||
def __init__(self, source: Iterable[data.Amount]=()) -> None:
|
||||
def __init__(self,
|
||||
source: Iterable[data.Amount]=(),
|
||||
tolerance: Optional[Decimal]=None,
|
||||
) -> None:
|
||||
if tolerance is None:
|
||||
tolerance = self.TOLERANCE
|
||||
self._currency_map = {amount.currency: amount for amount in source}
|
||||
self.tolerance = tolerance
|
||||
|
||||
def _add_amount(self,
|
||||
currency_map: MutableMapping[str, data.Amount],
|
||||
|
@ -147,19 +154,24 @@ class Balance(Mapping[str, data.Amount]):
|
|||
) -> bool:
|
||||
return all(op_func(amt.number, operand) for amt in self.values())
|
||||
|
||||
@staticmethod
|
||||
def within_tolerance(dec: DecimalCompat, tolerance: DecimalCompat) -> bool:
|
||||
dec = cast(Decimal, dec)
|
||||
return abs(dec) < tolerance
|
||||
|
||||
def eq_zero(self) -> bool:
|
||||
"""Returns true if all amounts in the balance == 0."""
|
||||
return self._all_amounts(operator.eq, 0)
|
||||
"""Returns true if all amounts in the balance == 0, within tolerance."""
|
||||
return self._all_amounts(self.within_tolerance, self.tolerance)
|
||||
|
||||
is_zero = eq_zero
|
||||
|
||||
def ge_zero(self) -> bool:
|
||||
"""Returns true if all amounts in the balance >= 0."""
|
||||
return self._all_amounts(operator.ge, 0)
|
||||
"""Returns true if all amounts in the balance >= 0, within tolerance."""
|
||||
return self._all_amounts(operator.ge, -self.tolerance)
|
||||
|
||||
def le_zero(self) -> bool:
|
||||
"""Returns true if all amounts in the balance <= 0."""
|
||||
return self._all_amounts(operator.le, 0)
|
||||
"""Returns true if all amounts in the balance <= 0, within tolerance."""
|
||||
return self._all_amounts(operator.le, self.tolerance)
|
||||
|
||||
def format(self,
|
||||
fmt: Optional[str]='#,#00.00 ¤¤',
|
||||
|
|
|
@ -92,6 +92,8 @@ def test_mixed_balance():
|
|||
({'JPY': 10}, False),
|
||||
({'JPY': 10, 'BRL': 0}, False),
|
||||
({'JPY': 10, 'BRL': 20}, False),
|
||||
({'USD': '0.00015'}, True),
|
||||
({'EUR': '-0.00052'}, True),
|
||||
])
|
||||
def test_eq_zero(mapping, expected):
|
||||
balance = core.Balance(amounts_from_map(mapping))
|
||||
|
@ -108,6 +110,8 @@ def test_eq_zero(mapping, expected):
|
|||
({'JPY': 10}, True),
|
||||
({'JPY': 10, 'BRL': 0}, True),
|
||||
({'JPY': 10, 'BRL': 20}, True),
|
||||
({'USD': '0.00015'}, True),
|
||||
({'EUR': '-0.00052'}, True),
|
||||
])
|
||||
def test_ge_zero(mapping, expected):
|
||||
balance = core.Balance(amounts_from_map(mapping))
|
||||
|
@ -123,6 +127,8 @@ def test_ge_zero(mapping, expected):
|
|||
({'JPY': 10}, False),
|
||||
({'JPY': 10, 'BRL': 0}, False),
|
||||
({'JPY': 10, 'BRL': 20}, False),
|
||||
({'USD': '0.00015'}, True),
|
||||
({'EUR': '-0.00052'}, True),
|
||||
])
|
||||
def test_le_zero(mapping, expected):
|
||||
balance = core.Balance(amounts_from_map(mapping))
|
||||
|
|
Loading…
Reference in a new issue