mirror of
https://github.com/eitchtee/WYGIWYH.git
synced 2026-11-13 12:23:44 +01:00
fix(automatic-exchange-rates): skip bad AllRatesToday rows individually
A non-numeric, NaN or infinite value raised while parsing and threw away the whole table. Each bad row is now skipped on its own. Log a warning when a table has rows but none of a usable rate type, so a bank with unknown types does not fail silently.
This commit is contained in:
1 parent
43145be24d
commit
6a335b1a63
2 files changed
+44
-4
No files matched your search
@@ -739,10 +739,17 @@ class AllRatesTodayProvider(ExchangeRateProvider):
|
||||
"""Reduce the table to one rate per pair, in both directions"""
|
||||
grouped = {}
|
||||
for row in rows:
|
||||
if not isinstance(row, dict) or not row.get("value"):
|
||||
if not isinstance(row, dict):
|
||||
continue
|
||||
try:
|
||||
value = Decimal(str(row.get("value")))
|
||||
except ArithmeticError:
|
||||
continue
|
||||
# A bad cell skips its own row, not the whole table
|
||||
if not value.is_finite() or value <= 0:
|
||||
continue
|
||||
pair = (row.get("base"), row.get("quote"))
|
||||
grouped.setdefault(pair, {})[row.get("type")] = Decimal(str(row["value"]))
|
||||
grouped.setdefault(pair, {})[row.get("type")] = value
|
||||
|
||||
rates = {}
|
||||
for (base, quote), values in grouped.items():
|
||||
@@ -756,11 +763,22 @@ class AllRatesTodayProvider(ExchangeRateProvider):
|
||||
),
|
||||
None,
|
||||
)
|
||||
if rate is None or rate <= 0:
|
||||
if rate is None:
|
||||
logger.debug(
|
||||
f"AllRatesToday {self.bank}: no usable rate type for "
|
||||
f"{base}/{quote}, got {sorted(map(str, values))}"
|
||||
)
|
||||
continue
|
||||
rates[(base, quote)] = rate
|
||||
rates.setdefault((quote, base), self.invert_rate(rate))
|
||||
|
||||
if grouped and not rates:
|
||||
types = sorted({str(t) for values in grouped.values() for t in values})
|
||||
logger.warning(
|
||||
f"AllRatesToday table for {self.bank} has no usable rate types, "
|
||||
f"got {types}"
|
||||
)
|
||||
|
||||
return rates
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -155,13 +155,35 @@ class AllRatesTodayProviderTests(TestCase):
|
||||
|
||||
self.assertEqual(self._get_rates(rows, self.brl, self.usd), [])
|
||||
|
||||
def test_logs_a_table_without_usable_types(self):
|
||||
self.usd.exchange_currency = self.brl
|
||||
payload = {"rates": [_row("USD", "BRL", 5, "monthly_average")]}
|
||||
|
||||
with patch.object(
|
||||
self.provider.session, "get", return_value=_response(payload)
|
||||
):
|
||||
with self.assertLogs(
|
||||
"apps.currencies.exchange_rates.providers", level="WARNING"
|
||||
) as logs:
|
||||
self.provider.get_rates([self.usd], {self.brl})
|
||||
|
||||
self.assertIn("monthly_average", logs.output[0])
|
||||
|
||||
def test_skips_pair_missing_from_the_table(self):
|
||||
rows = [_row("USD", "BRL", 5)]
|
||||
|
||||
self.assertEqual(self._get_rates(rows, self.eur, self.usd), [])
|
||||
|
||||
def test_ignores_zero_and_malformed_rows(self):
|
||||
rows = ["nope", _row("USD", "BRL", 0), _row("EUR", "BRL", 6)]
|
||||
rows = [
|
||||
"nope",
|
||||
_row("USD", "BRL", 0),
|
||||
_row("USD", "BRL", "5,4"),
|
||||
_row("USD", "BRL", None),
|
||||
_row("USD", "BRL", "Infinity"),
|
||||
_row("USD", "BRL", "NaN"),
|
||||
_row("EUR", "BRL", 6),
|
||||
]
|
||||
|
||||
rates = self._get_rates(rows, self.brl, self.eur)
|
||||
|
||||
|
||||
Reference in new issue
Block a user