mirror of
https://github.com/jdejaegh/irm-kmi-api.git
synced 2025-06-27 12:09:26 +02:00
Compare commits
9 commits
Author | SHA1 | Date | |
---|---|---|---|
b59ca80de7 | |||
3c28d2dfaf | |||
c6c4d9b585 | |||
bd3b4e0a84 | |||
7efc8170c5 | |||
9b1752c096 | |||
30c955c987 | |||
3e04e0d460 | |||
a55b1efb28 |
12 changed files with 1737 additions and 17 deletions
|
@ -39,7 +39,7 @@ __all__ = [
|
||||||
"WarningData",
|
"WarningData",
|
||||||
"WarningType",
|
"WarningType",
|
||||||
"PollenParser",
|
"PollenParser",
|
||||||
"RainGraph"
|
"RainGraph",
|
||||||
]
|
]
|
||||||
|
|
||||||
__version__ = '1.0.0'
|
__version__ = '1.1.0'
|
||||||
|
|
|
@ -27,6 +27,7 @@ MAP_WARNING_ID_TO_SLUG: Final = {
|
||||||
3: WarningType.THUNDER,
|
3: WarningType.THUNDER,
|
||||||
7: WarningType.FOG,
|
7: WarningType.FOG,
|
||||||
9: WarningType.COLD,
|
9: WarningType.COLD,
|
||||||
|
10: WarningType.HEAT,
|
||||||
12: WarningType.THUNDER_WIND_RAIN,
|
12: WarningType.THUNDER_WIND_RAIN,
|
||||||
13: WarningType.THUNDERSTORM_STRONG_GUSTS,
|
13: WarningType.THUNDERSTORM_STRONG_GUSTS,
|
||||||
14: WarningType.THUNDERSTORM_LARGE_RAINFALL,
|
14: WarningType.THUNDERSTORM_LARGE_RAINFALL,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
"""Data classes for IRM KMI integration"""
|
"""Data classes for IRM KMI integration"""
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from enum import Enum
|
from enum import StrEnum
|
||||||
from typing import List, Required, TypedDict
|
from typing import List, Required, TypedDict
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ class Forecast(TypedDict, total=False):
|
||||||
is_daytime: bool | None # Mandatory to use with forecast_twice_daily
|
is_daytime: bool | None # Mandatory to use with forecast_twice_daily
|
||||||
|
|
||||||
|
|
||||||
class ConditionEvol(Enum):
|
class ConditionEvol(StrEnum):
|
||||||
"""Possible state for evolution between weather conditions"""
|
"""Possible state for evolution between weather conditions"""
|
||||||
|
|
||||||
ONE_WAY = 'one_way'
|
ONE_WAY = 'one_way'
|
||||||
|
@ -44,7 +44,7 @@ class ConditionEvol(Enum):
|
||||||
STABLE = 'stable'
|
STABLE = 'stable'
|
||||||
|
|
||||||
|
|
||||||
class RadarStyle(Enum):
|
class RadarStyle(StrEnum):
|
||||||
"""Possible style for the rain radar"""
|
"""Possible style for the rain radar"""
|
||||||
|
|
||||||
OPTION_STYLE_STD = 'standard_style'
|
OPTION_STYLE_STD = 'standard_style'
|
||||||
|
@ -53,7 +53,7 @@ class RadarStyle(Enum):
|
||||||
OPTION_STYLE_SATELLITE = 'satellite_style'
|
OPTION_STYLE_SATELLITE = 'satellite_style'
|
||||||
|
|
||||||
|
|
||||||
class PollenName(Enum):
|
class PollenName(StrEnum):
|
||||||
ALDER = 'alder'
|
ALDER = 'alder'
|
||||||
ASH = 'ash'
|
ASH = 'ash'
|
||||||
BIRCH = 'birch'
|
BIRCH = 'birch'
|
||||||
|
@ -63,7 +63,7 @@ class PollenName(Enum):
|
||||||
OAK = 'oak'
|
OAK = 'oak'
|
||||||
|
|
||||||
|
|
||||||
class PollenLevel(Enum):
|
class PollenLevel(StrEnum):
|
||||||
"""Possible pollen levels"""
|
"""Possible pollen levels"""
|
||||||
|
|
||||||
NONE = 'none'
|
NONE = 'none'
|
||||||
|
@ -74,12 +74,13 @@ class PollenLevel(Enum):
|
||||||
RED = 'red'
|
RED = 'red'
|
||||||
PURPLE = 'purple'
|
PURPLE = 'purple'
|
||||||
|
|
||||||
class WarningType(Enum):
|
class WarningType(StrEnum):
|
||||||
"""Possible warning types"""
|
"""Possible warning types"""
|
||||||
|
|
||||||
COLD = 'cold'
|
COLD = 'cold'
|
||||||
COLDSPELL = 'coldspell'
|
COLDSPELL = 'coldspell'
|
||||||
FOG = 'fog'
|
FOG = 'fog'
|
||||||
|
HEAT = 'heat'
|
||||||
ICE_OR_SNOW = 'ice_or_snow'
|
ICE_OR_SNOW = 'ice_or_snow'
|
||||||
RAIN = 'rain'
|
RAIN = 'rain'
|
||||||
STORM_SURGE = 'storm_surge'
|
STORM_SURGE = 'storm_surge'
|
||||||
|
|
|
@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "irm-kmi-api"
|
name = "irm-kmi-api"
|
||||||
version = "1.0.0"
|
version = "1.1.0"
|
||||||
description = "Retrieve data from the Belgian IRM KMI in Python"
|
description = "Retrieve data from the Belgian IRM KMI in Python"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
authors = [{ name = "Jules Dejaeghere", email = "curable.grass491@mailer.me" }]
|
authors = [{ name = "Jules Dejaeghere", email = "curable.grass491@mailer.me" }]
|
||||||
|
@ -25,10 +25,10 @@ requires-python = ">=3.12"
|
||||||
Homepage = "https://github.com/jdejaegh/irm-kmi-api"
|
Homepage = "https://github.com/jdejaegh/irm-kmi-api"
|
||||||
|
|
||||||
[tool.setuptools]
|
[tool.setuptools]
|
||||||
packages = ["irm_kmi_api"]
|
packages = ["irm_kmi_api", "irm_kmi_api.resources"]
|
||||||
|
|
||||||
[tool.bumpver]
|
[tool.bumpver]
|
||||||
current_version = "1.0.0"
|
current_version = "1.1.0"
|
||||||
version_pattern = "MAJOR.MINOR.PATCH"
|
version_pattern = "MAJOR.MINOR.PATCH"
|
||||||
commit_message = "bump version {old_version} -> {new_version}"
|
commit_message = "bump version {old_version} -> {new_version}"
|
||||||
tag_message = "{new_version}"
|
tag_message = "{new_version}"
|
||||||
|
|
|
@ -21,3 +21,15 @@ def get_api_with_data(fixture: str) -> IrmKmiApiClientHa:
|
||||||
api = IrmKmiApiClientHa(session=MagicMock(), user_agent='', cdt_map=IRM_KMI_TO_HA_CONDITION_MAP)
|
api = IrmKmiApiClientHa(session=MagicMock(), user_agent='', cdt_map=IRM_KMI_TO_HA_CONDITION_MAP)
|
||||||
api._api_data = get_api_data(fixture)
|
api._api_data = get_api_data(fixture)
|
||||||
return api
|
return api
|
||||||
|
|
||||||
|
def is_serializable(x):
|
||||||
|
try:
|
||||||
|
json.dumps(x)
|
||||||
|
return True
|
||||||
|
except (TypeError, OverflowError):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def assert_all_serializable(elements: list):
|
||||||
|
for element in elements:
|
||||||
|
for v in element.values():
|
||||||
|
assert is_serializable(v)
|
1647
tests/fixtures/antwerp_with_heat_warning.json
vendored
Normal file
1647
tests/fixtures/antwerp_with_heat_warning.json
vendored
Normal file
File diff suppressed because it is too large
Load diff
|
@ -5,7 +5,7 @@ import pytest
|
||||||
from freezegun import freeze_time
|
from freezegun import freeze_time
|
||||||
|
|
||||||
from irm_kmi_api import CurrentWeatherData
|
from irm_kmi_api import CurrentWeatherData
|
||||||
from tests.conftest import get_api_data, get_api_with_data
|
from tests.conftest import get_api_data, get_api_with_data, is_serializable
|
||||||
from irm_kmi_api.const import ATTR_CONDITION_CLOUDY, ATTR_CONDITION_PARTLYCLOUDY
|
from irm_kmi_api.const import ATTR_CONDITION_CLOUDY, ATTR_CONDITION_PARTLYCLOUDY
|
||||||
|
|
||||||
|
|
||||||
|
@ -140,3 +140,10 @@ def test_current_weather_attributes(
|
||||||
assert r == expected_
|
assert r == expected_
|
||||||
|
|
||||||
run(sensor, expected)
|
run(sensor, expected)
|
||||||
|
|
||||||
|
@freeze_time(datetime.fromisoformat('2023-12-26T17:30:00+00:00'))
|
||||||
|
def test_current_weather_is_serializable() -> None:
|
||||||
|
api = get_api_with_data("forecast.json")
|
||||||
|
tz = ZoneInfo("Europe/Brussels")
|
||||||
|
result = api.get_current_weather(tz)
|
||||||
|
assert is_serializable(result)
|
|
@ -4,7 +4,7 @@ from zoneinfo import ZoneInfo
|
||||||
from freezegun import freeze_time
|
from freezegun import freeze_time
|
||||||
|
|
||||||
from irm_kmi_api import ConditionEvol, ExtendedForecast
|
from irm_kmi_api import ConditionEvol, ExtendedForecast
|
||||||
from tests.conftest import get_api_with_data
|
from tests.conftest import get_api_with_data, assert_all_serializable
|
||||||
from irm_kmi_api.const import ATTR_CONDITION_PARTLYCLOUDY
|
from irm_kmi_api.const import ATTR_CONDITION_PARTLYCLOUDY
|
||||||
|
|
||||||
|
|
||||||
|
@ -106,3 +106,11 @@ async def test_sunrise_sunset_be() -> None:
|
||||||
|
|
||||||
assert result[2]['sunrise'] == '2023-12-28T08:45:00+01:00'
|
assert result[2]['sunrise'] == '2023-12-28T08:45:00+01:00'
|
||||||
assert result[2]['sunset'] == '2023-12-28T16:43:00+01:00'
|
assert result[2]['sunset'] == '2023-12-28T16:43:00+01:00'
|
||||||
|
|
||||||
|
|
||||||
|
def test_daily_serializable() -> None:
|
||||||
|
api = get_api_with_data("forecast.json")
|
||||||
|
tz = ZoneInfo("Europe/Brussels")
|
||||||
|
|
||||||
|
result = api.get_daily_forecast(tz, 'fr')
|
||||||
|
assert_all_serializable(result)
|
|
@ -4,7 +4,7 @@ from zoneinfo import ZoneInfo
|
||||||
from freezegun import freeze_time
|
from freezegun import freeze_time
|
||||||
|
|
||||||
from irm_kmi_api import Forecast
|
from irm_kmi_api import Forecast
|
||||||
from tests.conftest import get_api_with_data
|
from tests.conftest import get_api_with_data, assert_all_serializable
|
||||||
from irm_kmi_api.const import ATTR_CONDITION_CLOUDY, ATTR_CONDITION_RAINY
|
from irm_kmi_api.const import ATTR_CONDITION_CLOUDY, ATTR_CONDITION_RAINY
|
||||||
|
|
||||||
|
|
||||||
|
@ -88,4 +88,10 @@ def test_hourly_forecast_midnight_bug() -> None:
|
||||||
|
|
||||||
assert result[24]['datetime'] == '2024-06-01T00:00:00+02:00'
|
assert result[24]['datetime'] == '2024-06-01T00:00:00+02:00'
|
||||||
|
|
||||||
|
def test_hourly_serializable() -> None:
|
||||||
|
api = get_api_with_data("forecast.json")
|
||||||
|
tz = ZoneInfo("Europe/Brussels")
|
||||||
|
|
||||||
|
result = api.get_hourly_forecast(tz)
|
||||||
|
|
||||||
|
assert_all_serializable(result)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from unittest.mock import AsyncMock
|
from unittest.mock import AsyncMock
|
||||||
|
|
||||||
from irm_kmi_api import PollenLevel, PollenName, PollenParser
|
from irm_kmi_api import PollenLevel, PollenName, PollenParser
|
||||||
from tests.conftest import get_api_with_data, load_fixture
|
from tests.conftest import get_api_with_data, load_fixture, is_serializable
|
||||||
|
|
||||||
|
|
||||||
def test_svg_pollen_parsing():
|
def test_svg_pollen_parsing():
|
||||||
|
@ -76,3 +76,9 @@ async def test_pollen_data_from_api() -> None:
|
||||||
PollenName.HAZEL: PollenLevel.NONE}
|
PollenName.HAZEL: PollenLevel.NONE}
|
||||||
assert result == expected
|
assert result == expected
|
||||||
|
|
||||||
|
def test_pollen_is_serializable():
|
||||||
|
with open("tests/fixtures/pollens-2025.svg", "r") as file:
|
||||||
|
svg_data = file.read()
|
||||||
|
data = PollenParser(svg_data).get_pollen_data()
|
||||||
|
|
||||||
|
assert is_serializable(data)
|
|
@ -1,7 +1,7 @@
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from irm_kmi_api import RadarForecast
|
from irm_kmi_api import RadarForecast
|
||||||
from tests.conftest import get_api_with_data
|
from tests.conftest import get_api_with_data, assert_all_serializable
|
||||||
|
|
||||||
|
|
||||||
def test_radar_forecast() -> None:
|
def test_radar_forecast() -> None:
|
||||||
|
@ -78,3 +78,10 @@ async def test_current_rainfall_unit(
|
||||||
|
|
||||||
for r in radar_forecast:
|
for r in radar_forecast:
|
||||||
assert r.get('unit') == expected
|
assert r.get('unit') == expected
|
||||||
|
|
||||||
|
def test_radar_serializable() -> None:
|
||||||
|
api = get_api_with_data("forecast.json")
|
||||||
|
|
||||||
|
result = api.get_radar_forecast()
|
||||||
|
|
||||||
|
assert_all_serializable(result)
|
|
@ -3,7 +3,7 @@ from datetime import datetime
|
||||||
from freezegun import freeze_time
|
from freezegun import freeze_time
|
||||||
|
|
||||||
from irm_kmi_api import WarningType
|
from irm_kmi_api import WarningType
|
||||||
from tests.conftest import get_api_with_data
|
from tests.conftest import get_api_with_data, is_serializable
|
||||||
|
|
||||||
|
|
||||||
@freeze_time(datetime.fromisoformat('2024-01-12T07:10:00+00:00'))
|
@freeze_time(datetime.fromisoformat('2024-01-12T07:10:00+00:00'))
|
||||||
|
@ -23,3 +23,28 @@ async def test_warning_data() -> None:
|
||||||
assert first.get('friendly_name') == 'Fog'
|
assert first.get('friendly_name') == 'Fog'
|
||||||
assert first.get('id') == 7
|
assert first.get('id') == 7
|
||||||
assert first.get('level') == 1
|
assert first.get('level') == 1
|
||||||
|
|
||||||
|
async def test_warning_heat() -> None:
|
||||||
|
api = get_api_with_data("antwerp_with_heat_warning.json")
|
||||||
|
|
||||||
|
result = api.get_warnings(lang='en')
|
||||||
|
|
||||||
|
assert isinstance(result, list)
|
||||||
|
assert len(result) == 1
|
||||||
|
|
||||||
|
first = result[0]
|
||||||
|
|
||||||
|
assert first.get('slug') == WarningType.HEAT
|
||||||
|
assert first.get('friendly_name') == 'Heat'
|
||||||
|
assert first.get('id') == 10
|
||||||
|
assert first.get('level') == 1
|
||||||
|
|
||||||
|
|
||||||
|
async def test_warning_data_is_serializable() -> None:
|
||||||
|
api = get_api_with_data("be_forecast_warning.json")
|
||||||
|
|
||||||
|
result = api.get_warnings(lang='en')
|
||||||
|
for r in result:
|
||||||
|
del r["starts_at"]
|
||||||
|
del r["ends_at"]
|
||||||
|
assert is_serializable(r)
|
Loading…
Add table
Reference in a new issue