Skip to content

mostlyright.weather.obs

mostlyright.weather.obs(station, start, end, , source=None, strategy=‘auto’, granularity=‘daily’, as_dataframe=None, backend=‘pandas’, return_type=‘dataframe’, tz_override=None)

Section titled “mostlyright.weather.obs(station, start, end, , source=None, strategy=‘auto’, granularity=‘daily’, as_dataframe=None, backend=‘pandas’, return_type=‘dataframe’, tz_override=None)”

Return observation data for station over [start, end].

Returns default fused-source aggregates merged via SOURCE_PRIORITY (AWC > IEM > GHCNh). granularity chooses the row level.

  • Parameters:
    • station (str) – ICAO code (e.g. "KNYC") or 3-letter NWS code.

    • start (str) – ISO date strings (YYYY-MM-DD), inclusive bounds.

    • end (str) – ISO date strings (YYYY-MM-DD), inclusive bounds.

    • source ( {“iem” , “ghcnh” , “awc”} | None , keyword-only) – If set, only that source is queried; the other two fetchers are skipped. If None, all three are queried and merged with the standard priority (AWC > IEM > GHCNh).

    • granularity ( {“daily” , “observation”} , keyword-only , default “daily”) –

      Row level of the result.

      • "daily" (default): one row per LST settlement day — the obs_* aggregate subset (obs_high_f, obs_low_f, obs_mean_f, …). Behaviour is byte-unchanged from prior releases.

      • "observation": the merged per-report rows (native METAR/SPECI + sub-hourly cadence), trimmed to the queried UTC window, pass-through with observation_type and raw_metar preserved — NO bucketing/resampling. Each row’s source column is the truthful bare parser tag (awc/iem/ghcnh); the FRAME identity (df.attrs["source"]) is "merged.live_v1" when unpinned, or the bare source when source= is pinned. Fixed-cadence resampling (exact-hourly, 30-min, …) is a separate preprocessing transform, not a granularity value.

        Each observation-grain row also carries a settlement_date column (D-19) — the ISO YYYY-MM-DD of the LST settlement day the report belongs to (via the snapshot settlement machinery, never a raw UTC-day slice). This is the ergonomic key for grouping/joining reports by their settlement day (and the internal join key dataset(granularity="observation") uses).

    • strategy ( {“auto” , “exact_window” , “warm_cache” , “hosted”} , keyword-only) – Advanced/documented escape hatch — ordinary users never type it. "auto" (the default) self-selects the right tactic, including the source-isolated exact_window path for any pinned source= query. The default ships as "auto" and never churns between releases.

    • as_dataframe (bool | None , keyword-only , default None) – DEPRECATED (Phase 30 D-06) — use return_type instead (True"dataframe", False"list"). Passing it explicitly emits a DeprecationWarning; when both are supplied an explicit return_type wins. Left unset (default), return_type governs and a no-arg call still returns a pandas.DataFrame.

    • backend ( {“pandas” , “polars”} , keyword-only , default “pandas”) – Output frame backend. "polars" requires return_type="wrapper" (polars frames carry no df.attrs provenance). Validated via the shared validate_backend_kwargs gate.

    • return_type ( {“dataframe” , “list” , “wrapper”} , keyword-only , default “dataframe”) – Output shape: raw pandas.DataFrame (default), plain list[dict] of rows, or a MostlyRightResult wrapper carrying provenance.

    • tz_override (str | None , keyword-only , default None) – IANA timezone name override for stations outside the built-in registry. Threaded to the settlement-date machinery (mostlyright.snapshot.settlement_date_for()) used for daily bucketing and for the settlement_date column at granularity="observation". Rarely needed for the US registry.

  • Returns: Daily obs_* aggregate rows (granularity="daily") or merged per-report rows (granularity="observation"). Shape follows return_type.
  • Return type: pd.DataFrame | list[dict]
  • Raises:
    • ValueError – If source, strategy, or granularity is not in its allowed Literal set, OR if strategy="warm_cache" is called with source != None (post-merge filtering would corrupt SOURCE_PRIORITY semantics; use strategy="exact_window" for single-source queries).
    • DataAvailabilityError – If strategy="hosted" (the precomputed-API seam deferred to v0.2.x).
  • obs() does NOT return CLI climate columns (cli_high_f, cli_low_f, fcst_*). If you need joined obs + CLI + forecast, use research() directly.
  • The "auto" router’s warm_cache tactic produces daily aggregates byte-equivalent to research() for obs_high_f, obs_low_f, obs_high_at, obs_low_at, source (verified against the 5 Phase 1 parity fixtures in tests/weather/test_obs_warm_cache_parity.py). The exact_window tactic matches those values at the row level but intentionally bypasses year-aligned caching, so its cache footprint and fetch URLs differ.
>>> from mostlyright.weather import obs
>>> df = obs("KNYC", "2024-03-01", "2024-03-31", source="iem")
>>> hourly = obs("KNYC", "2024-03-01", "2024-03-31",
... granularity="observation")