# therminal-py

Python SDK for Therminal — Kalshi temperature prediction markets + NWS weather data + live METAR signaling.
Wraps the REST API at `https://api.mostlyright.xyz`. WeatherLive fetches directly from AWC (aviationweather.gov).

## Stack
- Python 3.11+, httpx (HTTP client), tomllib (config)
- Optional: pandas + pyarrow (DataFrame support), scikit-learn (ML), torch (PyTorch), typer + rich (CLI)

## Project Layout
```
src/therminal/
  __init__.py          # Public API re-exports (backward compat)
  client.py            # TherminalClient facade (composes WeatherHistory + MarketsClient)
  config.py            # TherminalConfig — TOML + env + kwargs layered defaults
  _http.py             # HttpSession composition class (shared HTTP logic)
  _convert.py          # Unit conversion with Go-matched rounding (WeatherLive only)
  _version.py          # Version string ("1.0.3")
  exceptions.py        # Error hierarchy (NotFoundError, RateLimitError, etc.)
  cli.py               # Optional CLI (typer)
  models/
    _base.py           # DictLikeMixin, _to_int, _to_float shared utilities
    observation.py     # Observation dataclass (29 fields, THE schema contract)
    candle.py          # Candle dataclass
    market.py          # Market, Series dataclasses
    climate.py         # Climate dataclass
    lob.py             # LOBSnapshot, Level dataclasses
  weather/
    client.py          # WeatherHistory (observations, climate, climate_gaps via API)
    live.py            # WeatherLive (real-time METAR from AWC, batch support)
    _awc.py            # AWC field mapping (ported from therminal-ingest/awc-client.ts)
  markets/
    client.py          # MarketsClient (series, markets, candles, lob via API)
  ml/
    features.py        # WeatherFeatures sklearn transformer
    lob.py             # LOBFeatures sklearn transformer
    cache.py           # Local disk cache
    torch.py           # TherminalDataset (PyTorch)
tests/
  test_client.py       # TherminalClient facade tests (30 tests)
  test_models.py       # Observation + other model tests (24 tests)
  test_awc.py          # AWC field mapping tests (25 tests)
  test_config.py       # Config loading + resolution tests (18 tests)
  test_convert.py      # Unit conversion tests (25 tests)
  test_live.py         # WeatherLive tests (11 tests)
  test_parity.py       # Schema parity test — AWC vs API (5 tests)
  test_backward_compat.py  # v0.5.0 import compat (10 tests)
  test_ml.py           # WeatherFeatures tests (18 tests)
  test_ml_lob.py       # LOBFeatures tests (18 tests)
```

## Commands
```bash
source .venv/bin/activate
pytest tests/ -v                     # Run tests (186 tests)
pytest tests/ --cov=therminal        # With coverage (80%)
ruff check src/ tests/               # Lint
python -m build                      # Build package
python -m therminal.cli health       # CLI
```

## Architecture
- **WeatherHistory** — historical observations/climate via therminal-api (unit conversion server-side)
- **WeatherLive** — real-time METAR from AWC (unit conversion client-side via _convert.py)
- **MarketsClient** — series/markets/candles/lob via therminal-api
- **TherminalClient** — backward-compat facade composing Weather + Markets
- **HttpSession** — shared HTTP logic via composition (not inheritance)
- **TherminalConfig** — 4-layer resolution: built-in < ~/.therminal.toml < env vars < kwargs
- **DictLikeMixin** — all dataclasses support obs["field"], obs.get("field"), obs.field

## Coding Rules
- All methods return typed dataclasses by default, DataFrame with `as_dataframe=True`
- Dict-style access (obs["temp_f"]) preserved for backward compat
- Never mutate input parameters (frozen dataclasses, immutable config)
- All HTTP errors mapped to specific exceptions
- Date params accept both YYYY-MM-DD and RFC3339 (auto-normalized)
- Go-matched rounding (round-half-away-from-zero) in _convert.py and _awc.py
- sea_level_pressure_mb is NOT converted (already metric)
- observed_at uses strftime('%Y-%m-%dT%H:%M:%SZ'), not isoformat()
- Pandas is optional — ImportError with helpful message if missing

## Testing
```bash
pytest tests/ -v                     # 186 tests, 80% coverage
```
- Schema parity test: Observation.from_api_dict() and from_awc_json() produce identical output
- Real AWC + API fixtures in tests/fixtures_*.json
- pytest-httpx for mocking API calls, unittest.mock for WeatherLive AWC calls
