Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sort station observations at lower layer; Add latest observation #72

Merged
merged 8 commits into from
Mar 13, 2022
1 change: 1 addition & 0 deletions pynws/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
API_URL = "https://api.weather.gov/"
API_POINTS_STATIONS = "points/{},{}/stations"
API_STATIONS_OBSERVATIONS = "stations/{}/observations/"
API_STATIONS_OBSERVATIONS_LATEST = "stations/{}/observations/latest"
API_ACCEPT = "application/geo+json"
API_USER = "pynws {}"
API_DETAILED_FORECAST = "gridpoints/{}/{},{}"
Expand Down
13 changes: 12 additions & 1 deletion pynws/nws.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
raw_points,
raw_points_stations,
raw_stations_observations,
raw_stations_observations_latest,
)
from pynws.forecast import DetailedForecast

Expand Down Expand Up @@ -50,7 +51,17 @@ async def get_stations_observations(self, limit=0, start_time=None):
res = await raw_stations_observations(
self.station, self.session, self.userid, limit, start_time
)
return [o["properties"] for o in res["features"]]
observations = [o["properties"] for o in res["features"]]
return sorted(observations, key=lambda o: o.get("timestamp"), reverse=True)

async def get_stations_observations_latest(self):
"""Returns latest observation"""
if self.station is None:
raise NwsError("Need to set station")
res = await raw_stations_observations_latest(
self.station, self.session, self.userid
)
return res.get("properties")

async def get_points(self):
"""Saves griddata from latlon."""
Expand Down
7 changes: 7 additions & 0 deletions pynws/raw_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ async def raw_stations_observations(station, websession, userid, limit=0, start=
return await _make_request(websession, url, header, params)


async def raw_stations_observations_latest(station, websession, userid):
"""Get observation response from station"""
url = pynws.urls.stations_observations_latest_url(station)
header = get_header(userid)
return await _make_request(websession, url, header)


async def raw_points_stations(lat, lon, websession, userid):
"""Get list of stations for lat/lon"""
url = pynws.urls.points_stations_url(lat, lon)
Expand Down
6 changes: 1 addition & 5 deletions pynws/simple_nws.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,11 +168,7 @@ async def update_observation(self, limit=0, start_time=None):
obs = await self.get_stations_observations(limit, start_time=start_time)
if obs is None:
return None
self._observation = sorted(
obs,
key=lambda item: self.extract_observation_value(item, "timestamp"),
reverse=True,
)
self._observation = obs
self._metar_obs = [self.extract_metar(iobs) for iobs in self._observation]

async def update_forecast(self):
Expand Down
6 changes: 6 additions & 0 deletions pynws/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
API_POINTS,
API_POINTS_STATIONS,
API_STATIONS_OBSERVATIONS,
API_STATIONS_OBSERVATIONS_LATEST,
API_URL,
)

Expand All @@ -16,6 +17,11 @@ def stations_observations_url(station):
return API_URL + API_STATIONS_OBSERVATIONS.format(station)


def stations_observations_latest_url(station):
"""Formats observation url."""
return API_URL + API_STATIONS_OBSERVATIONS_LATEST.format(station)


def points_stations_url(lat, lon):
"""formats station url"""
return API_URL + API_POINTS_STATIONS.format(str(lat), str(lon))
Expand Down
7 changes: 6 additions & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ def mock_urls():
with patch(
"pynws.urls.stations_observations_url"
) as mock_stations_observations_url, patch(
"pynws.urls.stations_observations_latest_url"
) as mock_stations_observations_latest_url, patch(
"pynws.urls.points_url"
) as mock_points_url, patch(
"pynws.urls.detailed_forecast_url"
Expand All @@ -20,11 +22,14 @@ def mock_urls():
"pynws.urls.alerts_active_zone_url"
) as mock_alerts_active_zone_url:
mock_stations_observations_url.return_value = "/stations_observations"
mock_stations_observations_latest_url.return_value = (
"/stations_observations_latest"
)
mock_points_url.return_value = "/points"
mock_detailed_forecast_url.return_value = "/gridpoints"
mock_gridpoints_forecast_url.return_value = "/gridpoints_forecast"
mock_gridpoints_forecast_hourly_url.return_value = "/gridpoints_forecast_hourly"
mock_points_stations_url.return_value = "/points_stations"
mock_alerts_active_zone_url.return_value = "/alerts_active_zone"

yield mock_stations_observations_url, mock_points_url, mock_detailed_forecast_url, mock_gridpoints_forecast_url, mock_gridpoints_forecast_hourly_url, mock_points_stations_url, mock_alerts_active_zone_url
yield mock_stations_observations_url, mock_stations_observations_latest_url, mock_points_url, mock_detailed_forecast_url, mock_gridpoints_forecast_url, mock_gridpoints_forecast_hourly_url, mock_points_stations_url, mock_alerts_active_zone_url
162 changes: 162 additions & 0 deletions tests/fixtures/stations_observations_latest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
{
"@context": [
"https://geojson.org/geojson-ld/geojson-context.jsonld",
{
"@version": "1.1",
"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"
}
}
],
"id": "https://api.weather.gov/stations/KFLL/observations/2022-03-02T23:53:00+00:00",
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
-80.150000000000006,
26.07
]
},
"properties": {
"@id": "https://api.weather.gov/stations/KFLL/observations/2022-03-02T23:53:00+00:00",
"@type": "wx:ObservationStation",
"elevation": {
"unitCode": "wmoUnit:m",
"value": 3
},
"station": "https://api.weather.gov/stations/KFLL",
"timestamp": "2022-03-02T23:53:00+00:00",
"rawMessage": "KFLL 022353Z 02004KT 10SM FEW026 BKN055 23/18 A3008 RMK AO2 SLP187 60000 T02280183 10244 20228 53008 $",
"textDescription": "Mostly Cloudy",
"icon": "https://api.weather.gov/icons/land/night/bkn?size=medium",
"presentWeather": [],
"temperature": {
"unitCode": "wmoUnit:degC",
"value": 22.800000000000001,
"qualityControl": "V"
},
"dewpoint": {
"unitCode": "wmoUnit:degC",
"value": 18.300000000000001,
"qualityControl": "V"
},
"windDirection": {
"unitCode": "wmoUnit:degree_(angle)",
"value": 20,
"qualityControl": "V"
},
"windSpeed": {
"unitCode": "wmoUnit:km_h-1",
"value": 7.5599999999999996,
"qualityControl": "V"
},
"windGust": {
"unitCode": "wmoUnit:km_h-1",
"value": null,
"qualityControl": "Z"
},
"barometricPressure": {
"unitCode": "wmoUnit:Pa",
"value": 101860,
"qualityControl": "V"
},
"seaLevelPressure": {
"unitCode": "wmoUnit:Pa",
"value": 101870,
"qualityControl": "V"
},
"visibility": {
"unitCode": "wmoUnit:m",
"value": 16090,
"qualityControl": "C"
},
"maxTemperatureLast24Hours": {
"unitCode": "wmoUnit:degC",
"value": null
},
"minTemperatureLast24Hours": {
"unitCode": "wmoUnit:degC",
"value": null
},
"precipitationLastHour": {
"unitCode": "wmoUnit:m",
"value": null,
"qualityControl": "Z"
},
"precipitationLast3Hours": {
"unitCode": "wmoUnit:m",
"value": null,
"qualityControl": "Z"
},
"precipitationLast6Hours": {
"unitCode": "wmoUnit:m",
"value": 0,
"qualityControl": "C"
},
"relativeHumidity": {
"unitCode": "wmoUnit:percent",
"value": 75.770935807607003,
"qualityControl": "V"
},
"windChill": {
"unitCode": "wmoUnit:degC",
"value": null,
"qualityControl": "V"
},
"heatIndex": {
"unitCode": "wmoUnit:degC",
"value": 23.11401887942111,
"qualityControl": "V"
},
"cloudLayers": [
{
"base": {
"unitCode": "wmoUnit:m",
"value": 790
},
"amount": "FEW"
},
{
"base": {
"unitCode": "wmoUnit:m",
"value": 1680
},
"amount": "BKN"
}
]
}
}
5 changes: 5 additions & 0 deletions tests/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ def setup_app(
points_stations="points_stations.json",
points="points.json",
stations_observations="stations_observations.json",
stations_observations_latest="stations_observations_latest.json",
detailed_forecast="detailed_forecast.json",
gridpoints_forecast="gridpoints_forecast.json",
gridpoints_forecast_hourly="gridpoints_forecast_hourly.json",
Expand All @@ -33,6 +34,10 @@ def setup_app(
app.router.add_get(
"/stations_observations", data_return_function(stations_observations)
)
app.router.add_get(
"/stations_observations_latest",
data_return_function(stations_observations_latest),
)
app.router.add_get("/gridpoints", data_return_function(detailed_forecast))
app.router.add_get(
"/gridpoints_forecast", data_return_function(gridpoints_forecast)
Expand Down
13 changes: 13 additions & 0 deletions tests/test_nws.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,19 @@ async def test_nws_stations_observations(aiohttp_client, loop, mock_urls):
assert isinstance(observations, list)


async def test_nws_stations_observations_latest(aiohttp_client, loop, mock_urls):
app = setup_app()
client = await aiohttp_client(app)
nws = Nws(client, USERID, LATLON)
assert nws
with pytest.raises(NwsError):
await nws.get_stations_observations_latest()
nws.station = STATION
observation = await nws.get_stations_observations_latest()
assert observation
assert isinstance(observation, dict)


async def test_nws_detailed_forecast(aiohttp_client, loop, mock_urls):
app = setup_app()
client = await aiohttp_client(app)
Expand Down