# How this library was generated Every subpackage under `action0.open_meteo` — the clients, the operation classes, the enums, the models and their JSON converters — was generated by [action0-client-openapi](https://laughinjar.github.io/action0-client-openapi/) from Open-Meteo's OpenAPI schemas, and is checked in like hand-written code. This page is the worked example of that generator: exactly what we ran, and what came out. ## The schemas Open-Meteo publishes one OpenAPI 3.1 document per service in the [open-meteo/open-meteo](https://github.com/open-meteo/open-meteo/tree/main/openapi) repository. The nine documents are vendored under `schemas/` (pinned to an upstream commit — `schemas/README.md` records which). The Geocoding API has no upstream schema, so `schemas/geocoding.yml` was written for this project against the API docs and live responses — authoring a small OpenAPI file and generating from it beats hand-writing a client. ## The generation runs `tools/regenerate.sh` runs the generator once per schema — the whole script is ten calls of this shape: ```shell uv run action0-openapi schemas/forecast.yml \ -o src/action0/open_meteo \ --package-name forecast \ --client-name ForecastClient \ --force ``` `--package-name` and `--client-name` override the defaults derived from the schema's `info.title` (which would have been the mouthful `open_meteo_weather_forecast_api_client` / `OpenMeteoWeatherForecastApiClient`). Everything else comes from the schema itself: - **The base URL.** Open-Meteo declares its `servers` per *path*, not at the document level; the generator falls back to them, so `ForecastClient` defaults to `https://api.open-meteo.com` and `AirQualityClient` to `https://air-quality-api.open-meteo.com` — no `--base-url` flags needed. - **Enums for the weather variables.** `hourly=temperature_2m,rain`-style parameters are enum arrays in the schema, so the generated fields are `list[GetV1ForecastHourlyItem]` and your IDE completes the legal values. - **Typed dynamic keys.** The ensemble and seasonal APIs answer with per-member keys (`temperature_2m_member01`, ...) declared as `additionalProperties`; the generated models collect them in a typed catch-all field: `additional_properties: dict[str, list[float]]`. - **Dates.** `start_date`/`end_date` parameters are `format: date`, so the fields are `datetime.date` and serialize to ISO 8601. - **Comma-joined variable lists.** The schemas declare `explode: false` on the array parameters, so the generated fields carry a `serialize=` join lambda — the request says `hourly=temperature_2m,rain`, Open-Meteo's documented form. - **Typed errors.** The documented 400 answers (`{"error": true, "reason": ...}`) become an `errors.py` per package: a `BadRequestError` subclassing `action0.client.APIError`, raised by the operations' generated `check()` with the parsed payload as `.error`. Each run writes one package: `client.py`, `operations.py`, `models.py`, `errors.py`, `__init__.py` (re-exporting everything) and `py.typed`, each file headed by a `generated by action0-client-openapi vX.Y.Z from forecast.yml — do not edit` line. ## Living with generated code The generated packages are treated exactly like hand-written code — reviewed in PRs, type-checked strictly (mypy `--strict`, pyright and ty run over them in CI) and linted (they come out of the generator already `ruff format`-clean). What is *not* done is editing them by hand: when Open-Meteo's schemas change, we re-vendor them, run `bash tools/regenerate.sh`, and review the diff — hand edits would be lost on the next regeneration, which the `do not edit` headers are there to remind you of. Hand-written code (the tests, the examples, the docs) lives outside the generated packages. This project also feeds back the other way: generating it surfaced three generator gaps — the `additionalProperties` catch-all, the path-level `servers` fallback and a naming fix (`get_v_1_...` → `get_v1_...`) — all fixed in action0-client-openapi 0.1.1 before this library was first generated. A second round followed the same day: honoring `explode: false` and generating typed error exceptions landed in 0.1.2, and this library picked both up by regenerating — the diff was reviewed like any other change.