From 9c5521c7ddbeff423020fabc6b70f7d2e9d8aec8 Mon Sep 17 00:00:00 2001 From: Maciej Bieniek Date: Wed, 7 Jul 2021 10:27:16 +0200 Subject: [PATCH 1/4] Use dataclass --- example.py | 2 +- gios/__init__.py | 9 ++++- gios/model.py | 27 ++++++++++++++ requirements.txt | 3 +- tests/test_init.py | 93 ++++++++++++++++++++++------------------------ 5 files changed, 82 insertions(+), 52 deletions(-) create mode 100644 gios/model.py diff --git a/example.py b/example.py index b1fb73f..bf19a73 100644 --- a/example.py +++ b/example.py @@ -4,7 +4,7 @@ from aiohttp import ClientError, ClientSession from gios import ApiError, InvalidSensorsData, Gios, NoStationError -GIOS_STATION_ID = 117 +GIOS_STATION_ID = 568 logging.basicConfig(level=logging.DEBUG) diff --git a/gios/__init__.py b/gios/__init__.py index 4e81d42..28ea6bb 100644 --- a/gios/__init__.py +++ b/gios/__init__.py @@ -6,6 +6,7 @@ from typing import Any, Dict, List, Optional, cast from aiohttp import ClientSession +from dacite import from_dict from .const import ( ATTR_AQI, @@ -20,6 +21,7 @@ URL_STATION, URL_STATIONS, ) +from .model import GiosSensors _LOGGER = logging.getLogger(__name__) @@ -37,7 +39,7 @@ def __init__(self, station_id: int, session: ClientSession) -> None: self.session = session - async def async_update(self) -> Dict[str, Any]: # pylint:disable=too-many-branches + async def async_update(self) -> GiosSensors: # pylint:disable=too-many-branches """Update GIOS data.""" data: Dict[str, Dict[str, Any]] = {} invalid_sensors: List[str] = [] @@ -104,7 +106,10 @@ async def async_update(self) -> Dict[str, Any]: # pylint:disable=too-many-branc "indexLevelName" ].lower() - return data + if data.get("pm2.5"): + data["pm25"] = data.pop("pm2.5") + + return from_dict(data_class=GiosSensors, data=data) async def _get_stations(self) -> List[Dict[str, Any]]: """Retreive list of measuring stations.""" diff --git a/gios/model.py b/gios/model.py new file mode 100644 index 0000000..9c64e48 --- /dev/null +++ b/gios/model.py @@ -0,0 +1,27 @@ +"""Type definitions for GIOS.""" +from dataclasses import dataclass +from typing import Optional, Union + + +@dataclass +class Sensor: + """Data class for sensor.""" + + name: str + id: Optional[int] # pylint: disable=invalid-name + index: Optional[str] = None + value: Optional[Union[float, str]] = None + + +@dataclass +class GiosSensors: # pylint: disable=too-many-instance-attributes + """Data class for polutants.""" + + aqi: Optional[Sensor] + c6h6: Optional[Sensor] + co: Optional[Sensor] # pylint: disable=invalid-name + no2: Optional[Sensor] + o3: Optional[Sensor] # pylint: disable=invalid-name + pm10: Optional[Sensor] + pm25: Optional[Sensor] + so2: Optional[Sensor] diff --git a/requirements.txt b/requirements.txt index ce23571..3e4ba39 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ -aiohttp \ No newline at end of file +aiohttp +dacite \ No newline at end of file diff --git a/tests/test_init.py b/tests/test_init.py index 65f6e3d..78a1ea3 100644 --- a/tests/test_init.py +++ b/tests/test_init.py @@ -92,22 +92,21 @@ async def test_valid_data_first_value(): # pylint:disable=too-many-statements assert gios.station_id == VALID_STATION_ID assert gios.latitude == VALID_LATITUDE assert gios.longitude == VALID_LONGITUDE - assert len(data) == 8 - assert data["so2"]["value"] == 11.6502 - assert data["so2"]["index"] == "very good" - assert data["c6h6"]["value"] == 2.57148 - assert data["c6h6"]["index"] == "very good" - assert data["co"]["value"] == 786.702 - assert data["co"]["index"] == "very good" - assert data["no2"]["value"] == 59.9545 - assert data["no2"]["index"] == "very good" - assert data["o3"]["value"] == 8.63111 - assert data["o3"]["index"] == "good" - assert data["pm2.5"]["value"] == 59.9428 - assert data["pm2.5"]["index"] == "very good" - assert data["pm10"]["value"] == 123.879 - assert data["pm10"]["index"] == "very good" - assert data["aqi"]["value"] == "good" + assert data.so2.value == 11.6502 + assert data.so2.index == "very good" + assert data.c6h6.value == 2.57148 + assert data.c6h6.index == "very good" + assert data.co.value == 786.702 + assert data.co.index == "very good" + assert data.no2.value == 59.9545 + assert data.no2.index == "very good" + assert data.o3.value == 8.63111 + assert data.o3.index == "good" + assert data.pm25.value == 59.9428 + assert data.pm25.index == "very good" + assert data.pm10.value == 123.879 + assert data.pm10.index == "very good" + assert data.aqi.value == "good" @pytest.mark.asyncio @@ -214,22 +213,21 @@ async def test_valid_data_second_value(): # pylint:disable=too-many-statements assert gios.station_id == VALID_STATION_ID assert gios.latitude == VALID_LATITUDE assert gios.longitude == VALID_LONGITUDE - assert len(data) == 8 - assert data["so2"]["value"] == 11.501 - assert data["so2"]["index"] == "very good" - assert data["c6h6"]["value"] == 3.24432 - assert data["c6h6"]["index"] == "very good" - assert data["co"]["value"] == 1041.74 - assert data["co"]["index"] == "very good" - assert data["no2"]["value"] == 52.6198 - assert data["no2"]["index"] == "very good" - assert data["o3"]["value"] == 4.93778 - assert data["o3"]["index"] == "good" - assert data["pm2.5"]["value"] == 72.0243 - assert data["pm2.5"]["index"] == "very good" - assert data["pm10"]["value"] == 115.559 - assert data["pm10"]["index"] == "very good" - assert data["aqi"]["value"] == "good" + assert data.so2.value == 11.501 + assert data.so2.index == "very good" + assert data.c6h6.value == 3.24432 + assert data.c6h6.index == "very good" + assert data.co.value == 1041.74 + assert data.co.index == "very good" + assert data.no2.value == 52.6198 + assert data.no2.index == "very good" + assert data.o3.value == 4.93778 + assert data.o3.index == "good" + assert data.pm25.value == 72.0243 + assert data.pm25.index == "very good" + assert data.pm10.value == 115.559 + assert data.pm10.index == "very good" + assert data.aqi.value == "good" @pytest.mark.asyncio @@ -307,22 +305,21 @@ async def test_no_indexes_data(): # pylint: disable=too-many-statements assert gios.station_id == VALID_STATION_ID assert gios.latitude == VALID_LATITUDE assert gios.longitude == VALID_LONGITUDE - assert len(data) == 8 - assert data["so2"]["value"] == 11.6502 - assert data["so2"].get("index") is None - assert data["c6h6"]["value"] == 2.57148 - assert data["c6h6"].get("index") is None - assert data["co"]["value"] == 786.702 - assert data["co"].get("index") is None - assert data["no2"]["value"] == 59.9545 - assert data["no2"].get("index") is None - assert data["o3"]["value"] == 8.63111 - assert data["o3"].get("index") is None - assert data["pm2.5"]["value"] == 59.9428 - assert data["pm2.5"].get("index") is None - assert data["pm10"]["value"] == 123.879 - assert data["pm10"].get("index") is None - assert data["aqi"].get("value") is None + assert data.so2.value == 11.6502 + assert data.so2.index is None + assert data.c6h6.value == 2.57148 + assert data.c6h6.index is None + assert data.co.value == 786.702 + assert data.co.index is None + assert data.no2.value == 59.9545 + assert data.no2.index is None + assert data.o3.value == 8.63111 + assert data.o3.index is None + assert data.pm25.value == 59.9428 + assert data.pm25.index is None + assert data.pm10.value == 123.879 + assert data.pm10.index is None + assert data.aqi.value is None @pytest.mark.asyncio From a96dc0db4568738c8910770aa23124957babf505 Mon Sep 17 00:00:00 2001 From: Maciej Bieniek Date: Tue, 27 Jul 2021 11:53:58 +0200 Subject: [PATCH 2/4] AQI is None when indexes are invalid --- gios/__init__.py | 9 +++++---- tests/test_init.py | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/gios/__init__.py b/gios/__init__.py index 28ea6bb..6a28f81 100644 --- a/gios/__init__.py +++ b/gios/__init__.py @@ -101,10 +101,11 @@ async def async_update(self) -> GiosSensors: # pylint:disable=too-many-branches sensor_data[ATTR_INDEX] = indexes[index_level]["indexLevelName"].lower() with suppress(IndexError, KeyError, TypeError): - data[ATTR_AQI.lower()] = {ATTR_NAME: ATTR_AQI} - data[ATTR_AQI.lower()][ATTR_VALUE] = indexes["stIndexLevel"][ - "indexLevelName" - ].lower() + if indexes["stIndexLevel"]["indexLevelName"]: + data[ATTR_AQI.lower()] = {ATTR_NAME: ATTR_AQI} + data[ATTR_AQI.lower()][ATTR_VALUE] = indexes["stIndexLevel"][ + "indexLevelName" + ].lower() if data.get("pm2.5"): data["pm25"] = data.pop("pm2.5") diff --git a/tests/test_init.py b/tests/test_init.py index 78a1ea3..7c3e5a8 100644 --- a/tests/test_init.py +++ b/tests/test_init.py @@ -319,7 +319,7 @@ async def test_no_indexes_data(): # pylint: disable=too-many-statements assert data.pm25.index is None assert data.pm10.value == 123.879 assert data.pm10.index is None - assert data.aqi.value is None + assert data.aqi is None @pytest.mark.asyncio From c3e90f87b6db78b2c9c00a48c1dffa5432ac5182 Mon Sep 17 00:00:00 2001 From: Maciej Bieniek Date: Tue, 27 Jul 2021 11:55:25 +0200 Subject: [PATCH 3/4] Add py.typed file --- gios/py.typed | 0 setup.py | 1 + 2 files changed, 1 insertion(+) create mode 100644 gios/py.typed diff --git a/gios/py.typed b/gios/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/setup.py b/setup.py index 535a573..4f602ff 100644 --- a/setup.py +++ b/setup.py @@ -16,6 +16,7 @@ url="https://github.com/bieniu/gios", license="Apache-2.0 License", packages=["gios"], + package_data={"gios": ["py.typed"]}, python_requires=">=3.6", install_requires=list(val.strip() for val in open("requirements.txt")), classifiers=[ From 15baf848b35bd46da6bc5150269968c06ce460cc Mon Sep 17 00:00:00 2001 From: Maciej Bieniek Date: Tue, 27 Jul 2021 11:55:54 +0200 Subject: [PATCH 4/4] Bump version --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 4f602ff..bd24f48 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ setup( name="gios", - version="1.0.2", + version="2.0.0", author="Maciej Bieniek", description="Python wrapper for getting air quality data from GIOĊš servers.", long_description=long_description,