ledger_entry: Improve error reporting for amount expressions.

This is going to become more important as amount expressions become more
capable.
This commit is contained in:
Brett Smith 2019-07-29 12:05:51 -04:00
parent 5463290f87
commit 4009c626d4
3 changed files with 30 additions and 5 deletions

View file

@ -168,11 +168,17 @@ class AccountSplitter:
def _build_amounts(self, template_vars): def _build_amounts(self, template_vars):
amount_vars = {k: v for k, v in template_vars.items() if isinstance(v, decimal.Decimal)} amount_vars = {k: v for k, v in template_vars.items() if isinstance(v, decimal.Decimal)}
amount_vars['Decimal'] = decimal.Decimal amount_vars['Decimal'] = decimal.Decimal
amounts = [ try:
(account, self._currency_decimal(eval(amount_expr, amount_vars), amounts = [
template_vars['currency'])) (account, self._currency_decimal(eval(amount_expr, amount_vars),
for account, amount_expr in self.splits template_vars['currency']))
] for account, amount_expr in self.splits
]
except (ArithmeticError, NameError, TypeError, ValueError) as error:
raise errors.UserInputConfigurationError(
"{}: {}".format(type(error).__name__, error),
"template {!r}".format(self.template_name)
) from error
self._balance_amounts(amounts, template_vars['amount']) self._balance_amounts(amounts, template_vars['amount'])
self._balance_amounts(amounts, -template_vars['amount']) self._balance_amounts(amounts, -template_vars['amount'])
return amounts return amounts

View file

@ -53,6 +53,16 @@ template =
Expenses:Banking Fees (6 if {amount} > 50 else 3) Expenses:Banking Fees (6 if {amount} > 50 else 3)
Income:Sales -{amount} Income:Sales -{amount}
[NondecimalWord]
template =
Income:Sales -5
Assets:Cash foo
[NondecimalVariable]
template =
Income:Sales -5
Assets:Cash {payee}
[Empty] [Empty]
template = template =

View file

@ -259,3 +259,12 @@ def test_hook_handles_template_undefined():
entry_data = template_vars('DD', 1) entry_data = template_vars('DD', 1)
assert not run_hook(entry_data, 'Nonexistent') assert not run_hook(entry_data, 'Nonexistent')
def test_string_value_is_user_error():
entry_data = template_vars('EE', 1)
with pytest.raises(errors.UserInputConfigurationError):
run_hook(entry_data, 'NondecimalWord')
def test_string_variable_is_user_error():
entry_data = template_vars('FF', 1)
with pytest.raises(errors.UserInputConfigurationError):
run_hook(entry_data, 'NondecimalVariable')