refactor(data): unify vendor errors under a VendorError hierarchy

Every condition where a vendor cannot return usable data now derives from a
single VendorError base (errors.py): NoMarketDataError, VendorRateLimitError,
and VendorNotConfiguredError (still a ValueError for back-compat). Vendor-named
errors subclass the generic bases, and the router catches the base types, so a
new vendor needs no new except clause. Not-configured now has explicit
try-next-vendor handling instead of falling through the generic catch-all. The
number of error types tracks the number of distinct router reactions, not the
number of causes.
This commit is contained in:
Yijia-Xiao committed 2026-06-14 07:10:15 +00:00
1 parent db059034a2
commit 7df18fc912
7 files changed
+226 -64

No files matched your search

+4 -20
View File
@@ -23,29 +23,13 @@ from __future__ import annotations
import logging
import re
# NoMarketDataError lives in the vendor-error taxonomy (errors.py); re-exported
# here for the many call sites that import it alongside normalize_symbol.
from .errors import NoMarketDataError as NoMarketDataError
logger = logging.getLogger(__name__)
class NoMarketDataError(Exception):
"""Raised when a vendor returns no rows/records for a symbol.
Carries both the symbol the user requested and the canonical symbol the
vendor was actually queried with, so callers can build a clear message
instead of emitting a vendor-specific empty string into the data channel.
"""
def __init__(self, symbol: str, canonical: str | None = None, detail: str = ""):
self.symbol = symbol
self.canonical = canonical or symbol
self.detail = detail
msg = f"No market data for {symbol!r}"
if canonical and canonical != symbol:
msg += f" (queried as {canonical!r})"
if detail:
msg += f": {detail}"
super().__init__(msg)
# ISO-4217 codes common enough to appear in retail forex pairs. A bare
# six-letter symbol whose halves are BOTH in this set is treated as a spot
# forex pair and given Yahoo's ``=X`` suffix.