Skip to content

Commit

Permalink
Accept function values for IntoMoney
Browse files Browse the repository at this point in the history
Fixes #7.
  • Loading branch information
jbhannah committed Dec 27, 2024
1 parent c6089ab commit 81e1903
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 12 deletions.
25 changes: 18 additions & 7 deletions src/budge/money.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,29 @@
from collections.abc import Callable
from decimal import Decimal
from typing import Any, Union
from typing import Any

from stockholm import Money, MoneyType
from stockholm import Money
from stockholm.money import MoneyModel

IntoMoneyType = Union[MoneyType, MoneyModel[Any], Decimal, int, float, str, object]
type IntoMoneyType = MoneyModel[Money] | Decimal | int | float | str

type IntoMoneyCallback = Callable[[Any], IntoMoneyType]


class IntoMoney:
def __set_name__(self, owner: Any, name: str):
self._name = "_" + name

def __get__(self, instance, owner=None) -> Money:
return getattr(instance, self._name)
def __get__(self, instance: Any, owner=None) -> Money:
attr: Money | IntoMoneyCallback = getattr(instance, self._name)

if isinstance(attr, Money):
return attr

return Money(attr(instance))

def __set__(self, instance, value: IntoMoneyType | IntoMoneyCallback):
if not callable(value):
value = Money(value)

def __set__(self, instance, value: IntoMoneyType):
setattr(instance, self._name, Money(value))
setattr(instance, self._name, value)
24 changes: 19 additions & 5 deletions tests/budge/test_money.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,25 @@ def test_into_money_from_str():
assert obj.amount == Money(100)


def test_into_money_from_none():
with raises(ConversionError, match="Missing input values for monetary amount"):
IntoMoneyTest(None)


def test_into_money_from_empty_string():
with raises(ConversionError, match="Missing input values for monetary amount"):
IntoMoneyTest("")


def test_into_money_with_callable():
def get_amount(instance: IntoMoneyTest):
assert instance is obj
return Money(100)

obj = IntoMoneyTest(get_amount)
assert isinstance(obj.amount, Money)
assert obj.amount == Money(100)


def test_into_money_with_wrong_callable_type():
def wrong_function(instance: IntoMoneyTest):
return "can't convert this to Money"

obj = IntoMoneyTest(wrong_function)
with raises(ConversionError, match="Input value cannot be used as monetary amount"):
obj.amount

0 comments on commit 81e1903

Please sign in to comment.