Skip to content

mostlyright.international

Phase 3.1 — International station expansion + daily_extremes rollup.

Phase 3.1 v0.1.0 scope: expand the v0.14.1 20-US station registry to 60 (20 US + 40 international ICAOs), add the per-event station resolver for multi-airport cities (Paris LFPG/LFPB split), add daily_extremes() rollup with station-local IANA calendar day semantics, and surface whole-°C source-precision for international stations.

The full STATIONS dict lives in _internal/_stations.py; this module exposes the public extension surface — daily_extremes(station, from_date, to_date) + DeferredMarketError for sources we can’t ship until v0.2 (Taipei CWA, HK HKO).

INTERNATIONAL_STATIONSPhase 3.1 international ICAOs — 40 stations covering the markets Polymarket lists as of v0.1.0 scope.
DEFERRED_STATIONSMarkets routed to stations whose data source is deferred to v0.2.
daily_extremes(station, from_date, to_date, *)Roll up cached hourly observations to per-local-day temperature extremes.
DeferredMarketError([message, error_code, …])A market resolves to a station whose data source is deferred to v0.2.

Markets routed to stations whose data source is deferred to v0.2. Phase 23 reconciled Hong Kong to its actual Polymarket settlement station, HKO (the HK Observatory) — no airport ICAO, sourced from weather.gov.hk, so ALL HK markets now defer (previously HK-high routed via VHHH METAR). Taipei moved RCTP→RCSS (Songshan); RCSS defers all markets (CWA is the sole issuer there). VHHH/RCTP remain registry weather stations but no longer front any deferred market.

exception mostlyright.international.DeferredMarketError(message=”, , error_code=None, source=None, request_id=None)

Section titled “exception mostlyright.international.DeferredMarketError(message=”, , error_code=None, source=None, request_id=None)”

Bases: MostlyRightError

A market resolves to a station whose data source is deferred to v0.2.

Currently raised for Taipei (RCSS, CWA client) and Hong Kong (HKO, weather.gov.hk client). v0.2 will land both clients and remove the deferral.

  • Parameters:
    • message (str)
    • error_code (str)
    • source (str | None)
    • request_id (str | None)
  • Return type: None

Subclass override — the stable string enum surfaced via error_code.

mostlyright.international.INTERNATIONAL_STATIONS : dict[str, str] = {‘CYYZ’: ‘America/Toronto’, ‘EDDB’: ‘Europe/Berlin’, ‘EDDF’: ‘Europe/Berlin’, ‘EDDM’: ‘Europe/Berlin’, ‘EFHK’: ‘Europe/Helsinki’, ‘EGKK’: ‘Europe/London’, ‘EGLC’: ‘Europe/London’, ‘EGLL’: ‘Europe/London’, ‘EHAM’: ‘Europe/Amsterdam’, ‘EKCH’: ‘Europe/Copenhagen’, ‘EPWA’: ‘Europe/Warsaw’, ‘ESSA’: ‘Europe/Stockholm’, ‘FACT’: ‘Africa/Johannesburg’, ‘LEBL’: ‘Europe/Madrid’, ‘LEMD’: ‘Europe/Madrid’, ‘LFPB’: ‘Europe/Paris’, ‘LFPG’: ‘Europe/Paris’, ‘LFPO’: ‘Europe/Paris’, ‘LIMC’: ‘Europe/Rome’, ‘LIRF’: ‘Europe/Rome’, ‘LLBG’: ‘Asia/Jerusalem’, ‘LOWW’: ‘Europe/Vienna’, ‘LSZH’: ‘Europe/Zurich’, ‘LTAC’: ‘Europe/Istanbul’, ‘LTFM’: ‘Europe/Istanbul’, ‘MMMX’: ‘America/Mexico_City’, ‘MPMG’: ‘America/Panama’, ‘NZAA’: ‘Pacific/Auckland’, ‘NZWN’: ‘Pacific/Auckland’, ‘OEJN’: ‘Asia/Riyadh’, ‘OERK’: ‘Asia/Riyadh’, ‘OMDB’: ‘Asia/Dubai’, ‘OPKC’: ‘Asia/Karachi’, ‘OTHH’: ‘Asia/Qatar’, ‘RCSS’: ‘Asia/Taipei’, ‘RCTP’: ‘Asia/Taipei’, ‘RJAA’: ‘Asia/Tokyo’, ‘RJTT’: ‘Asia/Tokyo’, ‘RKPK’: ‘Asia/Seoul’, ‘RKSI’: ‘Asia/Seoul’, ‘RPLL’: ‘Asia/Manila’, ‘SAEZ’: ‘America/Argentina/Buenos_Aires’, ‘SBGR’: ‘America/Sao_Paulo’, ‘UUEE’: ‘Europe/Moscow’, ‘UUWW’: ‘Europe/Moscow’, ‘VABB’: ‘Asia/Kolkata’, ‘VHHH’: ‘Asia/Hong_Kong’, ‘VIDP’: ‘Asia/Kolkata’, ‘VILK’: ‘Asia/Kolkata’, ‘VTBS’: ‘Asia/Bangkok’, ‘WMKK’: ‘Asia/Kuala_Lumpur’, ‘WSSS’: ‘Asia/Singapore’, ‘YBBN’: ‘Australia/Brisbane’, ‘YMML’: ‘Australia/Melbourne’, ‘YSSY’: ‘Australia/Sydney’, ‘ZBAA’: ‘Asia/Shanghai’, ‘ZGGG’: ‘Asia/Shanghai’, ‘ZGSZ’: ‘Asia/Shanghai’, ‘ZHCC’: ‘Asia/Shanghai’, ‘ZHHH’: ‘Asia/Shanghai’, ‘ZSJN’: ‘Asia/Shanghai’, ‘ZSPD’: ‘Asia/Shanghai’, ‘ZSQD’: ‘Asia/Shanghai’, ‘ZUCK’: ‘Asia/Shanghai’, ‘ZUUU’: ‘Asia/Shanghai’}

Section titled “mostlyright.international.INTERNATIONAL_STATIONS : dict[str, str] = {‘CYYZ’: ‘America/Toronto’, ‘EDDB’: ‘Europe/Berlin’, ‘EDDF’: ‘Europe/Berlin’, ‘EDDM’: ‘Europe/Berlin’, ‘EFHK’: ‘Europe/Helsinki’, ‘EGKK’: ‘Europe/London’, ‘EGLC’: ‘Europe/London’, ‘EGLL’: ‘Europe/London’, ‘EHAM’: ‘Europe/Amsterdam’, ‘EKCH’: ‘Europe/Copenhagen’, ‘EPWA’: ‘Europe/Warsaw’, ‘ESSA’: ‘Europe/Stockholm’, ‘FACT’: ‘Africa/Johannesburg’, ‘LEBL’: ‘Europe/Madrid’, ‘LEMD’: ‘Europe/Madrid’, ‘LFPB’: ‘Europe/Paris’, ‘LFPG’: ‘Europe/Paris’, ‘LFPO’: ‘Europe/Paris’, ‘LIMC’: ‘Europe/Rome’, ‘LIRF’: ‘Europe/Rome’, ‘LLBG’: ‘Asia/Jerusalem’, ‘LOWW’: ‘Europe/Vienna’, ‘LSZH’: ‘Europe/Zurich’, ‘LTAC’: ‘Europe/Istanbul’, ‘LTFM’: ‘Europe/Istanbul’, ‘MMMX’: ‘America/Mexico_City’, ‘MPMG’: ‘America/Panama’, ‘NZAA’: ‘Pacific/Auckland’, ‘NZWN’: ‘Pacific/Auckland’, ‘OEJN’: ‘Asia/Riyadh’, ‘OERK’: ‘Asia/Riyadh’, ‘OMDB’: ‘Asia/Dubai’, ‘OPKC’: ‘Asia/Karachi’, ‘OTHH’: ‘Asia/Qatar’, ‘RCSS’: ‘Asia/Taipei’, ‘RCTP’: ‘Asia/Taipei’, ‘RJAA’: ‘Asia/Tokyo’, ‘RJTT’: ‘Asia/Tokyo’, ‘RKPK’: ‘Asia/Seoul’, ‘RKSI’: ‘Asia/Seoul’, ‘RPLL’: ‘Asia/Manila’, ‘SAEZ’: ‘America/Argentina/Buenos_Aires’, ‘SBGR’: ‘America/Sao_Paulo’, ‘UUEE’: ‘Europe/Moscow’, ‘UUWW’: ‘Europe/Moscow’, ‘VABB’: ‘Asia/Kolkata’, ‘VHHH’: ‘Asia/Hong_Kong’, ‘VIDP’: ‘Asia/Kolkata’, ‘VILK’: ‘Asia/Kolkata’, ‘VTBS’: ‘Asia/Bangkok’, ‘WMKK’: ‘Asia/Kuala_Lumpur’, ‘WSSS’: ‘Asia/Singapore’, ‘YBBN’: ‘Australia/Brisbane’, ‘YMML’: ‘Australia/Melbourne’, ‘YSSY’: ‘Australia/Sydney’, ‘ZBAA’: ‘Asia/Shanghai’, ‘ZGGG’: ‘Asia/Shanghai’, ‘ZGSZ’: ‘Asia/Shanghai’, ‘ZHCC’: ‘Asia/Shanghai’, ‘ZHHH’: ‘Asia/Shanghai’, ‘ZSJN’: ‘Asia/Shanghai’, ‘ZSPD’: ‘Asia/Shanghai’, ‘ZSQD’: ‘Asia/Shanghai’, ‘ZUCK’: ‘Asia/Shanghai’, ‘ZUUU’: ‘Asia/Shanghai’}”

Phase 3.1 international ICAOs — 40 stations covering the markets Polymarket lists as of v0.1.0 scope. Each entry maps the ICAO to its IANA timezone (needed for station-local calendar-day extremes).

This mapping is the legacy shape (icao -> tz string); the full StationInfo (with lat/lon/country) lives in _internal/_stations. Kept as a thin convenience view so callers that only need the tz lookup do not have to construct StationInfo.

mostlyright.international.daily_extremes(station, from_date, to_date, , merge=‘live_v1’, backend=‘pandas’, return_type=‘list’)

Section titled “mostlyright.international.daily_extremes(station, from_date, to_date, , merge=‘live_v1’, backend=‘pandas’, return_type=‘list’)”

Roll up cached hourly observations to per-local-day temperature extremes.

Reads from the parquet cache (mostlyright.weather.cache.read_cache) one calendar month at a time, converts each row’s observed_at from UTC to the station’s IANA local date, and aggregates per (station, local_date).

The function never touches the network — it is purely a rollup over whatever observations the cache already has. Callers are expected to have run mostlyright.research() (or another fetcher) first to warm the cache.

  • Parameters:

    • station (str) – 4-letter ICAO (e.g. "EGLL", "KNYC") or 3-letter NWS code ("NYC"). Resolved to a StationInfo to look up the IANA timezone and the country (which gates rounding precision).
    • from_date (date) – Inclusive local-calendar-day start.
    • to_date (date) – Inclusive local-calendar-day end.
    • merge (str) – Merge policy. Only "live_v1" is supported in v0.1.0; anything else raises ValueError.
    • backend (str) – Output frame backend, {"pandas", "polars"} (default "pandas"). "polars" requires return_type="wrapper" (polars frames carry no df.attrs provenance). Part of the unified output convention (Phase 30 D-06); validated via the shared validate_backend_kwargs gate.
    • return_type (str) – Output shape, {"list", "dataframe", "wrapper"}. Defaults to “”list”“ for this function — a no-arg call returns list[dict] (byte-stable, D-12/D-15), unlike the DataFrame-default surfaces. "dataframe" returns a pandas.DataFrame; "wrapper" returns a MostlyRightResult. daily_extremes has no as_dataframe knob — it was born on the winning backend/return_type convention.
  • Return type: list[dict[str, Any]]

  • Returns: list[dict] with one entry per local calendar day in [from_date, to_date] that had at least one cached observation. Each dict matches the schema.daily_extreme.v1 JSON Schema:

    • station (str, ICAO)
    • local_date (str, YYYY-MM-DD)
    • n_obs (int)
    • tmin_c / tmax_c / tmean_c (float or None)
    • precip_inches (float)
    • source_tmin / source_tmax (str or None)
    • country (str, informational)

    Days with n_obs < 12 have tmin_c=tmax_c=tmean_c=None and a WARNING is logged with the low_coverage keyword.

  • Raises:

>>> from datetime import date
>>> # After warming the cache via research(), roll up two days.
>>> rows = daily_extremes("EGLL", date(2025, 1, 1), date(2025, 1, 2))
>>> [r["local_date"] for r in rows]
['2025-01-01', '2025-01-02']