From fe4b9c24feb2b09a80d9a77b86961234417900f1 Mon Sep 17 00:00:00 2001 From: MatthewFlamm <39341281+MatthewFlamm@users.noreply.github.com> Date: Thu, 20 Jun 2024 15:43:18 -0400 Subject: [PATCH] use yarl to handle icon url for parsing of condition (#208) --- pyproject.toml | 3 +- requirements-test.txt | 1 + src/pynws/simple_nws.py | 8 +- .../gridpoints_forecast_relative_icon.json | 119 +++++++++++++ .../stations_observations_relative_icon.json | 168 ++++++++++++++++++ tests/test_simple_nws.py | 11 +- 6 files changed, 304 insertions(+), 6 deletions(-) create mode 100644 tests/fixtures/gridpoints_forecast_relative_icon.json create mode 100644 tests/fixtures/stations_observations_relative_icon.json diff --git a/pyproject.toml b/pyproject.toml index dd36143..1ff17fd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,8 @@ name = "pynws" requires-python = ">=3.8" dependencies = [ "aiohttp", - "metar" + "metar", + "yarl" ] description = "Python library to retrieve observations and forecasts from NWS/NOAA" readme = {file = "README.md", content-type = "text/markdown"} diff --git a/requirements-test.txt b/requirements-test.txt index 90426da..84a67cf 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -7,3 +7,4 @@ pytest-cov==5.0.0 pytest-aiohttp==1.0.5 mypy==1.10.0 tenacity==8.3.0 +yarl==1.9.4 \ No newline at end of file diff --git a/src/pynws/simple_nws.py b/src/pynws/simple_nws.py index 6b30cc8..5b6bf92 100644 --- a/src/pynws/simple_nws.py +++ b/src/pynws/simple_nws.py @@ -23,6 +23,7 @@ from aiohttp import ClientResponseError, ClientSession from metar import Metar +from yarl import URL from .const import ALERT_ID, API_WEATHER_CODE, Final from .forecast import DetailedForecast @@ -177,9 +178,10 @@ def parse_icon(icon: str) -> Tuple[str, _WeatherCodes]: Example return: ('day', (('skc', None), ('tsra', 40),)) """ - icon_list = icon.split("/") - time = icon_list[5] - weather = [i.split("?")[0] for i in icon_list[6:]] + icon_url = URL(icon) + icon_parts = icon_url.parts + time = icon_parts[3] + weather = icon_parts[4:] code = [w.split(",")[0] for w in weather] chance = [int(w.split(",")[1]) if len(w.split(",")) == 2 else None for w in weather] return time, list(zip(code, chance)) diff --git a/tests/fixtures/gridpoints_forecast_relative_icon.json b/tests/fixtures/gridpoints_forecast_relative_icon.json new file mode 100644 index 0000000..c0cd9f6 --- /dev/null +++ b/tests/fixtures/gridpoints_forecast_relative_icon.json @@ -0,0 +1,119 @@ +{ + "@context": [ + "https://raw.githubusercontent.com/geojson/geojson-ld/master/contexts/geojson-base.jsonld", + { + "wx": "https://api.weather.gov/ontology#", + "geo": "http://www.opengis.net/ont/geosparql#", + "unit": "http://codes.wmo.int/common/unit/", + "@vocab": "https://api.weather.gov/ontology#" + } + ], + "type": "Feature", + "geometry": { + "type": "GeometryCollection", + "geometries": [ + { + "type": "Point", + "coordinates": [ + -84.956046999999998, + 29.995017300000001 + ] + }, + { + "type": "Polygon", + "coordinates": [ + [ + [ + -84.968174099999999, + 30.007206 + ], + [ + -84.970116500000003, + 29.984511300000001 + ], + [ + -84.943922400000005, + 29.982827500000003 + ], + [ + -84.941974999999999, + 30.005522000000003 + ], + [ + -84.968174099999999, + 30.007206 + ] + ] + ] + } + ] + }, + "properties": { + "updated": "2019-10-13T18:16:20+00:00", + "units": "us", + "forecastGenerator": "BaselineForecastGenerator", + "generatedAt": "2019-10-13T18:42:44+00:00", + "updateTime": "2019-10-13T18:16:20+00:00", + "validTimes": "2019-10-13T12:00:00+00:00/P6DT22H", + "elevation": { + "value": 7.9248000000000003, + "unitCode": "unit:m" + }, + "periods": [ + { + "number": 1, + "name": "This Afternoon", + "startTime": "2019-10-13T14:00:00-04:00", + "endTime": "2019-10-13T18:00:00-04:00", + "isDaytime": true, + "temperature": 41, + "temperatureUnit": "F", + "temperatureTrend": null, + "probabilityOfPrecipitation": { + "unitCode": "wmoUnit:percent", + "value": 20 + }, + "dewpoint": { + "unitCode": "wmoUnit:degC", + "value": 5 + }, + "relativeHumidity": { + "unitCode": "wmoUnit:percent", + "value": 63 + }, + "windSpeed": "10 mph", + "windDirection": "S", + "icon": "/icons/land/day/tsra,40/ovc?size=medium", + "shortForecast": "Chance Showers And Thunderstorms", + "detailedForecast": "" + }, + { + "number": 2, + "name": "Tonight", + "startTime": "2019-10-13T18:00:00-04:00", + "endTime": "2019-10-14T06:00:00-04:00", + "isDaytime": false, + "temperature": 68, + "temperatureUnit": "F", + "temperatureTrend": null, + "probabilityOfPrecipitation": { + "unitCode": "wmoUnit:percent", + "value": null + }, + "dewpoint": { + "unitCode": "wmoUnit:degC", + "value": 5 + }, + "relativeHumidity": { + "unitCode": "wmoUnit:percent", + "value": 63 + }, + "windSpeed": "0 to 5 mph", + "windDirection": "S", + "icon": "/icons/land/night/few?size=medium", + "shortForecast": "Mostly Clear", + "detailedForecast": "Mostly clear, with a low around 68. South wind 0 to 5 mph." + } + ] + } +} diff --git a/tests/fixtures/stations_observations_relative_icon.json b/tests/fixtures/stations_observations_relative_icon.json new file mode 100644 index 0000000..0ccd17e --- /dev/null +++ b/tests/fixtures/stations_observations_relative_icon.json @@ -0,0 +1,168 @@ +{ + "@context": [ + "https://raw.githubusercontent.com/geojson/geojson-ld/master/contexts/geojson-base.jsonld", + { + "wx": "https://api.weather.gov/ontology#", + "s": "https://schema.org/", + "geo": "http://www.opengis.net/ont/geosparql#", + "unit": "http://codes.wmo.int/common/unit/", + "@vocab": "https://api.weather.gov/ontology#", + "geometry": { + "@id": "s:GeoCoordinates", + "@type": "geo:wktLiteral" + }, + "city": "s:addressLocality", + "state": "s:addressRegion", + "distance": { + "@id": "s:Distance", + "@type": "s:QuantitativeValue" + }, + "bearing": { + "@type": "s:QuantitativeValue" + }, + "value": { + "@id": "s:value" + }, + "unitCode": { + "@id": "s:unitCode", + "@type": "@id" + }, + "forecastOffice": { + "@type": "@id" + }, + "forecastGridData": { + "@type": "@id" + }, + "publicZone": { + "@type": "@id" + }, + "county": { + "@type": "@id" + } + } + ], + "type": "FeatureCollection", + "features": [ + { + "id": "https://api.weather.gov/stations/KFLL/observations/2019-06-27T10:53:00+00:00", + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ + -80.150000000000006, + 26.07 + ] + }, + "properties": { + "@id": "https://api.weather.gov/stations/KFLL/observations/2019-06-27T10:53:00+00:00", + "@type": "wx:ObservationStation", + "elevation": { + "value": 10, + "unitCode": "unit:m" + }, + "station": "https://api.weather.gov/stations/KFLL", + "timestamp": "2019-06-27T10:53:00+00:00", + "rawMessage": "KFLL 271053Z 35005KT 10SM FEW025 FEW250 26/23 A3005 RMK AO2 SLP176 T02560228", + "textDescription": "Mostly Clear", + "icon": "/icons/land/day/few?size=medium", + "presentWeather": [], + "temperature": { + "value": 10, + "unitCode": "unit:degC", + "qualityControl": "qc:V" + }, + "dewpoint": { + "value": 10, + "unitCode": "unit:degC", + "qualityControl": "qc:V" + }, + "windDirection": { + "value": 10, + "unitCode": "unit:degree_(angle)", + "qualityControl": "qc:V" + }, + "windSpeed": { + "value": 10, + "unitCode": "unit:m_s-1", + "qualityControl": "qc:V" + }, + "windGust": { + "value": 10, + "unitCode": "unit:m_s-1", + "qualityControl": "qc:Z" + }, + "barometricPressure": { + "value": 100000, + "unitCode": "unit:Pa", + "qualityControl": "qc:V" + }, + "seaLevelPressure": { + "value": 100000, + "unitCode": "unit:Pa", + "qualityControl": "qc:V" + }, + "visibility": { + "value": 10000, + "unitCode": "unit:m", + "qualityControl": "qc:C" + }, + "maxTemperatureLast24Hours": { + "value": null, + "unitCode": "unit:degC", + "qualityControl": null + }, + "minTemperatureLast24Hours": { + "value": null, + "unitCode": "unit:degC", + "qualityControl": null + }, + "precipitationLastHour": { + "value": null, + "unitCode": "unit:m", + "qualityControl": "qc:Z" + }, + "precipitationLast3Hours": { + "value": null, + "unitCode": "unit:m", + "qualityControl": "qc:Z" + }, + "precipitationLast6Hours": { + "value": null, + "unitCode": "unit:m", + "qualityControl": "qc:Z" + }, + "relativeHumidity": { + "value": 10, + "unitCode": "unit:percent", + "qualityControl": "qc:C" + }, + "windChill": { + "value": null, + "unitCode": "unit:degC", + "qualityControl": "qc:V" + }, + "heatIndex": { + "value": 10, + "unitCode": "unit:degC", + "qualityControl": "qc:V" + }, + "cloudLayers": [ + { + "base": { + "value": 760, + "unitCode": "unit:m" + }, + "amount": "FEW" + }, + { + "base": { + "value": 7620, + "unitCode": "unit:m" + }, + "amount": "FEW" + } + ] + } + } + ] +} diff --git a/tests/test_simple_nws.py b/tests/test_simple_nws.py index c39114d..22b5173 100644 --- a/tests/test_simple_nws.py +++ b/tests/test_simple_nws.py @@ -40,6 +40,7 @@ async def test_nws_set_station_none(aiohttp_client, mock_urls): "stations_observations_strings.json", "stations_observations_other_unitcode.json", "stations_observations_multiple_unsorted.json", + "stations_observations_relative_icon.json", ], ) async def test_nws_observation(aiohttp_client, mock_urls, observation_json): @@ -230,9 +231,15 @@ async def test_nws_observation_missing_value(aiohttp_client, mock_urls): assert observation["iconWeather"] is None +@pytest.mark.parametrize( + "gridpoints_forecast", + ["gridpoints_forecast.json", "gridpoints_forecast_relative_icon.json"], +) @freeze_time("2019-10-13T14:30:00-04:00") -async def test_nws_forecast(aiohttp_client, mock_urls): - app = setup_app() +async def test_nws_forecast(aiohttp_client, mock_urls, gridpoints_forecast): + app = setup_app( + gridpoints_forecast=gridpoints_forecast, + ) client = await aiohttp_client(app) nws = SimpleNWS(*LATLON, USERID, client) await nws.update_forecast()