"""Thailand external-sector / trade factor — TradingEconomics Thailand. Source: https://tradingeconomics.com/thailand/current-account (server-rendered HTML, same infobox/infrastructure as the auto_credit source — the "related indicators" table lists the current value, previous value, unit and reporting period for Thailand's external account). Verified live: the current-account page's related-indicators table exposes (Jul 2026) Exports 34,781.10, Imports 38,399.60, Balance of Trade -3,611.00 USD mn and (Jun 2026) Current Account -3,473.85 USD mn. Replaces the stale BOT report-60 path (which only carried data through 2011) with a CURRENT, free, scrapeable source per the plan's "do not ship a wrong/stale series" gate. """ from __future__ import annotations import html import re from dataclasses import dataclass from typing import Optional from urllib.request import Request, urlopen _USER_AGENT = ( "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 " "(KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36" ) _URL = "https://tradingeconomics.com/thailand/current-account" class ThaiTradeError(Exception): """Raised when the TradingEconomics Thailand page cannot be fetched/parsed.""" @dataclass(frozen=True) class ThaiTradeSnapshot: current_account_usdm: Optional[float] = None # USD million trade_balance_usdm: Optional[float] = None # USD million exports_usdm: Optional[float] = None # USD million imports_usdm: Optional[float] = None # USD million as_of: str = "" source: str = "tradingeconomics.thai-trade" def to_dict(self) -> dict: return { "source": self.source, "as_of": self.as_of, "current_account_usdm": self.current_account_usdm, "trade_balance_usdm": self.trade_balance_usdm, "exports_usdm": self.exports_usdm, "imports_usdm": self.imports_usdm, } def _fetch(url: str = _URL, timeout: float = 30.0) -> str: req = Request(url, headers={"User-Agent": _USER_AGENT, "Accept": "text/html"}) try: with urlopen(req, timeout=timeout) as resp: raw = resp.read() except Exception as exc: raise ThaiTradeError(f"failed to fetch {url}: {exc}") from exc try: return raw.decode("utf-8") except UnicodeDecodeError: return raw.decode("latin-1", "ignore") def _tables(html_text: str) -> list[str]: return re.findall(r"