noaa-apiroute 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- noaa_apiroute-0.1.0/.agent/skills/apiroute-client.md +199 -0
- noaa_apiroute-0.1.0/.github/workflows/build.yml +62 -0
- noaa_apiroute-0.1.0/.github/workflows/ci.yml +53 -0
- noaa_apiroute-0.1.0/.github/workflows/release.yml +103 -0
- noaa_apiroute-0.1.0/.gitignore +9 -0
- noaa_apiroute-0.1.0/AGENT.md +53 -0
- noaa_apiroute-0.1.0/CHANGELOG.md +8 -0
- noaa_apiroute-0.1.0/CLAUDE.md +7 -0
- noaa_apiroute-0.1.0/LICENSE +21 -0
- noaa_apiroute-0.1.0/PKG-INFO +181 -0
- noaa_apiroute-0.1.0/README.md +149 -0
- noaa_apiroute-0.1.0/apis.yaml +46 -0
- noaa_apiroute-0.1.0/pyproject.toml +60 -0
- noaa_apiroute-0.1.0/scripts/generate.py +152 -0
- noaa_apiroute-0.1.0/scripts/next_release.py +138 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/__init__.py +11 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/auth.py +47 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/__init__.py +6 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/client.py +319 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/client.py +329 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/models.py +318 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/air_sigmet_geo_json.py +19 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/air_sigmet_geo_json_features_item.py +22 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/air_sigmet_geo_json_features_item_geometry.py +17 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/air_sigmet_geo_json_features_item_properties.py +30 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/air_sigmet_json.py +12 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/air_sigmet_json_value_item.py +45 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/airmet_geo_json.py +19 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/airmet_geo_json_features_item.py +22 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/airmet_geo_json_features_item_geometry.py +17 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/airmet_geo_json_features_item_properties.py +25 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/airmet_json.py +12 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/airmet_json_value_item.py +22 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/cloud_info.py +13 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/cloud_info_value_item.py +26 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/cwa_geo_json.py +19 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/cwa_geo_json_features_item.py +22 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/cwa_geo_json_features_item_geometry.py +17 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/cwa_geo_json_features_item_properties.py +29 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/cwa_json.py +12 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/cwa_json_value_item.py +34 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/error_json.py +17 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/error_xml.py +20 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/error_xml_request.py +14 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/gairmet_geo_json.py +19 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/gairmet_geo_json_features_item.py +22 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/gairmet_geo_json_features_item_geometry.py +17 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/gairmet_geo_json_features_item_properties.py +23 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/gairmet_json.py +12 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/gairmet_json_value_item.py +31 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/i_sigmet_geo_json.py +19 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/i_sigmet_geo_json_features_item.py +22 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/i_sigmet_geo_json_features_item_geometry.py +17 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/i_sigmet_geo_json_features_item_properties.py +27 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/i_sigmet_json.py +12 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/i_sigmet_json_value_item.py +43 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/meta_rproperties.py +115 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/meta_rtext.py +11 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/metar_geo_json.py +19 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/metar_geo_json_features_item.py +22 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/metar_geo_json_features_item_geometry.py +17 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/metarjson.py +12 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/metarxml.py +26 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/metarxml_data_item.py +53 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/metarxml_data_item_quality_control_flags.py +14 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/metarxml_data_source.py +16 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/metarxml_request.py +16 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/navigational_data_get_api_data_airport_response_item.py +29 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/navigational_data_get_api_data_fix_response_item.py +17 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/navigational_data_get_api_data_navaid_response_item.py +23 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/pire_ptext.py +10 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/pirep_geo_json.py +19 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/pirep_geo_json_features_item.py +22 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/pirep_geo_json_features_item_geometry.py +17 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/pirep_geo_json_features_item_properties.py +58 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/pirepjson.py +12 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/pirepjson_value_item.py +130 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/pirepxml.py +26 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/pirepxml_data_item.py +44 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/pirepxml_data_item_icing_condition.py +18 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/pirepxml_data_item_turbulence_condition.py +18 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/pirepxml_data_source.py +16 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/pirepxml_request.py +16 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/sigmet_geo_json.py +19 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/sigmet_geo_json_features_item.py +22 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/sigmet_geo_json_features_item_geometry.py +17 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/sigmet_geo_json_features_item_properties.py +27 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/sigmet_json.py +12 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/sigmet_json_value_item.py +43 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/station_info_geo_json.py +19 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/station_info_geo_json_features_item.py +22 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/station_info_geo_json_features_item_geometry.py +17 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/station_info_geo_json_features_item_properties.py +40 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/station_info_json.py +12 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/station_info_json_value_item.py +46 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/station_info_xml.py +26 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/station_info_xml_data_item.py +26 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/station_info_xml_data_item_site_type.py +17 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/station_info_xml_data_source.py +16 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/station_info_xml_request.py +16 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/ta_fproperties.py +62 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/ta_fproperties_fcsts_item.py +77 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/ta_fproperties_fcsts_item_icg_turb_item.py +29 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/ta_fproperties_fcsts_item_temp_item.py +26 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/ta_ftext.py +10 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/taf_geo_json.py +19 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/taf_geo_json_features_item.py +24 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/taf_geo_json_features_item_geometry.py +17 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/tafjson.py +12 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/tcf_geo_json.py +22 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/tcf_geo_json_features_item.py +22 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/tcf_geo_json_features_item_geometry.py +17 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/aviation/models/schemas/tcf_geo_json_features_item_properties.py +27 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/py.typed +0 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/__init__.py +6 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/client.py +30 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/client.py +95 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/client.py +104 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/models.py +186 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/datums_horizontal.py +16 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/datums_notes.py +14 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/datums_vertical.py +16 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/flood_categories.py +19 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/flood_categories_datum.py +15 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/flood_crests.py +17 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/flood_crests_datum.py +18 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/flood_impact.py +15 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/flood_low_waters.py +16 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/flood_low_waters_datum.py +17 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_data_attribution.py +17 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_datums.py +20 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_datums_value.py +17 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_downloads.py +16 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_flood.py +26 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_flood_statements.py +15 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_gauge.py +76 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_gauge_pedts.py +15 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_gauge_photo_out.py +20 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_gauge_photo_out_geometry.py +15 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_gauge_photo_out_properties.py +15 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_gauge_rfc.py +17 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_gauge_state.py +17 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_gauge_status.py +18 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_gauge_wfo.py +17 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_get_stage_flow_all_response.py +17 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_hydronotes.py +16 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_images.py +20 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_impacts_low_waters.py +15 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_in_service.py +15 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_inundation.py +25 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_inundation_data_attribution.py +17 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_lids.py +14 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_list_gauges_response.py +16 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_list_gauges_response_gauge.py +28 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_low_threshold.py +15 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_lro.py +18 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_normal_threshold.py +15 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_pedts.py +15 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_raag_gauge_info.py +20 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_raag_response.py +17 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_ratings.py +18 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_rfc.py +15 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_state.py +15 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_status_forecast.py +19 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_status_observed.py +19 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_stream.py +15 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_upstream_downstream.py +18 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_wfo.py +15 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/gauge_zero_datum.py +15 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/images_hydrograph.py +15 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/images_probability.py +19 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/probability_entperiod.py +16 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/probability_weekint.py +16 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/gauges/models/schemas/ratings_rating.py +15 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/health/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/health/client.py +28 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/health/models/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/health/models/client.py +21 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/health/models/models.py +33 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/health/models/schemas/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/health/models/schemas/health_gauge_flood_stats.py +15 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/health/models/schemas/health_hml_stats.py +18 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/health/models/schemas/health_last_hml_received.py +15 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/health/models/schemas/health_lro_stats.py +15 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/health/models/schemas/health_monitor_response.py +20 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/models/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/models/client.py +10 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/models/models.py +39 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/models/schemas/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/models/schemas/gauge_datum.py +27 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/models/schemas/gauge_stage_flow.py +32 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/models/schemas/gauge_stage_flow_type.py +12 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/models/schemas/list_gauges_request_bounding_box.py +25 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/models/schemas/list_gauges_request_srid.py +13 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/models/schemas/protobuf_any.py +14 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/models/schemas/rpc_status.py +18 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/products/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/products/client.py +32 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/products/models/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/products/models/client.py +23 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/products/models/models.py +21 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/products/models/schemas/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/reaches/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/reaches/client.py +49 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/reaches/models/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/reaches/models/client.py +40 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/reaches/models/models.py +39 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/reaches/models/schemas/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/reaches/models/schemas/reach_forecast_series.py +14 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/reaches/models/schemas/reach_get_streamflow_response.py +26 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/reaches/models/schemas/reach_reach.py +28 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/reaches/models/schemas/reach_reach_route.py +17 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/reaches/models/schemas/reach_route_reach_segment.py +15 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/reaches/models/schemas/reach_streamflow.py +18 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/water/reaches/models/schemas/reach_streamflow_datum.py +15 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/__init__.py +6 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/alerts/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/alerts/client.py +564 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/alerts/models/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/alerts/models/client.py +197 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/alerts/models/models.py +65 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/alerts/models/schemas/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/alerts/models/schemas/active_alert_collection_geo_json.py +27 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/alerts/models/schemas/active_alert_collection_geo_json_features_item.py +20 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/alerts/models/schemas/alert_collection_geo_json.py +31 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/alerts/models/schemas/alert_collection_geo_json_features_item.py +20 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/alerts/models/schemas/alert_geo_json.py +31 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/alerts/models/schemas/alerts_active_count_response.py +31 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/alerts/models/schemas/alerts_types_response.py +16 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/aviation/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/aviation/client.py +159 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/aviation/models/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/aviation/models/client.py +97 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/aviation/models/models.py +61 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/aviation/models/schemas/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/aviation/models/schemas/atsu_identifier.py +11 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/aviation/models/schemas/center_weather_advisory.py +25 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/aviation/models/schemas/center_weather_advisory_collection_geo_json.py +23 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/aviation/models/schemas/center_weather_advisory_collection_geo_json_features_item.py +16 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/aviation/models/schemas/center_weather_advisory_geo_json.py +27 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/aviation/models/schemas/center_weather_service_unit_json_ld.py +12 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/aviation/models/schemas/nws_center_weather_service_unit_id.py +39 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/aviation/models/schemas/sigmet.py +25 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/aviation/models/schemas/sigmet_collection_geo_json.py +21 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/aviation/models/schemas/sigmet_geo_json.py +27 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/aviation/models/schemas/sigmet_sequence_number.py +10 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/client.py +54 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/gridpoints/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/gridpoints/client.py +617 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/gridpoints/models/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/gridpoints/models/client.py +86 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/gridpoints/models/models.py +44 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/gridpoints/models/schemas/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/gridpoints/models/schemas/gridpoint12h_forecast.py +51 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/gridpoints/models/schemas/gridpoint12h_forecast_geo_json.py +29 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/gridpoints/models/schemas/gridpoint_geo_json.py +31 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/gridpoints/models/schemas/gridpoint_hourly_forecast.py +51 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/gridpoints/models/schemas/gridpoint_hourly_forecast_geo_json.py +29 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/icons/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/icons/client.py +70 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/icons/models/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/icons/models/client.py +59 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/icons/models/models.py +24 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/icons/models/schemas/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/icons/models/schemas/icons_summary_response.py +18 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/icons/models/schemas/icons_summary_response_icons_value.py +14 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/client.py +21 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/models.py +313 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/active_alert_collection.py +19 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/active_alert_collection_json_ld.py +24 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/alert.py +151 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/alert_atom_entry.py +37 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/alert_atom_entry_author.py +14 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/alert_atom_feed.py +24 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/alert_atom_feed_author.py +14 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/alert_cap.py +12 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/alert_certainty.py +12 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/alert_collection.py +24 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/alert_collection_json_ld.py +28 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/alert_geocode.py +23 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/alert_id.py +11 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/alert_json_ld.py +16 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/alert_message_type.py +12 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/alert_references_item.py +27 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/alert_severity.py +12 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/alert_status.py +12 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/alert_urgency.py +12 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/alert_xml_parameter.py +15 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/area_code.py +14 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/astronomical_data.py +50 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/binary_file.py +12 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/date.py +11 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/geo_json_bounding_box.py +11 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/geo_json_coordinate.py +11 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/geo_json_feature.py +30 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/geo_json_feature_collection.py +25 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/geo_json_geometry.py +26 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/geo_json_geometry_value_option1.py +26 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/geo_json_geometry_value_option2.py +27 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/geo_json_geometry_value_option3.py +26 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/geo_json_geometry_value_option4.py +24 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/geo_json_geometry_value_option5.py +24 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/geo_json_geometry_value_option6.py +24 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/geo_json_line_string.py +13 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/geo_json_polygon.py +13 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/geometry_string.py +11 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/glossary_response.py +20 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/glossary_response_glossary_item.py +19 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/gridpoint.py +109 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/gridpoint12h_forecast_json_ld.py +49 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/gridpoint12h_forecast_period.py +102 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/gridpoint_forecast_units.py +13 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/gridpoint_hazards.py +16 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/gridpoint_hazards_values_item.py +22 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/gridpoint_hazards_values_item_value_item.py +29 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/gridpoint_hourly_forecast_json_ld.py +49 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/gridpoint_hourly_forecast_period.py +112 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/gridpoint_json_ld.py +12 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/gridpoint_quantitative_value_layer.py +28 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/gridpoint_quantitative_value_layer_values_item.py +21 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/gridpoint_weather.py +16 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/gridpoint_weather_values_item.py +22 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/gridpoint_weather_values_item_value_item.py +89 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/is_o8601_interval.py +11 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/json_ld_context.py +12 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/marine_area_code.py +18 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/marine_region_code.py +13 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/metar_phenomenon.py +53 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/metar_sky_coverage.py +12 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/nws_forecast_office_id.py +150 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/nws_zone_id.py +11 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/nws_zone_type.py +14 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/observation.py +129 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/observation_cloud_layers_item.py +22 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/observation_collection_geo_json.py +25 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/observation_collection_geo_json_features_item.py +16 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/observation_collection_json_ld.py +22 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/observation_json_ld.py +12 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/observation_station.py +58 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/observation_station_collection_geo_json.py +28 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/observation_station_collection_geo_json_features_item.py +16 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/observation_station_collection_json_ld.py +23 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/observation_station_json_ld.py +58 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/office.py +36 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/office_address.py +20 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/pagination_info.py +18 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/point_json_ld.py +59 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/point_json_ld_nwr.py +27 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/point_string.py +10 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/problem_detail.py +39 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/quantitative_value.py +43 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/relative_location.py +27 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/relative_location_geo_json.py +27 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/relative_location_json_ld.py +31 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/state_territory_code.py +75 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/time.py +11 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/unit_of_measure.py +11 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/zone.py +46 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/zone_collection_json_ld.py +18 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/zone_forecast.py +32 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/zone_forecast_json_ld.py +12 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/zone_forecast_periods_item.py +22 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/models/schemas/zone_json_ld.py +12 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/offices/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/offices/client.py +1214 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/offices/models/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/offices/models/client.py +84 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/offices/models/models.py +51 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/offices/models/schemas/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/offices/models/schemas/nws_connect_document_metadata.py +37 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/offices/models/schemas/nws_national_hq_id.py +13 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/offices/models/schemas/nws_office_id.py +14 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/offices/models/schemas/nws_regional_hq_id.py +13 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/offices/models/schemas/office_briefing.py +12 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/offices/models/schemas/office_headline.py +26 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/offices/models/schemas/office_headline_collection.py +18 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/offices/models/schemas/office_weather_story.py +41 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/offices/models/schemas/office_weather_story_collection.py +12 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/points/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/points/client.py +51 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/points/models/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/points/models/client.py +39 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/points/models/models.py +30 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/points/models/schemas/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/points/models/schemas/point.py +59 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/points/models/schemas/point_geo_json.py +27 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/points/models/schemas/point_nwr.py +27 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/products/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/products/client.py +111 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/products/models/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/products/models/client.py +108 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/products/models/models.py +33 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/products/models/schemas/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/products/models/schemas/text_product.py +24 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/products/models/schemas/text_product_collection.py +18 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/products/models/schemas/text_product_location_collection.py +17 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/products/models/schemas/text_product_type_collection.py +18 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/products/models/schemas/text_product_type_collection_graph_item.py +15 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/radar/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/radar/client.py +107 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/radar/models/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/radar/models/client.py +109 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/radar/models/models.py +24 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/radar/models/schemas/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/radar/models/schemas/is_o8601_duration.py +11 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/radio/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/radio/client.py +46 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/radio/models/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/radio/models/client.py +34 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/radio/models/models.py +12 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/radio/models/schemas/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/stations/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/stations/client.py +321 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/stations/models/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/stations/models/client.py +145 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/stations/models/models.py +51 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/stations/models/schemas/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/stations/models/schemas/observation_geo_json.py +27 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/stations/models/schemas/observation_station_geo_json.py +27 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/thumbnails/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/thumbnails/client.py +33 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/thumbnails/models/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/thumbnails/models/client.py +21 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/thumbnails/models/models.py +12 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/thumbnails/models/schemas/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/zones/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/zones/client.py +370 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/zones/models/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/zones/models/client.py +159 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/zones/models/models.py +61 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/zones/models/schemas/__init__.py +1 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/zones/models/schemas/land_region_code.py +13 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/zones/models/schemas/region_code.py +13 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/zones/models/schemas/zone_collection_geo_json.py +21 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/zones/models/schemas/zone_collection_geo_json_features_item.py +16 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/zones/models/schemas/zone_forecast_geo_json.py +29 -0
- noaa_apiroute-0.1.0/src/noaa_apiroute/weather/zones/models/schemas/zone_geo_json.py +27 -0
- noaa_apiroute-0.1.0/tests/__init__.py +0 -0
- noaa_apiroute-0.1.0/tests/conftest.py +36 -0
- noaa_apiroute-0.1.0/tests/live/__init__.py +0 -0
- noaa_apiroute-0.1.0/tests/live/conftest.py +41 -0
- noaa_apiroute-0.1.0/tests/live/test_noaa_live.py +71 -0
- noaa_apiroute-0.1.0/tests/scripts/__init__.py +0 -0
- noaa_apiroute-0.1.0/tests/scripts/test_next_release.py +128 -0
- noaa_apiroute-0.1.0/tests/test_apis_config.py +55 -0
- noaa_apiroute-0.1.0/tests/test_auth.py +60 -0
- noaa_apiroute-0.1.0/uv.lock +566 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: apiroute-client
|
|
3
|
+
description: Create, set up and maintain a GitHub repository that publishes apiroute-generated Python clients for an API described by OpenAPI/Swagger specs, WSDLs or a GraphQL schema (with hand-written operations). Covers gathering the specs and documentation links, the repository layout, the apis.yaml generation config, hand-written auth base classes, the README, CI/Build/Release workflows (the Build workflow regenerates and commits changes), PyPI publishing (only if the user wants it), and ongoing maintenance.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# apiroute client repositories
|
|
7
|
+
|
|
8
|
+
Use this skill when asked to create a client repository for an API ("make a <api>-apiroute repo", e.g. `stripe-apiroute`), or to maintain one: adding or removing an API, a spec change that broke generation, upgrading apiroute, or setting up releases.
|
|
9
|
+
|
|
10
|
+
A client repository holds generated code that is never edited by hand. It is the output of [apiroute](https://github.com/dougyouch/apiroute)'s generator (`apiroute generate openapi|wsdl|graphql`), applied to specs listed in one config file, and refreshed by a scheduled workflow. The one exception is GraphQL: its `.graphql` operation files are hand-written inputs, kept in `operations/` (see below). A worked example is **[ebay-apiroute](https://github.com/dougyouch/ebay-apiroute)**; the examples below use it, but nothing here is specific to eBay. Copy its files and adapt them rather than writing new ones; the sections below say what to change.
|
|
11
|
+
|
|
12
|
+
## 1. Gather before creating anything
|
|
13
|
+
|
|
14
|
+
Ask the user (an AskUserQuestion-style prompt with choices works well), and confirm what you find:
|
|
15
|
+
|
|
16
|
+
1. **Names:**
|
|
17
|
+
- the repository (`<api>-apiroute`)
|
|
18
|
+
- the PyPI name (the same)
|
|
19
|
+
- the Python package (`<api>_apiroute`)
|
|
20
|
+
- the GitHub owner
|
|
21
|
+
2. **Which APIs to cover.** Offer "everything with a published spec" as the default; lazy loading makes unused APIs free.
|
|
22
|
+
3. **Will it be released to PyPI?** Always ask; never assume. If yes, the repo gets `release.yml` and the user must create a PyPI pending publisher (step 6). If no, skip `release.yml`, and the README says to install from GitHub (`pip install git+https://github.com/<owner>/<repo>`).
|
|
23
|
+
4. **Public or private.** Releasing to PyPI implies public.
|
|
24
|
+
5. **Auth model:** OAuth bearer tokens, API keys, Basic auth, request signing, SOAP header credentials, or extra per-call parameters. This decides the auth base class (step 4).
|
|
25
|
+
6. **For a GraphQL API, which operations.** A GraphQL schema doesn't say what to fetch, so the repository holds the queries and mutations to generate. Ask what the user needs (or start from the API's documented examples), and write them as `.graphql` files. Also ask whether introspecting the schema needs a token, and the name of the environment variable that holds it.
|
|
26
|
+
|
|
27
|
+
Then find each API's machine-readable description and its documentation page:
|
|
28
|
+
|
|
29
|
+
- **Download every spec and check its content, not the HTTP status.** Some sites (eBay's, for example) answer unknown URLs with a normal 200 page. A spec must parse as JSON/YAML with an `openapi` or `swagger` key, or as XML with `definitions` (WSDL).
|
|
30
|
+
- **For GraphQL, introspect the endpoint** with `apiroute fetch-schema <endpoint> -o /tmp/x.graphql -H "Authorization: Bearer $TOKEN"`. Some APIs also publish the schema as a file (GitHub's `schema.docs.graphql`), which works without a token.
|
|
31
|
+
- **Treat documentation links the same way.** Some sites serve an error page to `curl` but the real page to browsers. A page's `<title>` that says "Error" or "Not Found" means "try another URL or a web search", not "it doesn't exist". Every API in the README table needs a working documentation link.
|
|
32
|
+
- **Probe URL patterns** when a site publishes many specs (eBay, as an example: `/api-docs/master/<group>/<api>/openapi/3/<group>_<api>_<version>_oas3.json`), but keep only the ones whose content validates.
|
|
33
|
+
- **Generate each spec into a scratch directory** before committing to it: `apiroute generate openapi <url> -o /tmp/x --models`, or for GraphQL `apiroute generate graphql /tmp/x.graphql --operations <dir> -o /tmp/x --models`, which reports every operation that doesn't match the schema as `file:line:column`. Note any spec the generator can't handle, and either fix apiroute or leave that API out, telling the user which.
|
|
34
|
+
|
|
35
|
+
## 2. Repository layout
|
|
36
|
+
|
|
37
|
+
```text
|
|
38
|
+
<repo>/
|
|
39
|
+
apis.yaml the source of truth: one entry per API (hand-written)
|
|
40
|
+
specs/ committed copies of the specs (written by --fetch; SDL for GraphQL)
|
|
41
|
+
operations/<api>/ GraphQL operations, one folder per API (hand-written)
|
|
42
|
+
scripts/generate.py fetch specs, run apiroute generate, write the README table
|
|
43
|
+
scripts/next_release.py each release's version, notes and changelog entry, from the commits (if releasing)
|
|
44
|
+
src/<package>/
|
|
45
|
+
__init__.py package docstring (hand-written)
|
|
46
|
+
auth.py auth base classes the generated clients extend (hand-written)
|
|
47
|
+
<group>/__init__.py written by scripts/generate.py
|
|
48
|
+
<group>/<api>/ generated by apiroute (never edited)
|
|
49
|
+
tests/ config checks, auth behaviour, one call per protocol
|
|
50
|
+
.github/workflows/ ci.yml, build.yml, release.yml (if releasing)
|
|
51
|
+
AGENT.md CLAUDE.md agent guidance; CLAUDE.md imports AGENT.md with "@AGENT.md"
|
|
52
|
+
.agent/skills/apiroute-client.md this skill (copy it into the new repository)
|
|
53
|
+
README.md CHANGELOG.md LICENSE pyproject.toml uv.lock
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
`apis.yaml`, one entry per API (shown with ebay-apiroute's values as an example):
|
|
57
|
+
|
|
58
|
+
```yaml
|
|
59
|
+
package: ebay_apiroute
|
|
60
|
+
apis:
|
|
61
|
+
- name: sell_inventory # unique; also the spec file name in specs/
|
|
62
|
+
title: Inventory API # shown in the README table
|
|
63
|
+
format: openapi # openapi (covers Swagger 2.0) or wsdl
|
|
64
|
+
spec: https://.../sell_inventory_v1_oas3.json
|
|
65
|
+
docs: https://developer.ebay.com/api-docs/sell/static/api-inventory.html
|
|
66
|
+
module: sell.inventory # -> src/ebay_apiroute/sell/inventory/
|
|
67
|
+
client: SellInventoryApi
|
|
68
|
+
base_class: ebay_apiroute.auth:EbayAuth # optional; owns auth
|
|
69
|
+
models: true # optional, default true: the typed .models layer
|
|
70
|
+
nullable_fields: false # optional: --nullable-fields, when the spec says fields are never null but the API sends null
|
|
71
|
+
open_enums: false # optional: --open-enums, when the API sends enum values the spec doesn't list
|
|
72
|
+
operation_names: specs/sell_inventory.names.json # optional: --operation-names, operation ID -> dotted section.method
|
|
73
|
+
pagination: specs/sell_inventory.pagination.yaml # optional: --pagination rules adding <name>_all methods
|
|
74
|
+
- name: github # a GraphQL API
|
|
75
|
+
title: GitHub GraphQL API
|
|
76
|
+
format: graphql
|
|
77
|
+
spec: https://api.github.com/graphql # introspected by --fetch into specs/github.graphql
|
|
78
|
+
spec_headers: # optional, for introspection; values name environment variables
|
|
79
|
+
Authorization: "Bearer ${GITHUB_TOKEN}"
|
|
80
|
+
operations: operations/github # hand-written .graphql files; subfolders become sections
|
|
81
|
+
endpoint: https://api.github.com/graphql # --endpoint: base_url and path
|
|
82
|
+
scalars: # optional --scalar mappings
|
|
83
|
+
DateTime: datetime:datetime
|
|
84
|
+
persisted_queries: false # optional: --persisted-queries, for servers with APQ
|
|
85
|
+
docs: https://docs.github.com/en/graphql
|
|
86
|
+
module: github
|
|
87
|
+
client: GitHubApi
|
|
88
|
+
base_class: github_apiroute.auth:GitHubAuth
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
`scripts/generate.py`: copy an existing one, such as [ebay-apiroute's](https://github.com/dougyouch/ebay-apiroute/blob/main/scripts/generate.py). It does the following:
|
|
92
|
+
|
|
93
|
+
- `--fetch` downloads each spec, validates it, and re-indents JSON (keeping key order) so diffs stay readable. For `format: graphql` it runs `apiroute fetch-schema <spec> -o specs/<name>.graphql`, expanding `${VAR}` in `spec_headers` from the environment and passing each as `-H`. Never write a token to a file.
|
|
94
|
+
- It runs `apiroute generate <format> specs/<name> -o src/<package>/<module> --client-name ... --models --base-class ...` for each API, adding `--nullable-fields` when an API sets `nullable_fields`, `--open-enums` when it sets `open_enums`, `--base-url` when it sets `base_url` (for a spec without servers), `--operation-names` when it sets `operation_names`, and `--pagination` when it sets `pagination`, and `--operations`, `--endpoint`, `--scalar` and `--persisted-queries` for GraphQL. [github-apiroute's script](https://github.com/dougyouch/github-apiroute/blob/main/scripts/generate.py) has the GraphQL support; ebay-apiroute's predates it.
|
|
95
|
+
- It writes the group packages' `__init__.py`, marked "Generated by scripts/generate.py".
|
|
96
|
+
- It rewrites the README table between `<!-- apis:start -->` and `<!-- apis:end -->`.
|
|
97
|
+
- `--only NAME` limits the run to the named APIs.
|
|
98
|
+
- When the API pages its lists, write a `--pagination` rules file in `specs/` (see the apiroute README's code generation notes): one rule per paging style, matched by response shape and parameters rather than listing operations, so new list operations are picked up when the spec changes. Check the generator's per-rule match counts after each regeneration, and add a live test that pages past the first page with a small page size.
|
|
99
|
+
- When a spec's tags and operationIds make poor names, pass `--operation-names` a JSON map of operation ID to dotted name (`customers.create`, `issuing.cards.list`): sections nest. An operation without an operationId is keyed by its method and path as the spec writes them (`"GET /api/data/metar": "metar"`). Keep the map in `specs/` so its diffs are reviewed with the spec's. If the spec carries better names in vendor extensions, have `generate.py` write the map from them on every run; [stripe-apiroute](https://github.com/dougyouch/stripe-apiroute) builds it from Stripe's `x-stripeOperations`.
|
|
100
|
+
|
|
101
|
+
ebay-apiroute's script also has an eBay-specific `_write_trading_version`. Drop it, or adapt it if your auth class must read a value from a spec.
|
|
102
|
+
|
|
103
|
+
`pyproject.toml`:
|
|
104
|
+
- Depend on `apiroute>=<current>` (add `apiroute[soap]` when any API is a WSDL; GraphQL clients need nothing extra at run time) and `pydantic>=2.6` (generated models fail on pydantic 2.1–2.5). Put `apiroute[codegen]`, `pytest` and `ruff` in the `dev` dependency group.
|
|
105
|
+
- Set ruff's `line-length = 100` and `extend-exclude = ["specs"]`.
|
|
106
|
+
- Keep `specs/` out of the sdist.
|
|
107
|
+
- If releasing, take the version from the git tag: `dynamic = ["version"]`, `requires = ["hatchling", "hatch-vcs"]` and `[tool.hatch.version] source = "vcs"`. Nothing in the repository holds the version; a release commits only its CHANGELOG.md entry.
|
|
108
|
+
|
|
109
|
+
## 3. Generate, lint, import
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
uv sync
|
|
113
|
+
uv run python scripts/generate.py --fetch
|
|
114
|
+
uv run ruff check . && uv run ruff format --check . # generated code passes both
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Then import every module and build every model, on the lowest and highest supported Python versions. A Python 3.10 import catches annotation problems that 3.14's deferred annotations hide. The checks live in `tests/test_apis_config.py`:
|
|
118
|
+
|
|
119
|
+
- every `apis.yaml` entry has a spec file, a documentation link, an importable client and the configured base class
|
|
120
|
+
- every route compiles
|
|
121
|
+
|
|
122
|
+
## 4. Auth base class (hand-written, in `auth.py`)
|
|
123
|
+
|
|
124
|
+
Every generated root client extends the `base_class` from `apis.yaml`, and apiroute then generates no auth of its own. Write the class once, by subclassing `apiroute.Client`. Sections inherit its `headers` and `query_params`, and they use its hooks.
|
|
125
|
+
|
|
126
|
+
| Need | How |
|
|
127
|
+
| --- | --- |
|
|
128
|
+
| Bearer token | `headers = {"Authorization": lambda self: f"Bearer {self.current_token()}" if self._token else None}`; accept a string or a function returning one (for refreshing OAuth helpers) |
|
|
129
|
+
| API key in a header or query | an entry in `headers` or `query_params` reading an attribute |
|
|
130
|
+
| Request signing | `on_request(self, request)` returning `dataclasses.replace(request, headers=...)` |
|
|
131
|
+
| Per-call parameters | `on_request`, with `request.operation` (the spec's operationId or WSDL operation name) |
|
|
132
|
+
| Retrying safe operations | apiroute 2 only retries `GET`, `HEAD` and `OPTIONS` after a read timeout. Override `idempotent(self, request)` to return `True` for operations that are safe to repeat, by `request.operation` (a SOAP API's `Get*` calls) or `request.method`, and `None` for the rest. Set `idempotency_key = "Idempotency-Key"` instead for APIs that honor that header |
|
|
133
|
+
| SOAP header credentials | `soap_header(self, operation) -> dict`, in the same xmltodict shape as bodies |
|
|
134
|
+
| Sandbox or region hosts | an `__init__` flag that sets `kwargs["base_url"]` from `type(self)._config.base_url` |
|
|
135
|
+
|
|
136
|
+
Test each behaviour in `tests/` with `apiroute.testing`: inside `with mock_transport() as mock:`, call the client and assert on `mock.last`, which records the operation, the header or parameter on the wire, the sandbox host, and a SOAP header if any. Match responses by operation with `mock.on(operation=...)`.
|
|
137
|
+
|
|
138
|
+
## 5. README (generate it as part of setup)
|
|
139
|
+
|
|
140
|
+
It must have:
|
|
141
|
+
- a one-paragraph description with CI and Build badges
|
|
142
|
+
- installation instructions (PyPI, or from GitHub when not releasing)
|
|
143
|
+
- usage per protocol: dict and typed calls, `.aio`, auth arguments and sandbox
|
|
144
|
+
- **links to the API's documentation and its auth or token guide**
|
|
145
|
+
- the generated API table, with a docs link per API
|
|
146
|
+
- **how the repository stays up to date:**
|
|
147
|
+
- the Build schedule
|
|
148
|
+
- the `specs/` snapshot and `git log -p specs/`
|
|
149
|
+
- apiroute as the generator
|
|
150
|
+
- the commit types and the releases they produce
|
|
151
|
+
- what CI checks
|
|
152
|
+
- development commands, and how to add an API
|
|
153
|
+
|
|
154
|
+
Use an existing client repository's README (ebay-apiroute's, for example) as the template.
|
|
155
|
+
|
|
156
|
+
## 6. Workflows
|
|
157
|
+
|
|
158
|
+
Copy them from an existing client repository ([github-apiroute](https://github.com/dougyouch/github-apiroute), for example) and change the names, the PyPI project and the schedule.
|
|
159
|
+
|
|
160
|
+
- **`ci.yml`** runs on pull requests and `workflow_call` (release.yml runs it before every release):
|
|
161
|
+
- Lint: `ruff check` and `ruff format --check`.
|
|
162
|
+
- `generated-is-current`: runs `scripts/generate.py` without `--fetch` and fails on any `git status` difference. This catches hand edits, and specs out of step with the code.
|
|
163
|
+
- Tests on every supported Python version.
|
|
164
|
+
- **`build.yml`** runs on a schedule and `workflow_dispatch`:
|
|
165
|
+
1. `uv lock --upgrade-package apiroute`, then `uv sync`.
|
|
166
|
+
2. `scripts/generate.py --fetch`.
|
|
167
|
+
3. Lint and test.
|
|
168
|
+
4. If `git status` shows changes, commit and push to main:
|
|
169
|
+
- `feat(specs): update clients from <API>'s latest specs` when `specs/` changed (a minor release)
|
|
170
|
+
- otherwise `fix(codegen): regenerate clients with apiroute <version>` (a patch)
|
|
171
|
+
|
|
172
|
+
It needs `permissions: contents: write`. If `main` is protected, give the workflow a bypass or have it open a PR instead. A GraphQL API whose introspection needs a token gets it from a repository secret, exposed to the fetch step as the environment variable `spec_headers` names.
|
|
173
|
+
- **`release.yml`**, only if the user said yes to PyPI, releases every push to main; there's no release PR. It runs CI, then `scripts/next_release.py` works out the version from the conventional commits since the last `vX.Y.Z` tag (`feat!:` or a `BREAKING CHANGE:` footer: major, `feat:` minor, anything else patch) and the notes. It commits the notes to CHANGELOG.md as `chore(release): vX.Y.Z` (which the next release's notes leave out), tags that commit and pushes both at once, then builds (hatch-vcs reads the version from the tag), publishes with `uv publish --trusted-publishing always` in the `pypi` environment, and creates the GitHub release with the notes and distributions. Each step skips what's already done (the tag, the PyPI version, the release), so rerunning a failed release finishes it, and a run on an already-tagged commit changes nothing. A run whose commit is no longer main's newest leaves the release to the newer push, which includes it. The release commit is pushed with `GITHUB_TOKEN`, so it triggers nothing; `main` may forbid force pushes but must accept the workflow's fast-forward push. Besides `push` and `workflow_dispatch`, trigger it on `workflow_run` of Build: commits pushed with `GITHUB_TOKEN` don't trigger other workflows. Copy apiroute's or github-apiroute's `release.yml` and `scripts/next_release.py`.
|
|
174
|
+
|
|
175
|
+
Each repository needs these GitHub and PyPI settings:
|
|
176
|
+
|
|
177
|
+
- Delete branches on merge: `gh repo edit --delete-branch-on-merge`.
|
|
178
|
+
- If releasing:
|
|
179
|
+
- The user creates a PyPI **pending publisher**: the project name, the repository owner and name, workflow `release.yml`, environment `pypi`.
|
|
180
|
+
- The first push to main releases `0.1.0` (no tag yet); every later push releases the next version.
|
|
181
|
+
|
|
182
|
+
## 7. Maintenance
|
|
183
|
+
|
|
184
|
+
- **Routine:** none. Build commits changes, and every commit on main is tested, tagged and published on its own. The tests are the gate, so keep them meaningful: config checks, auth behaviour, and one call per protocol.
|
|
185
|
+
- **A spec change breaks generation:** Build fails before committing, and the last good code stays on main. Reproduce with `scripts/generate.py --fetch --only <name>`, then fix apiroute (preferred) or the auth class. Never patch `specs/` or generated files by hand.
|
|
186
|
+
- **A GraphQL schema change breaks an operation:** Build fails listing each broken operation as `file:line:column`. The operations are yours: update them in `operations/<api>/` (a renamed or removed field), regenerate and commit (`feat!:` if a released method's result changed shape). Deprecation warnings in the Build log say what to move off before the API removes it.
|
|
187
|
+
- **Add a GraphQL operation:** add a `.graphql` file (or a query to one), `generate.py --only <name>`, test and commit (`feat:`).
|
|
188
|
+
- **Lists:** for a Relay connection the user wants in full, put `@paginate` on the connection field and give the operation a `$after: String` variable. The generated method then iterates every item across pages. Leave it off where one page (with `totalCount`) is what's wanted, because adding it later changes the method's return type.
|
|
189
|
+
- **Add an API:** add an `apis.yaml` entry, verifying its spec and docs as in step 1, then `generate.py --fetch --only <name>`, then test and commit (`feat:`).
|
|
190
|
+
- **Remove an API:** delete its entry, its spec and its folder, then regenerate and commit (`feat!:` if it was released).
|
|
191
|
+
- **apiroute adds a feature you need:** release apiroute, raise the minimum in `pyproject.toml`, `uv lock`, regenerate, commit.
|
|
192
|
+
|
|
193
|
+
## 8. Before handing over
|
|
194
|
+
|
|
195
|
+
- [ ] Every API has a working spec and a working docs link (checked by content, not by status).
|
|
196
|
+
- [ ] `ruff check`, `ruff format --check`, the tests, and a Python 3.10 import of every module all pass.
|
|
197
|
+
- [ ] CI, Build (run it once by hand) and, if releasing, Release are green.
|
|
198
|
+
- [ ] Branch auto-delete is on. If releasing, the pending publisher exists, or the user knows to create it.
|
|
199
|
+
- [ ] README, AGENT.md, CLAUDE.md (importing AGENT.md) and this skill are in the repository.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
name: Build
|
|
2
|
+
|
|
3
|
+
# Keeps the clients current: fetches NOAA's latest OpenAPI specs, upgrades apiroute,
|
|
4
|
+
# regenerates, checks (live too, against NOAA's APIs), and commits any difference to main.
|
|
5
|
+
# A changed spec is committed as feat(specs) (a minor release); output that changed only
|
|
6
|
+
# because apiroute did, as fix(codegen) (a patch).
|
|
7
|
+
on:
|
|
8
|
+
schedule:
|
|
9
|
+
- cron: "41 9 * * 1" # Mondays 09:41 UTC
|
|
10
|
+
workflow_dispatch:
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: write # commit regenerated clients
|
|
14
|
+
|
|
15
|
+
concurrency:
|
|
16
|
+
group: build
|
|
17
|
+
cancel-in-progress: false
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
regenerate:
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v4
|
|
24
|
+
- uses: astral-sh/setup-uv@v6
|
|
25
|
+
with:
|
|
26
|
+
python-version: "3.14"
|
|
27
|
+
- name: Use the newest apiroute
|
|
28
|
+
run: uv lock --upgrade-package apiroute
|
|
29
|
+
- run: uv sync
|
|
30
|
+
- name: Fetch the latest specs and regenerate
|
|
31
|
+
run: uv run python scripts/generate.py --fetch
|
|
32
|
+
- name: Check
|
|
33
|
+
run: |
|
|
34
|
+
uv run ruff check .
|
|
35
|
+
uv run ruff format --check .
|
|
36
|
+
uv run pytest
|
|
37
|
+
# Requests and typed models against what NOAA actually sends, before anything is
|
|
38
|
+
# committed. NOAA's APIs need no key.
|
|
39
|
+
- name: Live tests
|
|
40
|
+
env:
|
|
41
|
+
NOAA_LIVE: "1"
|
|
42
|
+
run: uv run pytest tests/live
|
|
43
|
+
- name: Commit changes
|
|
44
|
+
run: |
|
|
45
|
+
if [ -z "$(git status --porcelain)" ]; then
|
|
46
|
+
echo "Specs and generated clients are unchanged."
|
|
47
|
+
exit 0
|
|
48
|
+
fi
|
|
49
|
+
specs=$(git status --porcelain -- specs | awk '{print $2}' | xargs -r -n1 basename | sed 's/\..*$//' | sort -u | paste -sd ' ' -)
|
|
50
|
+
if [ -n "$specs" ]; then
|
|
51
|
+
subject="feat(specs): update clients from NOAA's latest specs"
|
|
52
|
+
body="Changed specs: $specs"
|
|
53
|
+
else
|
|
54
|
+
version=$(uv run python -c "import importlib.metadata as m; print(m.version('apiroute'))")
|
|
55
|
+
subject="fix(codegen): regenerate clients with apiroute $version"
|
|
56
|
+
body="No spec changed; the generated code did, with the newer apiroute."
|
|
57
|
+
fi
|
|
58
|
+
git config user.name 'github-actions[bot]'
|
|
59
|
+
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
|
|
60
|
+
git add -A
|
|
61
|
+
git commit -m "$subject" -m "$body"
|
|
62
|
+
git push
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
workflow_call: # release.yml runs it on every push to main, before releasing
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
lint:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
- uses: astral-sh/setup-uv@v6
|
|
16
|
+
with:
|
|
17
|
+
python-version: "3.14"
|
|
18
|
+
- run: uv sync
|
|
19
|
+
- run: uv run ruff check .
|
|
20
|
+
- run: uv run ruff format --check .
|
|
21
|
+
|
|
22
|
+
# The committed code must be exactly what the committed specs generate: nothing in src/
|
|
23
|
+
# is edited by hand, and specs/ and src/ never drift apart.
|
|
24
|
+
generated-is-current:
|
|
25
|
+
runs-on: ubuntu-latest
|
|
26
|
+
steps:
|
|
27
|
+
- uses: actions/checkout@v4
|
|
28
|
+
- uses: astral-sh/setup-uv@v6
|
|
29
|
+
with:
|
|
30
|
+
python-version: "3.14"
|
|
31
|
+
- run: uv sync
|
|
32
|
+
- run: uv run python scripts/generate.py
|
|
33
|
+
- name: Check for differences
|
|
34
|
+
run: |
|
|
35
|
+
if [ -n "$(git status --porcelain)" ]; then
|
|
36
|
+
git status --short
|
|
37
|
+
echo "::error::Generated code differs from the committed specs. Run 'uv run python scripts/generate.py' and commit the result."
|
|
38
|
+
exit 1
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
test:
|
|
42
|
+
runs-on: ubuntu-latest
|
|
43
|
+
strategy:
|
|
44
|
+
fail-fast: false
|
|
45
|
+
matrix:
|
|
46
|
+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
|
47
|
+
steps:
|
|
48
|
+
- uses: actions/checkout@v4
|
|
49
|
+
- uses: astral-sh/setup-uv@v6
|
|
50
|
+
with:
|
|
51
|
+
python-version: ${{ matrix.python-version }}
|
|
52
|
+
- run: uv sync
|
|
53
|
+
- run: uv run pytest
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Every push to main is a release. CI runs first; then scripts/next_release.py works out the
|
|
4
|
+
# version from the conventional commits since the last tag (feat: minor, ! or BREAKING CHANGE:
|
|
5
|
+
# major, anything else: patch). A release commit adds those commits to CHANGELOG.md and is
|
|
6
|
+
# tagged, built (hatch-vcs reads the version from the tag), published to PyPI and given a
|
|
7
|
+
# GitHub release with the same notes. Every step skips what's already done, so rerunning a
|
|
8
|
+
# failed release finishes it, and a run on a commit that's already released changes nothing.
|
|
9
|
+
# It also runs after Build, whose commits (pushed with GITHUB_TOKEN) trigger no push event.
|
|
10
|
+
on:
|
|
11
|
+
push:
|
|
12
|
+
branches: [main]
|
|
13
|
+
workflow_run:
|
|
14
|
+
workflows: [Build]
|
|
15
|
+
types: [completed]
|
|
16
|
+
branches: [main]
|
|
17
|
+
workflow_dispatch:
|
|
18
|
+
|
|
19
|
+
permissions:
|
|
20
|
+
contents: read
|
|
21
|
+
|
|
22
|
+
concurrency:
|
|
23
|
+
group: release
|
|
24
|
+
cancel-in-progress: false
|
|
25
|
+
|
|
26
|
+
jobs:
|
|
27
|
+
ci:
|
|
28
|
+
# after Build only when it succeeded (a failed Build committed nothing)
|
|
29
|
+
if: github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success'
|
|
30
|
+
uses: ./.github/workflows/ci.yml
|
|
31
|
+
|
|
32
|
+
release:
|
|
33
|
+
needs: ci
|
|
34
|
+
runs-on: ubuntu-latest
|
|
35
|
+
environment:
|
|
36
|
+
name: pypi
|
|
37
|
+
url: https://pypi.org/project/noaa-apiroute/
|
|
38
|
+
permissions:
|
|
39
|
+
contents: write # the tag and the GitHub release
|
|
40
|
+
id-token: write # PyPI trusted publishing (OIDC)
|
|
41
|
+
steps:
|
|
42
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
43
|
+
with:
|
|
44
|
+
fetch-depth: 0 # every commit and tag, for the version
|
|
45
|
+
- uses: astral-sh/setup-uv@v6
|
|
46
|
+
|
|
47
|
+
# A rerun of a release whose tag exists finishes that release from its tag. A push that
|
|
48
|
+
# newer pushes have overtaken is left to them: the newest releases every commit since
|
|
49
|
+
# the last tag, so nothing is skipped and main isn't pushed to from behind.
|
|
50
|
+
- name: Work out the version
|
|
51
|
+
run: |
|
|
52
|
+
version=$(python3 scripts/next_release.py)
|
|
53
|
+
echo "VERSION=$version" >> "$GITHUB_ENV"
|
|
54
|
+
echo "TAG=v$version" >> "$GITHUB_ENV"
|
|
55
|
+
python3 scripts/next_release.py --notes > "$RUNNER_TEMP/notes.md"
|
|
56
|
+
if git rev-parse -q --verify "refs/tags/v$version" > /dev/null; then
|
|
57
|
+
echo "STATE=tagged" >> "$GITHUB_ENV"
|
|
58
|
+
elif [ "$(git rev-parse origin/main)" != "$(git rev-parse HEAD)" ]; then
|
|
59
|
+
echo "STATE=overtaken" >> "$GITHUB_ENV"
|
|
60
|
+
echo "::notice::main has moved on; the newer push releases this commit with it."
|
|
61
|
+
else
|
|
62
|
+
echo "STATE=new" >> "$GITHUB_ENV"
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
# The release commit adds the notes to CHANGELOG.md; the tag goes on it, so the package
|
|
66
|
+
# carries its own changelog entry. Pushed with GITHUB_TOKEN, it starts no workflow.
|
|
67
|
+
- name: Commit the changelog and tag
|
|
68
|
+
if: env.STATE == 'new'
|
|
69
|
+
run: |
|
|
70
|
+
python3 scripts/next_release.py --changelog CHANGELOG.md
|
|
71
|
+
git config user.name 'github-actions[bot]'
|
|
72
|
+
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
|
|
73
|
+
git commit -m "chore(release): $TAG" CHANGELOG.md
|
|
74
|
+
git tag "$TAG"
|
|
75
|
+
git push --atomic origin HEAD:main "$TAG"
|
|
76
|
+
|
|
77
|
+
- name: Check out the tag
|
|
78
|
+
if: env.STATE == 'tagged'
|
|
79
|
+
run: git checkout "$TAG"
|
|
80
|
+
|
|
81
|
+
- name: Build
|
|
82
|
+
if: env.STATE != 'overtaken'
|
|
83
|
+
run: uv build
|
|
84
|
+
|
|
85
|
+
- name: Publish to PyPI
|
|
86
|
+
if: env.STATE != 'overtaken'
|
|
87
|
+
run: |
|
|
88
|
+
if curl -sf "https://pypi.org/pypi/noaa-apiroute/$VERSION/json" > /dev/null; then
|
|
89
|
+
echo "noaa-apiroute $VERSION is already published"
|
|
90
|
+
else
|
|
91
|
+
uv publish --trusted-publishing always
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
- name: GitHub release
|
|
95
|
+
if: env.STATE != 'overtaken'
|
|
96
|
+
env:
|
|
97
|
+
GH_TOKEN: ${{ github.token }}
|
|
98
|
+
run: |
|
|
99
|
+
if gh release view "$TAG" > /dev/null 2>&1; then
|
|
100
|
+
gh release upload "$TAG" dist/* --clobber
|
|
101
|
+
else
|
|
102
|
+
gh release create "$TAG" dist/* --title "$TAG" --notes-file "$RUNNER_TEMP/notes.md"
|
|
103
|
+
fi
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# AGENT.md
|
|
2
|
+
|
|
3
|
+
Guidance for AI coding agents (and people) working in this repository.
|
|
4
|
+
|
|
5
|
+
## What this repository is
|
|
6
|
+
|
|
7
|
+
`noaa-apiroute` publishes Python clients for three NOAA APIs: api.weather.gov (the National Weather Service), the AviationWeather.gov Data API and the National Water Prediction Service API. The clients are **generated** by [apiroute](https://github.com/dougyouch/apiroute) from NOAA's published OpenAPI specs. Hand-written name maps in `specs/` give the operations their sections and method names. The clients are kept current by the weekly Build workflow, and released to PyPI as `noaa-apiroute`.
|
|
8
|
+
|
|
9
|
+
## Layout
|
|
10
|
+
|
|
11
|
+
| Path | What it is | Edit by hand? |
|
|
12
|
+
| --- | --- | --- |
|
|
13
|
+
| `apis.yaml` | The APIs: spec URL, docs URL, module, client class, auth base class, generator options | **yes**: this is the source of truth |
|
|
14
|
+
| `specs/<name>.json`, `specs/aviation.yaml` | The committed copies of the specs, written by `scripts/generate.py --fetch` | no (fetch them) |
|
|
15
|
+
| `specs/<name>.names.json` | Operation ID (or `"GET /path"` for the aviation spec, which has no IDs) → dotted name | **yes** |
|
|
16
|
+
| `specs/weather.pagination.yaml` | Which weather.gov operations get `_all` methods, and how they page | **yes** |
|
|
17
|
+
| `scripts/generate.py` | Fetches the specs, runs `apiroute generate`, writes the README table | yes |
|
|
18
|
+
| `scripts/next_release.py` | Each release's version, notes and CHANGELOG.md entry, from the commits since the last tag | yes |
|
|
19
|
+
| `src/noaa_apiroute/auth.py` | `NoaaAuth`: the User-Agent, weather.gov's optional API key, retrying read-only POSTs | **yes** |
|
|
20
|
+
| `src/noaa_apiroute/__init__.py` | Package docstring | yes |
|
|
21
|
+
| `src/noaa_apiroute/{weather,aviation,water}/` | The generated clients (every file starts with `# Generated by apiroute`) | **never** |
|
|
22
|
+
| `tests/` | Config checks and auth; `tests/live/` against NOAA's APIs | yes |
|
|
23
|
+
| `.github/workflows/` | `ci.yml`, `build.yml` (regenerate, live-test and commit), `release.yml` (every push to main: tag, PyPI, GitHub release) | yes |
|
|
24
|
+
| `.agent/skills/apiroute-client.md` | Skill for creating and maintaining repos like this one | yes |
|
|
25
|
+
|
|
26
|
+
## Rules
|
|
27
|
+
|
|
28
|
+
- **Never edit generated code.** CI regenerates from `specs/` and fails on any difference. To change generated output:
|
|
29
|
+
- Edit `apis.yaml`, a name map, the pagination rules or `auth.py`, and regenerate.
|
|
30
|
+
- If the generator itself is wrong, fix apiroute; the Build workflow picks up its next release.
|
|
31
|
+
- **Never patch a spec by hand.** The next fetch overwrites it. Work around spec errors with generator options in `apis.yaml` (`nullable_fields`, `open_enums`, `base_url`), or in apiroute.
|
|
32
|
+
- **Regenerate after any change** to `apis.yaml`, `specs/` or the scripts: `uv run python scripts/generate.py`. Add `--fetch` to download the latest specs first. Commit the specs and the generated code together.
|
|
33
|
+
- **Send a User-Agent that identifies the project** in anything that calls NOAA (live tests, scripts). api.weather.gov refuses requests without one.
|
|
34
|
+
- **Every merge to main is a release.** There's no release PR; `release.yml` tests, tags and publishes each push to main, Build's commits included.
|
|
35
|
+
- **Use conventional commits.** The version comes from the commits since the last tag:
|
|
36
|
+
- `feat!:` (or a `BREAKING CHANGE:` footer) is a major release. Renaming a method in a name map is breaking.
|
|
37
|
+
- `feat:` is a minor release
|
|
38
|
+
- anything else (`fix:`, `docs:`, `chore:` ...) is a patch
|
|
39
|
+
- **The version lives in the git tag**, not `pyproject.toml` (hatch-vcs). Never tag by hand; the release workflow does.
|
|
40
|
+
- **Don't edit CHANGELOG.md by hand;** the release commits write it.
|
|
41
|
+
- **Before committing:** `uv run ruff check .`, `uv run ruff format --check .` and `uv run pytest`. After regenerating, also run the live tests: `NOAA_LIVE=1 uv run pytest tests/live`.
|
|
42
|
+
|
|
43
|
+
## Common tasks
|
|
44
|
+
|
|
45
|
+
- **NOAA added an operation:** generation still succeeds. The new operation lands on the root client, or in its tag's section, under a generated name. Give it a name in the API's `specs/<name>.names.json`, regenerate and commit (`feat:`).
|
|
46
|
+
- **Generation warns "--operation-names: no operation 'X'":** NOAA removed or renamed operation X. Remove or re-key its entry in the name map.
|
|
47
|
+
- **A spec change broke generation:** the Build workflow fails before committing anything. Reproduce with `scripts/generate.py --fetch --only <name>`, then fix apiroute or `apis.yaml`.
|
|
48
|
+
- **A live test fails after a spec update:** the spec and NOAA's responses disagree, or a typed model is wrong. Check the failing response. If the generator is at fault, fix apiroute. If the spec is, set `nullable_fields` (fields NOAA sends as null) or `open_enums` (enum values NOAA sends but the spec doesn't list) in `apis.yaml`. Type errors the options can't cover (a number declared a string) go in the README's notes for that API.
|
|
49
|
+
- **Release:** nothing to do. Every push to main, and every Build commit, is tested, released and published.
|
|
50
|
+
|
|
51
|
+
## Skill
|
|
52
|
+
|
|
53
|
+
`.agent/skills/apiroute-client.md` describes how to create, set up and maintain a client repository like this one for any API with OpenAPI/Swagger specs, WSDLs or GraphQL schemas. Read it before restructuring this repo or creating a sibling.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This repository's guidance for coding agents lives in AGENT.md, imported here:
|
|
4
|
+
|
|
5
|
+
@AGENT.md
|
|
6
|
+
|
|
7
|
+
Skills for this repository are in `.agent/skills/`. Read `.agent/skills/apiroute-client.md` before creating or restructuring an apiroute client repository.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 dougyouch
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|