Skip to content

Commit

Permalink
ADD: Input validation
Browse files Browse the repository at this point in the history
ADD: Flake8 and pydocstyle conformity
  • Loading branch information
stephan192 committed Apr 25, 2020
1 parent 541a593 commit d7917d4
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 71 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 1.0.2 (2020-04-25)
### Added
- Input validation
- Flake8 and pydocstyle conformity

## 1.0.1 (2020-04-20)
### Fixed
- DwdWeatherWarningsAPI: Exception handling when input data is None
Expand Down
6 changes: 2 additions & 4 deletions dwdwfsapi/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# -*- coding: utf-8 -*-

"""
Python client to retrieve data provided by DWD via their geoserver WFS API
"""
"""Python client to retrieve data provided by DWD via their WFS API."""

from .weatherwarnings import DwdWeatherWarningsAPI
from .weatherwarnings import DwdWeatherWarningsAPI # noqa: F401
12 changes: 6 additions & 6 deletions dwdwfsapi/core.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
# -*- coding: utf-8 -*-

"""
Collection of the core functions needed to communicate with the geoserver
operated by the Deutscher Wetterdienst (DWD)
Collection of the core functions needed to communicate with the geoserver.
The geoserver is operated by the Deutscher Wetterdienst (DWD).
https://maps.dwd.de
"""

import urllib.parse
Expand All @@ -16,9 +18,7 @@


def query_dwd(**kwargs):
"""
Retrive data from DWD server.
"""
"""Retrive data from DWD server."""
# Make all keys lowercase and escape all values
kwargs = {k.lower(): urllib.parse.quote(v) for k, v in kwargs.items()}

Expand Down Expand Up @@ -50,5 +50,5 @@ def query_dwd(**kwargs):
if resp.status_code != 200:
return None
return resp.json()
except: # pylint: disable=bare-except
except: # pylint: disable=bare-except # noqa: E722
return None
64 changes: 26 additions & 38 deletions dwdwfsapi/weatherwarnings.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
# -*- coding: utf-8 -*-

"""
Python client to retrieve weather warnings from Deutscher Wetterdienst (DWD)
"""
"""Python client to retrieve weather warnings from DWD."""

# pylint: disable=c-extension-no-member
import datetime
Expand All @@ -11,10 +9,7 @@


def convert_warning_data(data_in):
"""
Convert the data received from DWD
"""

"""Convert the data received from DWD."""
# pylint: disable=too-many-branches
# pylint: disable=too-many-statements

Expand Down Expand Up @@ -46,19 +41,19 @@ def convert_warning_data(data_in):
if "onset" in data_in:
try:
data_out["start_time"] = ciso8601.parse_datetime(data_in["onset"])
except: # pylint: disable=bare-except
except: # pylint: disable=bare-except # noqa: E722
data_out["start_time"] = None
if "expires" in data_in:
try:
data_out["end_time"] = ciso8601.parse_datetime(data_in["expires"])
except: # pylint: disable=bare-except
except: # pylint: disable=bare-except # noqa: E722
data_out["end_time"] = None
if "event" in data_in:
data_out["event"] = data_in["event"]
if "ec_ii" in data_in:
try:
data_out["event_code"] = int(data_in["ec_ii"])
except: # pylint: disable=bare-except
except: # pylint: disable=bare-except # noqa: E722
data_out["event_code"] = 0
if "headline" in data_in:
data_out["headline"] = data_in["headline"]
Expand All @@ -72,10 +67,11 @@ def convert_warning_data(data_in):
data_out["level"] = weather_severity_mapping[
data_in["severity"].lower()
]
except: # pylint: disable=bare-except
except: # pylint: disable=bare-except # noqa: E722
data_out["level"] = 0
if "parametername" in data_in and "parametervalue" in data_in:
# Depending on the query the keys and values are either seperated by , or ;
# Depending on the query the keys and values are either seperated
# by , or ;
try:
if "," in data_in["parametername"]:
keys = data_in["parametername"].split(",")
Expand All @@ -84,22 +80,22 @@ def convert_warning_data(data_in):
keys = data_in["parametername"].split(";")
values = data_in["parametervalue"].split(";")
data_out["parameters"] = dict(zip(keys, values))
except: # pylint: disable=bare-except
except: # pylint: disable=bare-except # noqa: E722
data_out["parameters"] = None
if "ec_area_color" in data_in:
try:
colors = data_in["ec_area_color"].split(" ")
data_out["color"] = f"#{int(colors[0]):02x}{int(colors[1]):02x}"
data_out["color"] += f"{int(colors[2]):02x}"
except: # pylint: disable=bare-except
except: # pylint: disable=bare-except # noqa: E722
data_out["color"] = "#000000"

return data_out


class DwdWeatherWarningsAPI:
"""
Class for retrieving weather warnings from DWD
Class for retrieving weather warnings from DWD.
Attributes:
-----------
Expand Down Expand Up @@ -148,7 +144,7 @@ class DwdWeatherWarningsAPI:

def __init__(self, identifier):
"""
Init DWD weather warnings
Init DWD weather warnings.
Parameters
----------
Expand All @@ -170,30 +166,27 @@ def __init__(self, identifier):
self.expected_warning_level = None
self.expected_warnings = None

self.__generate_query(identifier)
# Identifier must be either integer or string
if not isinstance(identifier, (int, str)):
return

self.__generate_query(identifier)
self.update()

def __bool__(self):
"""
Returns the data_valid attribute
"""
"""Return the data_valid attribute."""
return self.data_valid

def __len__(self):
"""
Returns the sum of current and expected warnings
"""
"""Return the sum of current and expected warnings."""
if self.data_valid:
length = len(self.current_warnings) + len(self.expected_warnings)
else:
length = 0
return length

def __str__(self):
"""
Returns a short overview about the actual status
"""
"""Return a short overview about the actual status."""
if self.data_valid:
retval = f"{len(self.current_warnings)} current and"
retval += f" {len(self.expected_warnings)} expected warnings"
Expand All @@ -203,9 +196,7 @@ def __str__(self):
return retval

def update(self):
"""
Update data by querying DWD server and parsing result
"""
"""Update data by querying DWD server and parsing result."""
if self.__query is None:
return

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

def __generate_query(self, identifier):
"""
Determine the warning region to which the identifier belongs
"""
"""Determine the warning region to which the identifier belongs."""
weather_warnings_query_mapping = {
"dwd:Warngebiete_Gemeinden": "dwd:Warnungen_Gemeinden",
"dwd:Warngebiete_Kreise": "dwd:Warnungen_Landkreise",
Expand All @@ -251,7 +240,8 @@ def __generate_query(self, identifier):
self.warncell_name = result["features"][0]["properties"][
"NAME"
]
# More than one match found. Can only happen if search is done by name.
# More than one match found. Can only happen if search is
# done by name.
if result["numberReturned"] > 1:
self.warncell_name += " (not unique used ID)!"

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

def __parse_result(self, json_obj):
"""
Parse the retrieved data
"""
"""Parse the retrieved data."""
try:
current_maxlevel = 0
expected_maxlevel = 0
Expand All @@ -284,7 +272,7 @@ def __parse_result(self, json_obj):
self.last_update = ciso8601.parse_datetime(
json_obj["timeStamp"]
)
except: # pylint: disable=bare-except
except: # pylint: disable=bare-except # noqa: E722
self.last_update = datetime.datetime.now(
datetime.timezone.utc
)
Expand Down Expand Up @@ -325,7 +313,7 @@ def __parse_result(self, json_obj):
self.expected_warnings = expected_warnings
self.data_valid = True

except: # pylint: disable=bare-except
except: # pylint: disable=bare-except # noqa: E722
self.data_valid = False
self.last_update = None
self.current_warning_level = None
Expand Down
12 changes: 7 additions & 5 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
# -*- coding: utf-8 -*-

"""
Setup for dwdwfsapi package
"""
"""Setup for dwdwfsapi package."""

from setuptools import setup, find_packages

# Package meta-data
NAME = "dwdwfsapi"
DESCRIPTION = "Python client to retrieve data provided by DWD via their geoserver WFS API"
DESCRIPTION = (
"Python client to retrieve data provided by DWD via their geoserver "
"WFS API"
)
KEYWORDS = "dwd ows wfs deutscher wetterdienst"
URL = "https://github.com/stephan192/dwdwfsapi"
EMAIL = "[email protected]"
AUTHOR = "stephan192"
REQUIRES_PYTHON = ">=3.6"
VERSION = "1.0.1"
VERSION = "1.0.2"

# Define required packages
REQUIRES = ["requests>=2.23.0,<3", "ciso8601>=2.1.3,<3", "urllib3>=1.25.8,<2"]
Expand All @@ -36,6 +37,7 @@
packages=find_packages(),
install_requires=REQUIRES,
keywords=KEYWORDS,
license="MIT",
classifiers=[
"Development Status :: 5 - Production/Stable",
"Programming Language :: Python :: 3",
Expand Down
37 changes: 19 additions & 18 deletions tests/test_weatherwarnings.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# -*- coding: utf-8 -*-
"""
Tests for dwdwfsapi weatherwarnings module
"""
"""Tests for dwdwfsapi weatherwarnings module."""

import datetime
from dwdwfsapi import DwdWeatherWarningsAPI
Expand All @@ -23,9 +21,7 @@


def test_city():
"""
Test a city warncell
"""
"""Test a city warncell."""
dwd = DwdWeatherWarningsAPI(WARNCELL_ID_CITY)
assert dwd.data_valid
assert dwd.warncell_id == WARNCELL_ID_CITY
Expand All @@ -42,9 +38,7 @@ def test_city():


def test_county():
"""
Test a county warncell
"""
"""Test a county warncell."""
dwd = DwdWeatherWarningsAPI(WARNCELL_NAME_COUNTY)
assert dwd.data_valid
assert dwd.warncell_id == WARNCELL_ID_COUNTY
Expand All @@ -61,9 +55,7 @@ def test_county():


def test_lake():
"""
Test a lake warncell
"""
"""Test a lake warncell."""
dwd = DwdWeatherWarningsAPI(WARNCELL_ID_LAKE)
assert dwd.data_valid
assert dwd.warncell_id == WARNCELL_ID_LAKE
Expand All @@ -80,9 +72,7 @@ def test_lake():


def test_coast():
"""
Test a coast warncell
"""
"""Test a coast warncell."""
dwd = DwdWeatherWarningsAPI(WARNCELL_NAME_COAST)
assert dwd.data_valid
assert dwd.warncell_id == WARNCELL_ID_COAST
Expand All @@ -99,9 +89,7 @@ def test_coast():


def test_sea():
"""
Test a sea warncell
"""
"""Test a sea warncell."""
dwd = DwdWeatherWarningsAPI(WARNCELL_ID_SEA)
assert dwd.data_valid
assert dwd.warncell_id == WARNCELL_ID_SEA
Expand All @@ -115,3 +103,16 @@ def test_sea():
assert MIN_WARNING_LEVEL <= dwd.expected_warning_level <= MAX_WARNING_LEVEL
assert isinstance(dwd.current_warnings, list)
assert isinstance(dwd.expected_warnings, list)


def test_wrong_input():
"""Test an invalid input."""
dwd = DwdWeatherWarningsAPI(None)
assert not dwd.data_valid
assert dwd.warncell_id is None
assert dwd.warncell_name is None
assert dwd.last_update is None
assert dwd.current_warning_level is None
assert dwd.expected_warning_level is None
assert dwd.current_warnings is None
assert dwd.expected_warnings is None

0 comments on commit d7917d4

Please sign in to comment.