more methods and tests

This commit is contained in:
Pablo Martin 2024-06-12 00:44:30 +02:00
parent aec65e5364
commit d382c332e3
2 changed files with 145 additions and 12 deletions

View file

@ -4,7 +4,12 @@ from decimal import Decimal
from money.currency import Currency from money.currency import Currency
from money.money import Money from money.money import Money
from xexe.exchange_rates import ExchangeRate, ExchangeRates, add_equal_rates from xexe.exchange_rates import (
ExchangeRate,
ExchangeRates,
add_equal_rates,
add_inverse_rates,
)
def test_exchange_rate_creation_works(): def test_exchange_rate_creation_works():
@ -124,6 +129,26 @@ def test_present_dates_works_fine():
} }
def test_exchange_rates_is_rate_present_method_works_fine():
a_rate = ExchangeRate(
from_currency=Currency.USD,
to_currency=Currency.EUR,
rate=Decimal("1.2"),
rate_date=datetime.date(2020, 3, 10),
)
another_rate = ExchangeRate(
from_currency=Currency.GBP,
to_currency=Currency.JPY,
rate=Decimal("10"),
rate_date=datetime.date(2019, 10, 3),
)
rates = ExchangeRates({a_rate})
assert rates.is_rate_present(a_rate)
assert not rates.is_rate_present(another_rate)
def test_add_equal_rates_returns_expected_values(): def test_add_equal_rates_returns_expected_values():
a_rate = ExchangeRate( a_rate = ExchangeRate(
from_currency=Currency.USD, from_currency=Currency.USD,
@ -170,3 +195,73 @@ def test_add_equal_rates_runs_on_empty_rates():
empty_rates = add_equal_rates(empty_rates) empty_rates = add_equal_rates(empty_rates)
assert True assert True
def test_add_equal_rates_overwrites():
a_rate = ExchangeRate(
from_currency=Currency.USD,
to_currency=Currency.USD,
rate=Decimal("1.2"),
rate_date=datetime.date(2020, 3, 10),
)
rates = ExchangeRates([a_rate])
assert len(rates) == 1
rates = add_equal_rates(rates, overwrite=True)
assert len(rates) == 1
assert list(rates)[0].amount == 1
def test_add_equal_rates_does_not_overwrite():
a_rate = ExchangeRate(
from_currency=Currency.USD,
to_currency=Currency.USD,
rate=Decimal("1.2"),
rate_date=datetime.date(2020, 3, 10),
)
rates = ExchangeRates([a_rate])
assert len(rates) == 1
rates = add_equal_rates(rates, overwrite=False)
assert len(rates) == 1
assert list(rates)[0].amount == Decimal("1.2")
def test_add_inverse_rates_returns_expected():
a_rate = ExchangeRate(
from_currency=Currency.EUR,
to_currency=Currency.USD,
rate=Decimal("1.25"),
rate_date=datetime.date(2020, 3, 10),
)
inverse_rate = ExchangeRate(
from_currency=Currency.USD,
to_currency=Currency.EUR,
rate=Decimal("0.8"),
rate_date=datetime.date(2020, 3, 10),
)
rates = ExchangeRates([a_rate])
assert len(rates) == 1
rates = add_inverse_rates(rates)
assert len(rates) == 2
assert rates.is_rate_present(inverse_rate)
assert rates[inverse_rate.descriptor].amount == Decimal("0.8")
def test_add_inverse_rates_runs_on_empty_rates():
empty_rates = ExchangeRates()
empty_rates = add_inverse_rates(empty_rates)
assert True

View file

@ -3,7 +3,7 @@ from decimal import Decimal
from numbers import Number from numbers import Number
from typing import Iterable, Set, Union from typing import Iterable, Set, Union
from money.currency import Currency from money.currency import Currency, CurrencyHelper
from money.money import Money from money.money import Money
@ -13,7 +13,7 @@ class ExchangeRate:
self, self,
from_currency: Currency, from_currency: Currency,
to_currency: Currency, to_currency: Currency,
rate: Union[Money, Number], rate: Union[Money, Number, str],
rate_date: datetime.date, rate_date: datetime.date,
) -> None: ) -> None:
self.from_currency = from_currency self.from_currency = from_currency
@ -66,26 +66,64 @@ class ExchangeRates:
self._rate_index[new_rate.descriptor] = new_rate self._rate_index[new_rate.descriptor] = new_rate
def __iter__(self): def __iter__(self):
return iter(self._rate_index.values()) return iter(list(self._rate_index.values()))
def __len__(self): def __len__(self):
return len(self._rate_index) return len(self._rate_index)
def __contains__(self, rate) -> bool:
if not isinstance(rate, ExchangeRate):
raise TypeError("ExchangeRates can only hold Rates.")
def add_equal_rates(rates: ExchangeRates) -> ExchangeRates: if rate.descriptor in self._rate_index:
return True
return False
def is_rate_present(self, rate: ExchangeRate) -> bool:
if rate.descriptor in self._rate_index:
return True
return False
def __getitem__(self, rate_descriptor) -> ExchangeRate:
return self._rate_index[rate_descriptor]
def add_equal_rates(rates: ExchangeRates, overwrite: bool = False) -> ExchangeRates:
present_currencies = rates.present_currencies present_currencies = rates.present_currencies
present_dates = rates.present_dates present_dates = rates.present_dates
for date in present_dates: for date in present_dates:
for currency in present_currencies: for currency in present_currencies:
rates.add_rate( new_rate = ExchangeRate(
ExchangeRate( from_currency=currency,
from_currency=currency, to_currency=currency,
to_currency=currency, rate=Money(1, currency),
rate=Money(1, currency), rate_date=date,
rate_date=date,
)
) )
if new_rate in rates and not overwrite:
continue
rates.add_rate(new_rate)
return rates
def add_inverse_rates(rates: ExchangeRates) -> ExchangeRates:
# Hey, I haven't thought properly what happens here if the inverse rate is
# *already* present in the rates set. It's probably going to be fucky. I
# would advise only running this against sets where you don't have inverse
# rates already present.
for rate in rates:
inverse_rate = ExchangeRate(
from_currency=rate.to_currency,
to_currency=rate.from_currency,
rate_date=rate.rate_date,
rate=f"{1 / rate.amount:.{CurrencyHelper.decimal_precision_for_currency(rate.from_currency)}f}",
)
rates.add_rate(inverse_rate)
return rates return rates