mostlyright.core.schemas.observation
mostlyright.core.schemas.observation
Section titled “mostlyright.core.schemas.observation”Canonical METAR/SPECI observation schema (schema.observation.v1).
Mirrors the §A “Observations schema” table in docs/design.md exactly:
20 metric columns, with the imperial-mode rename map preserving the
mostly-light/metar_parser.py 9-column contract as its projection.
Adapters (IEM, AWC) normalise their raw responses to these columns before
emitting rows. source, knowledge_time and retrieved_at are
overlay columns added by the schema layer (not part of COLUMNS); they
are stamped on every fetch and validated independently.
Classes
Section titled “Classes”ObservationSchema() | schema.observation.v1 — canonical METAR/SPECI rows. |
|---|
class mostlyright.core.schemas.observation.ObservationSchema
Section titled “class mostlyright.core.schemas.observation.ObservationSchema”Bases: Schema
schema.observation.v1 — canonical METAR/SPECI rows.
Metric column set per docs/design.md §A; imperial-mode rename map
per the same section preserves the existing mostly-light contract
(the 9-column anti-duplication projection: station, utc_datetime, temp_F, dew_point_F, slp_hpa, wind_speed_kt, wind_dir_deg, gust_kt, vsby). slp_hpa is canonical aviation units and unchanged across
modes; wind_dir_deg is dimensionless degrees.
COLUMNS : ClassVar[list[ColumnSpec]] = [ColumnSpec(name=‘station’, dtype=‘string’, units=None, nullable=False, enum_values=None, notes=‘ICAO/ASOS station ID (e.g. KORD)’), ColumnSpec(name=‘event_time’, dtype=‘timestamp_utc’, units=None, nullable=False, enum_values=None, notes=‘observation valid time’), ColumnSpec(name=‘observation_type’, dtype=‘enum’, units=None, nullable=False, enum_values=(‘METAR’, ‘SPECI’), notes=“METAR | SPECI; defaults METAR when source can’t distinguish (e.g. AWC JSON)”), ColumnSpec(name=‘temp_c’, dtype=‘float64’, units=‘celsius’, nullable=True, enum_values=None, notes=‘bounded TEMP_MIN_C..TEMP_MAX_C’), ColumnSpec(name=‘dew_point_c’, dtype=‘float64’, units=‘celsius’, nullable=True, enum_values=None, notes=‘bounded’), ColumnSpec(name=‘wind_speed_ms’, dtype=‘float64’, units=‘m/s’, nullable=True, enum_values=None, notes=‘converted from kt’), ColumnSpec(name=‘wind_dir_deg’, dtype=‘int64’, units=‘degrees’, nullable=True, enum_values=None, notes=‘0-360, bounded’), ColumnSpec(name=‘wind_gust_ms’, dtype=‘float64’, units=‘m/s’, nullable=True, enum_values=None, notes=‘converted from kt’), ColumnSpec(name=‘slp_hpa’, dtype=‘float64’, units=‘hPa’, nullable=True, enum_values=None, notes=‘sea-level pressure (canonical aviation unit, not converted across modes)’), ColumnSpec(name=‘visibility_m’, dtype=‘float64’, units=‘meters’, nullable=True, enum_values=None, notes=‘converted from statute miles’), ColumnSpec(name=‘precip_mm_1h’, dtype=‘float64’, units=‘mm’, nullable=True, enum_values=None, notes=‘hourly precip (METAR p01i, converted from inches)’), ColumnSpec(name=‘sky_cover_1’, dtype=‘enum’, units=None, nullable=True, enum_values=(‘CLR’, ‘FEW’, ‘SCT’, ‘BKN’, ‘OVC’, ‘VV’), notes=‘first cloud layer cover code’), ColumnSpec(name=‘sky_base_1_m’, dtype=‘float64’, units=‘meters’, nullable=True, enum_values=None, notes=‘first cloud layer base height (converted from feet)’), ColumnSpec(name=‘sky_cover_2’, dtype=‘enum’, units=None, nullable=True, enum_values=(‘CLR’, ‘FEW’, ‘SCT’, ‘BKN’, ‘OVC’, ‘VV’), notes=‘second layer; null if not present’), ColumnSpec(name=‘sky_base_2_m’, dtype=‘float64’, units=‘meters’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘sky_cover_3’, dtype=‘enum’, units=None, nullable=True, enum_values=(‘CLR’, ‘FEW’, ‘SCT’, ‘BKN’, ‘OVC’, ‘VV’), notes=‘third layer; null if not present’), ColumnSpec(name=‘sky_base_3_m’, dtype=‘float64’, units=‘meters’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘sky_cover_4’, dtype=‘enum’, units=None, nullable=True, enum_values=(‘CLR’, ‘FEW’, ‘SCT’, ‘BKN’, ‘OVC’, ‘VV’), notes=‘fourth layer; null if not present’), ColumnSpec(name=‘sky_base_4_m’, dtype=‘float64’, units=‘meters’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘metar_raw’, dtype=‘string’, units=None, nullable=True, enum_values=None, notes=‘raw METAR text if source has it; null for AWC JSON (structured-only)’)]
Section titled “COLUMNS : ClassVar[list[ColumnSpec]] = [ColumnSpec(name=‘station’, dtype=‘string’, units=None, nullable=False, enum_values=None, notes=‘ICAO/ASOS station ID (e.g. KORD)’), ColumnSpec(name=‘event_time’, dtype=‘timestamp_utc’, units=None, nullable=False, enum_values=None, notes=‘observation valid time’), ColumnSpec(name=‘observation_type’, dtype=‘enum’, units=None, nullable=False, enum_values=(‘METAR’, ‘SPECI’), notes=“METAR | SPECI; defaults METAR when source can’t distinguish (e.g. AWC JSON)”), ColumnSpec(name=‘temp_c’, dtype=‘float64’, units=‘celsius’, nullable=True, enum_values=None, notes=‘bounded TEMP_MIN_C..TEMP_MAX_C’), ColumnSpec(name=‘dew_point_c’, dtype=‘float64’, units=‘celsius’, nullable=True, enum_values=None, notes=‘bounded’), ColumnSpec(name=‘wind_speed_ms’, dtype=‘float64’, units=‘m/s’, nullable=True, enum_values=None, notes=‘converted from kt’), ColumnSpec(name=‘wind_dir_deg’, dtype=‘int64’, units=‘degrees’, nullable=True, enum_values=None, notes=‘0-360, bounded’), ColumnSpec(name=‘wind_gust_ms’, dtype=‘float64’, units=‘m/s’, nullable=True, enum_values=None, notes=‘converted from kt’), ColumnSpec(name=‘slp_hpa’, dtype=‘float64’, units=‘hPa’, nullable=True, enum_values=None, notes=‘sea-level pressure (canonical aviation unit, not converted across modes)’), ColumnSpec(name=‘visibility_m’, dtype=‘float64’, units=‘meters’, nullable=True, enum_values=None, notes=‘converted from statute miles’), ColumnSpec(name=‘precip_mm_1h’, dtype=‘float64’, units=‘mm’, nullable=True, enum_values=None, notes=‘hourly precip (METAR p01i, converted from inches)’), ColumnSpec(name=‘sky_cover_1’, dtype=‘enum’, units=None, nullable=True, enum_values=(‘CLR’, ‘FEW’, ‘SCT’, ‘BKN’, ‘OVC’, ‘VV’), notes=‘first cloud layer cover code’), ColumnSpec(name=‘sky_base_1_m’, dtype=‘float64’, units=‘meters’, nullable=True, enum_values=None, notes=‘first cloud layer base height (converted from feet)’), ColumnSpec(name=‘sky_cover_2’, dtype=‘enum’, units=None, nullable=True, enum_values=(‘CLR’, ‘FEW’, ‘SCT’, ‘BKN’, ‘OVC’, ‘VV’), notes=‘second layer; null if not present’), ColumnSpec(name=‘sky_base_2_m’, dtype=‘float64’, units=‘meters’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘sky_cover_3’, dtype=‘enum’, units=None, nullable=True, enum_values=(‘CLR’, ‘FEW’, ‘SCT’, ‘BKN’, ‘OVC’, ‘VV’), notes=‘third layer; null if not present’), ColumnSpec(name=‘sky_base_3_m’, dtype=‘float64’, units=‘meters’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘sky_cover_4’, dtype=‘enum’, units=None, nullable=True, enum_values=(‘CLR’, ‘FEW’, ‘SCT’, ‘BKN’, ‘OVC’, ‘VV’), notes=‘fourth layer; null if not present’), ColumnSpec(name=‘sky_base_4_m’, dtype=‘float64’, units=‘meters’, nullable=True, enum_values=None, notes=”), ColumnSpec(name=‘metar_raw’, dtype=‘string’, units=None, nullable=True, enum_values=None, notes=‘raw METAR text if source has it; null for AWC JSON (structured-only)’)]”IMPERIAL_RENAMES : ClassVar[dict[str, str]] = {‘dew_point_c’: ‘dew_point_F’, ‘event_time’: ‘utc_datetime’, ‘precip_mm_1h’: ‘precip_in_1h’, ‘sky_base_1_m’: ‘sky_base_1_ft’, ‘sky_base_2_m’: ‘sky_base_2_ft’, ‘sky_base_3_m’: ‘sky_base_3_ft’, ‘sky_base_4_m’: ‘sky_base_4_ft’, ‘temp_c’: ‘temp_F’, ‘visibility_m’: ‘vsby’, ‘wind_gust_ms’: ‘gust_kt’, ‘wind_speed_ms’: ‘wind_speed_kt’}
Section titled “IMPERIAL_RENAMES : ClassVar[dict[str, str]] = {‘dew_point_c’: ‘dew_point_F’, ‘event_time’: ‘utc_datetime’, ‘precip_mm_1h’: ‘precip_in_1h’, ‘sky_base_1_m’: ‘sky_base_1_ft’, ‘sky_base_2_m’: ‘sky_base_2_ft’, ‘sky_base_3_m’: ‘sky_base_3_ft’, ‘sky_base_4_m’: ‘sky_base_4_ft’, ‘temp_c’: ‘temp_F’, ‘visibility_m’: ‘vsby’, ‘wind_gust_ms’: ‘gust_kt’, ‘wind_speed_ms’: ‘wind_speed_kt’}”Metric → imperial column-name map (docs §A imperial-mode table).
station, observation_type, wind_dir_deg, slp_hpa,
sky_cover_N and metar_raw are unchanged across modes.