Migration
→ v1.13
v1.13 unifies the observation API onto one surface: dataset() is the composed training table, domain tables (obs(), the new climate(), forecasts(), satellite(), cwop.*) are the raw source-identified ingredients, and the numbered-mode era starts its deprecation train. Every existing entry point is byte-stable at runtime this release — nothing you call today returns different data.
The kwarg contract behind all of this lives in Source identity.
What changed
Section titled “What changed”| Surface | Before | v1.13 |
|---|---|---|
| Primary composer | research(...) | dataset(...) — research() is a fully working alias bound to the same callable (dataset is research) |
| Per-report observations | research_by_source(source, ...) (mostlyright.mode2) | obs(source=..., granularity="observation") |
| Standalone climate labels | only inside the dataset() join | climate(station, start, end) — a first-class domain table |
| Output shape knob | as_dataframe=True/False | return_type="dataframe" | "list" | "wrapper" |
assert_source_identity home | mostlyright.mode2 | mostlyright.core (re-exported) |
| Covariate columns | manual hand-join | dataset(include_satellite=, include_cwop=) (labels byte-identical, defaults off) |
dataset() — the primary composer
Section titled “dataset() — the primary composer”dataset() is the new canonical name for the leakage-safe training join. research() stays as a fully working alias — same callable, byte-identical output, no deprecation warning this release.
import mostlyright
# New canonical namedf = mostlyright.dataset("KNYC", "2025-01-06", "2025-01-12")
# research() is the same callable — no warning this releasesame = mostlyright.research("KNYC", "2025-01-06", "2025-01-12")assert mostlyright.dataset is mostlyright.researchimport { dataset, research } from "mostlyright";
// dataset === research — same callable, no warning on researchconst rows = await dataset("KNYC", "2025-01-06", "2025-01-12");Start using dataset() in new code. research() keeps working — it gains its own DeprecationWarning in a later release (1.14.x+) and is removed at 2.0.
Pinned features are a retrain event
Section titled “Pinned features are a retrain event”The deprecation message on research_by_source() points at the new pinned path:
# old (deprecated, still works, still byte-identical to 1.12.x)from mostlyright.mode2 import research_by_sourcerows = research_by_source("iem.archive", "KNYC", "2025-01-06", "2025-01-12")
# newfrom mostlyright.weather import obsrows = obs("KNYC", "2025-01-06", "2025-01-12", source="iem.archive", granularity="observation")These two calls do NOT return the same row set, by design:
research_by_source()filters post-merge: the AWC > IEM > GHCNh fusion runs first, then rows from your pinned source are selected from the fused result. Rows your source reported but the merge superseded (because a higher-priority source covered the same timestamp) are absent.obs(source=..., granularity="observation")fetches pre-merge via the source-isolated exact-window path: you get your source’s full coverage for the window — typically more rows, and a different per-day composition.
A feature pipeline built on the old post-merge rows and re-pointed at the new pre-merge rows will produce different aggregates, different distributions, and therefore a different model. Do not swap the call in a production strategy and keep trading. Treat the swap like a data-source change:
- Rebuild the training frame on the new path.
- Retrain.
- Re-backtest against settlements.
- Only then promote.
If you are not ready to retrain, do nothing: research_by_source() keeps its exact post-merge behavior for the whole deprecation window (≥2 minor releases). The warning is a schedule, not a behavior change.
The same logic applies to the new covariate flags: adding include_satellite=True / include_cwop=True to dataset() never changes label columns (byte-identical on vs off), but a model that starts consuming sat_*/cwop_* columns is a new model. Retrain deliberately.
Compatibility table
Section titled “Compatibility table”Byte-stable at runtime — no action, no warning
Section titled “Byte-stable at runtime — no action, no warning”| Surface | Status in v1.13 |
|---|---|
dataset() / research() default path | Identical output; dataset is research (same callable). research() emits no warning this release. |
research_by_source(...) behavior | Output byte-identical to 1.12.x (keeps its post-merge path). Only a warning is added. |
obs(...) daily default | granularity="daily" is the Python default; no-argument calls unchanged. |
live.latest / live.stream, snapshot | Untouched. |
| Merge semantics, cache layout, CWOP firewall | Frozen (parity gate green; the four firewall files are unchanged). |
| Default no-argument returns of every function | Preserved verbatim. |
Warns (DeprecationWarning), behaves identically — migrate within ≥2 minors
Section titled “Warns (DeprecationWarning), behaves identically — migrate within ≥2 minors”| Deprecated | Replacement | Notes |
|---|---|---|
research_by_source(...) (call-time warning) | obs(source=..., granularity="observation") | Retrain event — see above. |
import mostlyright.mode2 (import-path warning, once per session) | obs(...) from mostlyright.weather; assert_source_identity from mostlyright.core | assert_source_identity’s canonical home is now mostlyright.core (same object, re-exported). |
as_dataframe= on dataset()/research(), research_by_source(), obs() | return_type= (True → "dataframe", False → "list") | An explicit return_type= wins when both are passed (still warns). |
New and optional — adopt when ready
Section titled “New and optional — adopt when ready”| Surface | What it is |
|---|---|
dataset() | Canonical name for the training join. Start using it in new code. |
obs(granularity="observation") | Per-report merged rows, window-trimmed, observation_type + raw_metar surfaced; unpinned frames tagged merged.live_v1 (only schema.observation.merged.v1 accepts them). |
climate(station, start, end) | Standalone NWS CLI settlement-label table (JOIN vocabulary: cli_high_f/cli_low_f/cli_report_type), frame tag cli.archive, per-row source iem. |
dataset(include_satellite=, include_cwop=) | Labels-only covariate columns (sat_*, cwop_*), LEFT-joined per LST settlement day; needs the [satellite]/[cwop] extras; missing extras fail loud. |
backend= + return_type= everywhere | The one output convention going forward. |
Production warning filters (-W error)
Section titled “Production warning filters (-W error)”If your pipeline promotes warnings to errors (python -W error::DeprecationWarning, filterwarnings = ["error"] in pytest, etc.), v1.13 will surface the new DeprecationWarnings as failures at:
- any
research_by_source()call, - any
mostlyright.mode2attribute access (once per session), - any explicit
as_dataframe=argument.
Either migrate those call sites first, or add a targeted allowlist while you complete the migration window:
import warningswarnings.filterwarnings( "default", category=DeprecationWarning, module=r"mostlyright(\..*)?",)research() itself emits nothing this release, so the most common production entry point is unaffected.
TypeScript notes
Section titled “TypeScript notes”datasetalias:import { dataset } from "mostlyright"—dataset === research, same callable, no warning onresearch.obs()granularity default DIVERGES from Python (deliberate): TSobs()defaults togranularity: "observation"— the per-report rows TS has always returned — so existing TS callers stay byte-stable.granularity: "daily"is not yet ported in TS and throws a documented error (parity ticket filed); it never silently returns per-report rows. Python’s default remains"daily". If you run both SDKs, passgranularityexplicitly at the seam.climate()lives at a subpath:import { climate } from "@mostlyrightmd/weather/climate"(not the root barrel — browser bundle-budget adaptation). Output matches Python’s column contract; station codes resolve NWS↔ICAO identically.MODE2_*renamed with aliases:SOURCE_PINNED_SOURCES/SourcePinnedSource/isSourcePinnedSourceare canonical;MODE2_SOURCES/Mode2Source/isMode2Sourceremain as deprecated aliases binding the same values (removal at 2.0).return_type:"dataframe"is canonical;"frame"stays as a back-compat alias.
Deprecation timeline
Section titled “Deprecation timeline”| Release | What happens |
|---|---|
| v1.13 (this release) | Warnings added; zero behavior change. |
| 1.14.x+ | research() gains its DeprecationWarning (alias keeps working). |
| ≥2 minors out | Earliest removal window for research_by_source, mostlyright.mode2, as_dataframe. |
| 2.0 | Removals land; TS MODE2_* aliases removed. |
See also
Section titled “See also”- Source identity — the cross-vertical
source=/delivery=/ grain contract, frame-vs-row identity, and the labels-only covariate firewall. - Research API — the
dataset()surface in full. - Changelog — the complete change list for v1.13.