Skip to content

Commit

Permalink
use yarl to handle icon url for parsing of condition (#208)
Browse files Browse the repository at this point in the history
  • Loading branch information
MatthewFlamm authored Jun 20, 2024
1 parent aae2aee commit fe4b9c2
Show file tree
Hide file tree
Showing 6 changed files with 304 additions and 6 deletions.
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"}
Expand Down
1 change: 1 addition & 0 deletions requirements-test.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
8 changes: 5 additions & 3 deletions src/pynws/simple_nws.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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))
Expand Down
119 changes: 119 additions & 0 deletions tests/fixtures/gridpoints_forecast_relative_icon.json
Original file line number Diff line number Diff line change
@@ -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."
}
]
}
}
168 changes: 168 additions & 0 deletions tests/fixtures/stations_observations_relative_icon.json
Original file line number Diff line number Diff line change
@@ -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"
}
]
}
}
]
}
11 changes: 9 additions & 2 deletions tests/test_simple_nws.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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()
Expand Down

0 comments on commit fe4b9c2

Please sign in to comment.