Skip to content

Commit d7917d4

Browse files
committed
ADD: Input validation
ADD: Flake8 and pydocstyle conformity
1 parent 541a593 commit d7917d4

File tree

6 files changed

+65
-71
lines changed

6 files changed

+65
-71
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## 1.0.2 (2020-04-25)
2+
### Added
3+
- Input validation
4+
- Flake8 and pydocstyle conformity
5+
16
## 1.0.1 (2020-04-20)
27
### Fixed
38
- DwdWeatherWarningsAPI: Exception handling when input data is None

dwdwfsapi/__init__.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
# -*- coding: utf-8 -*-
22

3-
"""
4-
Python client to retrieve data provided by DWD via their geoserver WFS API
5-
"""
3+
"""Python client to retrieve data provided by DWD via their WFS API."""
64

7-
from .weatherwarnings import DwdWeatherWarningsAPI
5+
from .weatherwarnings import DwdWeatherWarningsAPI # noqa: F401

dwdwfsapi/core.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
# -*- coding: utf-8 -*-
22

33
"""
4-
Collection of the core functions needed to communicate with the geoserver
5-
operated by the Deutscher Wetterdienst (DWD)
64
5+
Collection of the core functions needed to communicate with the geoserver.
6+
7+
The geoserver is operated by the Deutscher Wetterdienst (DWD).
78
https://maps.dwd.de
9+
810
"""
911

1012
import urllib.parse
@@ -16,9 +18,7 @@
1618

1719

1820
def query_dwd(**kwargs):
19-
"""
20-
Retrive data from DWD server.
21-
"""
21+
"""Retrive data from DWD server."""
2222
# Make all keys lowercase and escape all values
2323
kwargs = {k.lower(): urllib.parse.quote(v) for k, v in kwargs.items()}
2424

@@ -50,5 +50,5 @@ def query_dwd(**kwargs):
5050
if resp.status_code != 200:
5151
return None
5252
return resp.json()
53-
except: # pylint: disable=bare-except
53+
except: # pylint: disable=bare-except # noqa: E722
5454
return None

dwdwfsapi/weatherwarnings.py

Lines changed: 26 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
# -*- coding: utf-8 -*-
22

3-
"""
4-
Python client to retrieve weather warnings from Deutscher Wetterdienst (DWD)
5-
"""
3+
"""Python client to retrieve weather warnings from DWD."""
64

75
# pylint: disable=c-extension-no-member
86
import datetime
@@ -11,10 +9,7 @@
119

1210

1311
def convert_warning_data(data_in):
14-
"""
15-
Convert the data received from DWD
16-
"""
17-
12+
"""Convert the data received from DWD."""
1813
# pylint: disable=too-many-branches
1914
# pylint: disable=too-many-statements
2015

@@ -46,19 +41,19 @@ def convert_warning_data(data_in):
4641
if "onset" in data_in:
4742
try:
4843
data_out["start_time"] = ciso8601.parse_datetime(data_in["onset"])
49-
except: # pylint: disable=bare-except
44+
except: # pylint: disable=bare-except # noqa: E722
5045
data_out["start_time"] = None
5146
if "expires" in data_in:
5247
try:
5348
data_out["end_time"] = ciso8601.parse_datetime(data_in["expires"])
54-
except: # pylint: disable=bare-except
49+
except: # pylint: disable=bare-except # noqa: E722
5550
data_out["end_time"] = None
5651
if "event" in data_in:
5752
data_out["event"] = data_in["event"]
5853
if "ec_ii" in data_in:
5954
try:
6055
data_out["event_code"] = int(data_in["ec_ii"])
61-
except: # pylint: disable=bare-except
56+
except: # pylint: disable=bare-except # noqa: E722
6257
data_out["event_code"] = 0
6358
if "headline" in data_in:
6459
data_out["headline"] = data_in["headline"]
@@ -72,10 +67,11 @@ def convert_warning_data(data_in):
7267
data_out["level"] = weather_severity_mapping[
7368
data_in["severity"].lower()
7469
]
75-
except: # pylint: disable=bare-except
70+
except: # pylint: disable=bare-except # noqa: E722
7671
data_out["level"] = 0
7772
if "parametername" in data_in and "parametervalue" in data_in:
78-
# Depending on the query the keys and values are either seperated by , or ;
73+
# Depending on the query the keys and values are either seperated
74+
# by , or ;
7975
try:
8076
if "," in data_in["parametername"]:
8177
keys = data_in["parametername"].split(",")
@@ -84,22 +80,22 @@ def convert_warning_data(data_in):
8480
keys = data_in["parametername"].split(";")
8581
values = data_in["parametervalue"].split(";")
8682
data_out["parameters"] = dict(zip(keys, values))
87-
except: # pylint: disable=bare-except
83+
except: # pylint: disable=bare-except # noqa: E722
8884
data_out["parameters"] = None
8985
if "ec_area_color" in data_in:
9086
try:
9187
colors = data_in["ec_area_color"].split(" ")
9288
data_out["color"] = f"#{int(colors[0]):02x}{int(colors[1]):02x}"
9389
data_out["color"] += f"{int(colors[2]):02x}"
94-
except: # pylint: disable=bare-except
90+
except: # pylint: disable=bare-except # noqa: E722
9591
data_out["color"] = "#000000"
9692

9793
return data_out
9894

9995

10096
class DwdWeatherWarningsAPI:
10197
"""
102-
Class for retrieving weather warnings from DWD
98+
Class for retrieving weather warnings from DWD.
10399
104100
Attributes:
105101
-----------
@@ -148,7 +144,7 @@ class DwdWeatherWarningsAPI:
148144

149145
def __init__(self, identifier):
150146
"""
151-
Init DWD weather warnings
147+
Init DWD weather warnings.
152148
153149
Parameters
154150
----------
@@ -170,30 +166,27 @@ def __init__(self, identifier):
170166
self.expected_warning_level = None
171167
self.expected_warnings = None
172168

173-
self.__generate_query(identifier)
169+
# Identifier must be either integer or string
170+
if not isinstance(identifier, (int, str)):
171+
return
174172

173+
self.__generate_query(identifier)
175174
self.update()
176175

177176
def __bool__(self):
178-
"""
179-
Returns the data_valid attribute
180-
"""
177+
"""Return the data_valid attribute."""
181178
return self.data_valid
182179

183180
def __len__(self):
184-
"""
185-
Returns the sum of current and expected warnings
186-
"""
181+
"""Return the sum of current and expected warnings."""
187182
if self.data_valid:
188183
length = len(self.current_warnings) + len(self.expected_warnings)
189184
else:
190185
length = 0
191186
return length
192187

193188
def __str__(self):
194-
"""
195-
Returns a short overview about the actual status
196-
"""
189+
"""Return a short overview about the actual status."""
197190
if self.data_valid:
198191
retval = f"{len(self.current_warnings)} current and"
199192
retval += f" {len(self.expected_warnings)} expected warnings"
@@ -203,9 +196,7 @@ def __str__(self):
203196
return retval
204197

205198
def update(self):
206-
"""
207-
Update data by querying DWD server and parsing result
208-
"""
199+
"""Update data by querying DWD server and parsing result."""
209200
if self.__query is None:
210201
return
211202

@@ -222,9 +213,7 @@ def update(self):
222213
self.expected_warnings = None
223214

224215
def __generate_query(self, identifier):
225-
"""
226-
Determine the warning region to which the identifier belongs
227-
"""
216+
"""Determine the warning region to which the identifier belongs."""
228217
weather_warnings_query_mapping = {
229218
"dwd:Warngebiete_Gemeinden": "dwd:Warnungen_Gemeinden",
230219
"dwd:Warngebiete_Kreise": "dwd:Warnungen_Landkreise",
@@ -251,7 +240,8 @@ def __generate_query(self, identifier):
251240
self.warncell_name = result["features"][0]["properties"][
252241
"NAME"
253242
]
254-
# More than one match found. Can only happen if search is done by name.
243+
# More than one match found. Can only happen if search is
244+
# done by name.
255245
if result["numberReturned"] > 1:
256246
self.warncell_name += " (not unique used ID)!"
257247

@@ -270,9 +260,7 @@ def __generate_query(self, identifier):
270260
break
271261

272262
def __parse_result(self, json_obj):
273-
"""
274-
Parse the retrieved data
275-
"""
263+
"""Parse the retrieved data."""
276264
try:
277265
current_maxlevel = 0
278266
expected_maxlevel = 0
@@ -284,7 +272,7 @@ def __parse_result(self, json_obj):
284272
self.last_update = ciso8601.parse_datetime(
285273
json_obj["timeStamp"]
286274
)
287-
except: # pylint: disable=bare-except
275+
except: # pylint: disable=bare-except # noqa: E722
288276
self.last_update = datetime.datetime.now(
289277
datetime.timezone.utc
290278
)
@@ -325,7 +313,7 @@ def __parse_result(self, json_obj):
325313
self.expected_warnings = expected_warnings
326314
self.data_valid = True
327315

328-
except: # pylint: disable=bare-except
316+
except: # pylint: disable=bare-except # noqa: E722
329317
self.data_valid = False
330318
self.last_update = None
331319
self.current_warning_level = None

setup.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
11
# -*- coding: utf-8 -*-
22

3-
"""
4-
Setup for dwdwfsapi package
5-
"""
3+
"""Setup for dwdwfsapi package."""
64

75
from setuptools import setup, find_packages
86

97
# Package meta-data
108
NAME = "dwdwfsapi"
11-
DESCRIPTION = "Python client to retrieve data provided by DWD via their geoserver WFS API"
9+
DESCRIPTION = (
10+
"Python client to retrieve data provided by DWD via their geoserver "
11+
"WFS API"
12+
)
1213
KEYWORDS = "dwd ows wfs deutscher wetterdienst"
1314
URL = "https://github.com/stephan192/dwdwfsapi"
1415
EMAIL = "stephan192@outlook.com"
1516
AUTHOR = "stephan192"
1617
REQUIRES_PYTHON = ">=3.6"
17-
VERSION = "1.0.1"
18+
VERSION = "1.0.2"
1819

1920
# Define required packages
2021
REQUIRES = ["requests>=2.23.0,<3", "ciso8601>=2.1.3,<3", "urllib3>=1.25.8,<2"]
@@ -36,6 +37,7 @@
3637
packages=find_packages(),
3738
install_requires=REQUIRES,
3839
keywords=KEYWORDS,
40+
license="MIT",
3941
classifiers=[
4042
"Development Status :: 5 - Production/Stable",
4143
"Programming Language :: Python :: 3",

tests/test_weatherwarnings.py

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
# -*- coding: utf-8 -*-
2-
"""
3-
Tests for dwdwfsapi weatherwarnings module
4-
"""
2+
"""Tests for dwdwfsapi weatherwarnings module."""
53

64
import datetime
75
from dwdwfsapi import DwdWeatherWarningsAPI
@@ -23,9 +21,7 @@
2321

2422

2523
def test_city():
26-
"""
27-
Test a city warncell
28-
"""
24+
"""Test a city warncell."""
2925
dwd = DwdWeatherWarningsAPI(WARNCELL_ID_CITY)
3026
assert dwd.data_valid
3127
assert dwd.warncell_id == WARNCELL_ID_CITY
@@ -42,9 +38,7 @@ def test_city():
4238

4339

4440
def test_county():
45-
"""
46-
Test a county warncell
47-
"""
41+
"""Test a county warncell."""
4842
dwd = DwdWeatherWarningsAPI(WARNCELL_NAME_COUNTY)
4943
assert dwd.data_valid
5044
assert dwd.warncell_id == WARNCELL_ID_COUNTY
@@ -61,9 +55,7 @@ def test_county():
6155

6256

6357
def test_lake():
64-
"""
65-
Test a lake warncell
66-
"""
58+
"""Test a lake warncell."""
6759
dwd = DwdWeatherWarningsAPI(WARNCELL_ID_LAKE)
6860
assert dwd.data_valid
6961
assert dwd.warncell_id == WARNCELL_ID_LAKE
@@ -80,9 +72,7 @@ def test_lake():
8072

8173

8274
def test_coast():
83-
"""
84-
Test a coast warncell
85-
"""
75+
"""Test a coast warncell."""
8676
dwd = DwdWeatherWarningsAPI(WARNCELL_NAME_COAST)
8777
assert dwd.data_valid
8878
assert dwd.warncell_id == WARNCELL_ID_COAST
@@ -99,9 +89,7 @@ def test_coast():
9989

10090

10191
def test_sea():
102-
"""
103-
Test a sea warncell
104-
"""
92+
"""Test a sea warncell."""
10593
dwd = DwdWeatherWarningsAPI(WARNCELL_ID_SEA)
10694
assert dwd.data_valid
10795
assert dwd.warncell_id == WARNCELL_ID_SEA
@@ -115,3 +103,16 @@ def test_sea():
115103
assert MIN_WARNING_LEVEL <= dwd.expected_warning_level <= MAX_WARNING_LEVEL
116104
assert isinstance(dwd.current_warnings, list)
117105
assert isinstance(dwd.expected_warnings, list)
106+
107+
108+
def test_wrong_input():
109+
"""Test an invalid input."""
110+
dwd = DwdWeatherWarningsAPI(None)
111+
assert not dwd.data_valid
112+
assert dwd.warncell_id is None
113+
assert dwd.warncell_name is None
114+
assert dwd.last_update is None
115+
assert dwd.current_warning_level is None
116+
assert dwd.expected_warning_level is None
117+
assert dwd.current_warnings is None
118+
assert dwd.expected_warnings is None

0 commit comments

Comments
 (0)