Skip to content

Commit 3f4179d

Browse files
authored
Improve error handling and README. Update Ubuntu. (#67)
* Tweak error handling * Update README * Update ubuntu version * Update version
1 parent 2a278d7 commit 3f4179d

File tree

8 files changed

+27
-24
lines changed

8 files changed

+27
-24
lines changed

.github/workflows/pythonpackage.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ on:
77

88
jobs:
99
build:
10-
runs-on: ubuntu-20.04
10+
runs-on: ubuntu-24.04
1111
strategy:
1212
matrix:
1313
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]

README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,11 @@ Working example can be found in [example.py](example.py).
2525
$ pip install fmi-weather-client
2626
```
2727

28-
### Get weather and forecasts
28+
### Get weather, forecasts, and observations
2929
You can get the weather using the following functions:
3030
- `weather_by_place_name(place_name)`
3131
- `weather_by_coordinates(latitude, longitude)`
32+
- `observation_by_station_id(fmi_station_id)`
3233

3334
Example:
3435
```python
@@ -65,9 +66,11 @@ except ServerError as err:
6566

6667
```
6768

68-
You can get the observation data from a station ID [shown here](https://www.ilmatieteenlaitos.fi/havaintoasemat) using the following functions:
69+
You can get the observation data from a station using the following functions:
6970
- `observation_by_station_id(fmi_sid)`
7071

72+
To get a weather observation from a station, you must provide a station ID. IDs can be found on [FMI's station list](https://www.ilmatieteenlaitos.fi/havaintoasemat). Note that weather observations are available only from **weather stations**. These are the ones with `sää` in the `Ryhmä` column.
73+
7174
Example:
7275
```python
7376
import fmi_weather_client as fmi

example.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55
# Get current weather in Kilpisjärvi using coordinates
66
kilpisjarvi_weather = fmi.weather_by_coordinates(69.0478, 20.7982)
77

8-
# Get forecast for Helsinki
9-
helsinki_forecast = fmi.forecast_by_place_name("Helsinki")
10-
118
# Get observation data
129
oulu_observation = fmi.observation_by_station_id(101794)
1310

11+
# Get forecast for Helsinki
12+
helsinki_forecast = fmi.forecast_by_place_name("Helsinki")
13+
1414
# Print current temperature
1515
print()
1616
print(f"Temperature @ {kilpisjarvi_weather.place}: {kilpisjarvi_weather.data.temperature}")

fmi_weather_client/http.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ def _send_request(params: Dict[str, Any]) -> str:
155155
response = requests.get(url, params=params, timeout=10)
156156

157157
if response.status_code == 200:
158+
_validate_response(response)
158159
_LOGGER.debug("GET response from %s in %d ms. Status: %d.",
159160
url,
160161
response.elapsed.microseconds / 1000,
@@ -165,6 +166,16 @@ def _send_request(params: Dict[str, Any]) -> str:
165166
return response.text
166167

167168

169+
def _validate_response(response: requests.Response):
170+
"""Validate response body"""
171+
data = xmltodict.parse(response.text)
172+
173+
if ('wfs:FeatureCollection' in data and
174+
'@numberMatched' in data['wfs:FeatureCollection'] and
175+
data['wfs:FeatureCollection']['@numberMatched'] == '0'):
176+
raise ClientError(200, "Valid data source not found with given parameters")
177+
178+
168179
def _handle_errors(response: requests.Response):
169180
"""Handle error responses from FMI service"""
170181
if 400 <= response.status_code < 500:

fmi_weather_client/parsers/errors.py

Lines changed: 0 additions & 2 deletions
This file was deleted.

fmi_weather_client/parsers/forecast.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import xmltodict
99

1010
from fmi_weather_client.models import FMIPlace, Forecast, Value, WeatherData, RequestType
11-
from fmi_weather_client.parsers.errors import StationTypeError
1211

1312
_LOGGER = logging.getLogger(__name__)
1413

@@ -23,8 +22,6 @@ def parse_fmi_response(body: str, request_type: RequestType):
2322
data = xmltodict.parse(body)
2423

2524
try:
26-
_check_valid(data)
27-
2825
station = _get_place(data, request_type)
2926
_LOGGER.debug("Received place: %s (%d, %d)", station.name, station.lat, station.lon)
3027

@@ -61,12 +58,6 @@ def parse_fmi_response(body: str, request_type: RequestType):
6158
return Forecast(station.name, station.lat, station.lon, forecasts)
6259

6360

64-
def _check_valid(data: Dict[str, Any]):
65-
if data['wfs:FeatureCollection']['@numberMatched'] == '0':
66-
raise StationTypeError("no matched places/observation stations")
67-
return True
68-
69-
7061
def _get_place(data: Dict[str, Any], request_type: RequestType) -> FMIPlace:
7162
place_data = (data['wfs:FeatureCollection']['wfs:member']['omso:GridSeriesObservation']
7263
['om:featureOfInterest']['sams:SF_SpatialSamplingFeature']['sams:shape']

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
setuptools.setup(
77
name="fmi-weather-client",
8-
version="0.5.1",
8+
version="0.6.0",
99
author="Mika Hiltunen",
1010
author_email="saaste@gmail.com",
1111
description="Library for fetching weather information from Finnish Meteorological Institute (FMI)",

test/test_init.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import fmi_weather_client
77
import test.test_data as test_data
88
from fmi_weather_client.errors import ClientError, ServerError
9-
from fmi_weather_client.parsers.errors import StationTypeError
109

1110

1211
class FMIWeatherTest(unittest.TestCase):
@@ -84,11 +83,6 @@ def test_nil_forecast_response(self, mock_get):
8483
self.assertEqual(forecast_coord.forecasts, [])
8584
self.assertEqual(forecast_name.forecasts, [])
8685

87-
@mock.patch('requests.get', side_effect=test_data.mock_invalid_station_id_response)
88-
def test_invalid_observation_id(self, mock_get):
89-
with self.assertRaises(StationTypeError):
90-
fmi_weather_client.observation_by_station_id(103124)
91-
9286
# ERROR CASES
9387
@mock.patch('requests.get', side_effect=test_data.mock_no_location_exception_response)
9488
def test_no_location_exception_response(self, mock_get):
@@ -110,6 +104,11 @@ def test_server_error_response(self, mock_get):
110104
with self.assertRaises(ServerError):
111105
fmi_weather_client.weather_by_coordinates(27.31317, 63.14343)
112106

107+
@mock.patch('requests.get', side_effect=test_data.mock_invalid_station_id_response)
108+
def test_invalid_observation_id(self, mock_get):
109+
with self.assertRaises(ClientError):
110+
fmi_weather_client.observation_by_station_id(103124)
111+
113112
def assert_name_weather(self, weather):
114113
self.assertEqual(weather.place, 'Iisalmi')
115114
self.assertEqual(weather.data.time.timestamp(), 1663585800.0)
@@ -175,5 +174,6 @@ def assert_observation_id(self, weather):
175174
self.assertEqual(weather.data.temperature.value, -7.2)
176175
self.assertEqual(weather.data.wind_speed.value, 2.6)
177176

177+
178178
if __name__ == '__main__':
179179
unittest.main()

0 commit comments

Comments
 (0)