Bump pytrafikverket to 0.3.1 (#92425)

* Bump pytrafikverket 0.3.0

* 0.3.1

* mypy

* Fix exceptions
This commit is contained in:
G Johansson 2023-05-05 21:19:16 +02:00 committed by GitHub
parent 85dcd4007c
commit 82b4368d1d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 154 additions and 106 deletions

View File

@ -5,6 +5,7 @@ from collections.abc import Mapping
from typing import Any from typing import Any
from pytrafikverket import TrafikverketFerry from pytrafikverket import TrafikverketFerry
from pytrafikverket.exceptions import InvalidAuthentication, NoFerryFound
import voluptuous as vol import voluptuous as vol
from homeassistant import config_entries from homeassistant import config_entries
@ -16,9 +17,6 @@ from homeassistant.helpers.aiohttp_client import async_get_clientsession
from .const import CONF_FROM, CONF_TIME, CONF_TO, DOMAIN from .const import CONF_FROM, CONF_TIME, CONF_TO, DOMAIN
from .util import create_unique_id from .util import create_unique_id
ERROR_INVALID_AUTH = "Source: Security, message: Invalid authentication"
ERROR_INVALID_ROUTE = "No FerryAnnouncement found"
DATA_SCHEMA = vol.Schema( DATA_SCHEMA = vol.Schema(
{ {
vol.Required(CONF_API_KEY): selector.TextSelector( vol.Required(CONF_API_KEY): selector.TextSelector(
@ -81,13 +79,12 @@ class TVFerryConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
await self.validate_input( await self.validate_input(
api_key, self.entry.data[CONF_FROM], self.entry.data[CONF_TO] api_key, self.entry.data[CONF_FROM], self.entry.data[CONF_TO]
) )
except ValueError as err: except InvalidAuthentication:
if str(err) == ERROR_INVALID_AUTH: errors["base"] = "invalid_auth"
errors["base"] = "invalid_auth" except NoFerryFound:
elif str(err) == ERROR_INVALID_ROUTE: errors["base"] = "invalid_route"
errors["base"] = "invalid_route" except Exception: # pylint: disable=broad-exception-caught
else: errors["base"] = "cannot_connect"
errors["base"] = "cannot_connect"
else: else:
self.hass.config_entries.async_update_entry( self.hass.config_entries.async_update_entry(
self.entry, self.entry,
@ -126,13 +123,12 @@ class TVFerryConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
try: try:
await self.validate_input(api_key, ferry_from, ferry_to) await self.validate_input(api_key, ferry_from, ferry_to)
except ValueError as err: except InvalidAuthentication:
if str(err) == ERROR_INVALID_AUTH: errors["base"] = "invalid_auth"
errors["base"] = "invalid_auth" except NoFerryFound:
elif str(err) == ERROR_INVALID_ROUTE: errors["base"] = "invalid_route"
errors["base"] = "invalid_route" except Exception: # pylint: disable=broad-exception-caught
else: errors["base"] = "cannot_connect"
errors["base"] = "cannot_connect"
else: else:
if not errors: if not errors:
unique_id = create_unique_id( unique_id = create_unique_id(

View File

@ -6,11 +6,13 @@ import logging
from typing import Any from typing import Any
from pytrafikverket import TrafikverketFerry from pytrafikverket import TrafikverketFerry
from pytrafikverket.exceptions import InvalidAuthentication, NoFerryFound
from pytrafikverket.trafikverket_ferry import FerryStop from pytrafikverket.trafikverket_ferry import FerryStop
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_API_KEY, CONF_WEEKDAY, WEEKDAYS from homeassistant.const import CONF_API_KEY, CONF_WEEKDAY, WEEKDAYS
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed
from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from homeassistant.util import dt from homeassistant.util import dt
@ -82,10 +84,12 @@ class TVDataUpdateCoordinator(DataUpdateCoordinator):
] = await self._ferry_api.async_get_next_ferry_stops( ] = await self._ferry_api.async_get_next_ferry_stops(
self._from, self._to, when, 3 self._from, self._to, when, 3
) )
except ValueError as error: except NoFerryFound as error:
raise UpdateFailed( raise UpdateFailed(
f"Departure {when} encountered a problem: {error}" f"Departure {when} encountered a problem: {error}"
) from error ) from error
except InvalidAuthentication as error:
raise ConfigEntryAuthFailed(error) from error
states = { states = {
"departure_time": routedata[0].departure_time, "departure_time": routedata[0].departure_time,

View File

@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/trafikverket_ferry", "documentation": "https://www.home-assistant.io/integrations/trafikverket_ferry",
"iot_class": "cloud_polling", "iot_class": "cloud_polling",
"loggers": ["pytrafikverket"], "loggers": ["pytrafikverket"],
"requirements": ["pytrafikverket==0.2.3"] "requirements": ["pytrafikverket==0.3.1"]
} }

View File

@ -2,6 +2,11 @@
from __future__ import annotations from __future__ import annotations
from pytrafikverket import TrafikverketTrain from pytrafikverket import TrafikverketTrain
from pytrafikverket.exceptions import (
InvalidAuthentication,
MultipleTrainStationsFound,
NoTrainStationFound,
)
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_API_KEY from homeassistant.const import CONF_API_KEY
@ -21,9 +26,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
try: try:
to_station = await train_api.async_get_train_station(entry.data[CONF_TO]) to_station = await train_api.async_get_train_station(entry.data[CONF_TO])
from_station = await train_api.async_get_train_station(entry.data[CONF_FROM]) from_station = await train_api.async_get_train_station(entry.data[CONF_FROM])
except ValueError as error: except InvalidAuthentication as error:
if "Invalid authentication" in error.args[0]: raise ConfigEntryAuthFailed from error
raise ConfigEntryAuthFailed from error except (NoTrainStationFound, MultipleTrainStationsFound) as error:
raise ConfigEntryNotReady( raise ConfigEntryNotReady(
f"Problem when trying station {entry.data[CONF_FROM]} to" f"Problem when trying station {entry.data[CONF_FROM]} to"
f" {entry.data[CONF_TO]}. Error: {error} " f" {entry.data[CONF_TO]}. Error: {error} "

View File

@ -5,6 +5,11 @@ from collections.abc import Mapping
from typing import Any from typing import Any
from pytrafikverket import TrafikverketTrain from pytrafikverket import TrafikverketTrain
from pytrafikverket.exceptions import (
InvalidAuthentication,
MultipleTrainStationsFound,
NoTrainStationFound,
)
import voluptuous as vol import voluptuous as vol
from homeassistant import config_entries from homeassistant import config_entries
@ -23,10 +28,6 @@ import homeassistant.util.dt as dt_util
from .const import CONF_FROM, CONF_TIME, CONF_TO, DOMAIN from .const import CONF_FROM, CONF_TIME, CONF_TO, DOMAIN
from .util import create_unique_id from .util import create_unique_id
ERROR_INVALID_AUTH = "Source: Security, message: Invalid authentication"
ERROR_INVALID_STATION = "Could not find a station with the specified name"
ERROR_MULTIPLE_STATION = "Found multiple stations with the specified name"
DATA_SCHEMA = vol.Schema( DATA_SCHEMA = vol.Schema(
{ {
vol.Required(CONF_API_KEY): TextSelector(), vol.Required(CONF_API_KEY): TextSelector(),
@ -86,15 +87,14 @@ class TVTrainConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
await self.validate_input( await self.validate_input(
api_key, self.entry.data[CONF_FROM], self.entry.data[CONF_TO] api_key, self.entry.data[CONF_FROM], self.entry.data[CONF_TO]
) )
except ValueError as err: except InvalidAuthentication:
if str(err) == ERROR_INVALID_AUTH: errors["base"] = "invalid_auth"
errors["base"] = "invalid_auth" except NoTrainStationFound:
elif str(err) == ERROR_INVALID_STATION: errors["base"] = "invalid_station"
errors["base"] = "invalid_station" except MultipleTrainStationsFound:
elif str(err) == ERROR_MULTIPLE_STATION: errors["base"] = "more_stations"
errors["base"] = "more_stations" except Exception: # pylint: disable=broad-exception-caught
else: errors["base"] = "cannot_connect"
errors["base"] = "cannot_connect"
else: else:
self.hass.config_entries.async_update_entry( self.hass.config_entries.async_update_entry(
self.entry, self.entry,
@ -131,15 +131,14 @@ class TVTrainConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
try: try:
await self.validate_input(api_key, train_from, train_to) await self.validate_input(api_key, train_from, train_to)
except ValueError as err: except InvalidAuthentication:
if str(err) == ERROR_INVALID_AUTH: errors["base"] = "invalid_auth"
errors["base"] = "invalid_auth" except NoTrainStationFound:
elif str(err) == ERROR_INVALID_STATION: errors["base"] = "invalid_station"
errors["base"] = "invalid_station" except MultipleTrainStationsFound:
elif str(err) == ERROR_MULTIPLE_STATION: errors["base"] = "more_stations"
errors["base"] = "more_stations" except Exception: # pylint: disable=broad-exception-caught
else: errors["base"] = "cannot_connect"
errors["base"] = "cannot_connect"
else: else:
if train_time: if train_time:
if bool(dt_util.parse_time(train_time) is None): if bool(dt_util.parse_time(train_time) is None):

View File

@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/trafikverket_train", "documentation": "https://www.home-assistant.io/integrations/trafikverket_train",
"iot_class": "cloud_polling", "iot_class": "cloud_polling",
"loggers": ["pytrafikverket"], "loggers": ["pytrafikverket"],
"requirements": ["pytrafikverket==0.2.3"] "requirements": ["pytrafikverket==0.3.1"]
} }

View File

@ -3,9 +3,13 @@ from __future__ import annotations
from datetime import date, datetime, time, timedelta from datetime import date, datetime, time, timedelta
import logging import logging
from typing import Any from typing import TYPE_CHECKING, Any
from pytrafikverket import TrafikverketTrain from pytrafikverket import TrafikverketTrain
from pytrafikverket.exceptions import (
MultipleTrainAnnouncementFound,
NoTrainAnnouncementFound,
)
from pytrafikverket.trafikverket_train import StationInfo, TrainStop from pytrafikverket.trafikverket_train import StationInfo, TrainStop
from homeassistant.components.sensor import SensorDeviceClass, SensorEntity from homeassistant.components.sensor import SensorDeviceClass, SensorEntity
@ -119,6 +123,8 @@ class TrainSensor(SensorEntity):
name=name, name=name,
configuration_url="https://api.trafikinfo.trafikverket.se/", configuration_url="https://api.trafikinfo.trafikverket.se/",
) )
if TYPE_CHECKING:
assert from_station.name and to_station.name
self._attr_unique_id = create_unique_id( self._attr_unique_id = create_unique_id(
from_station.name, to_station.name, departuretime, weekday from_station.name, to_station.name, departuretime, weekday
) )
@ -134,6 +140,7 @@ class TrainSensor(SensorEntity):
) )
try: try:
if self._time: if self._time:
_LOGGER.debug("%s, %s, %s", self._from_station, self._to_station, when)
_state = await self._train_api.async_get_train_stop( _state = await self._train_api.async_get_train_stop(
self._from_station, self._to_station, when self._from_station, self._to_station, when
) )
@ -141,7 +148,7 @@ class TrainSensor(SensorEntity):
_state = await self._train_api.async_get_next_train_stop( _state = await self._train_api.async_get_next_train_stop(
self._from_station, self._to_station, when self._from_station, self._to_station, when
) )
except ValueError as error: except (NoTrainAnnouncementFound, MultipleTrainAnnouncementFound) as error:
_LOGGER.error("Departure %s encountered a problem: %s", when, error) _LOGGER.error("Departure %s encountered a problem: %s", when, error)
if not _state: if not _state:
@ -153,6 +160,8 @@ class TrainSensor(SensorEntity):
self._attr_available = True self._attr_available = True
# The original datetime doesn't provide a timezone so therefore attaching it here. # The original datetime doesn't provide a timezone so therefore attaching it here.
if TYPE_CHECKING:
assert _state.advertised_time_at_location
self._attr_native_value = dt.as_utc(_state.advertised_time_at_location) self._attr_native_value = dt.as_utc(_state.advertised_time_at_location)
if _state.time_at_location: if _state.time_at_location:
self._attr_native_value = dt.as_utc(_state.time_at_location) self._attr_native_value = dt.as_utc(_state.time_at_location)
@ -165,7 +174,7 @@ class TrainSensor(SensorEntity):
"""Return extra state attributes.""" """Return extra state attributes."""
attributes: dict[str, Any] = { attributes: dict[str, Any] = {
ATTR_DEPARTURE_STATE: state.get_state().name, ATTR_DEPARTURE_STATE: state.get_state().value,
ATTR_CANCELED: state.canceled, ATTR_CANCELED: state.canceled,
ATTR_DELAY_TIME: None, ATTR_DELAY_TIME: None,
ATTR_PLANNED_TIME: None, ATTR_PLANNED_TIME: None,

View File

@ -1,6 +1,11 @@
"""Adds config flow for Trafikverket Weather integration.""" """Adds config flow for Trafikverket Weather integration."""
from __future__ import annotations from __future__ import annotations
from pytrafikverket.exceptions import (
InvalidAuthentication,
MultipleWeatherStationsFound,
NoWeatherStationFound,
)
from pytrafikverket.trafikverket_weather import TrafikverketWeather from pytrafikverket.trafikverket_weather import TrafikverketWeather
import voluptuous as vol import voluptuous as vol
@ -20,15 +25,11 @@ class TVWeatherConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
entry: config_entries.ConfigEntry entry: config_entries.ConfigEntry
async def validate_input(self, sensor_api: str, station: str) -> str: async def validate_input(self, sensor_api: str, station: str) -> None:
"""Validate input from user input.""" """Validate input from user input."""
web_session = async_get_clientsession(self.hass) web_session = async_get_clientsession(self.hass)
weather_api = TrafikverketWeather(web_session, sensor_api) weather_api = TrafikverketWeather(web_session, sensor_api)
try: await weather_api.async_get_weather(station)
await weather_api.async_get_weather(station)
except ValueError as err:
return str(err)
return "connected"
async def async_step_user( async def async_step_user(
self, user_input: dict[str, str] | None = None self, user_input: dict[str, str] | None = None
@ -41,8 +42,17 @@ class TVWeatherConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
api_key = user_input[CONF_API_KEY] api_key = user_input[CONF_API_KEY]
station = user_input[CONF_STATION] station = user_input[CONF_STATION]
validate = await self.validate_input(api_key, station) try:
if validate == "connected": await self.validate_input(api_key, station)
except InvalidAuthentication:
errors["base"] = "invalid_auth"
except NoWeatherStationFound:
errors["base"] = "invalid_station"
except MultipleWeatherStationsFound:
errors["base"] = "more_stations"
except Exception: # pylint: disable=broad-exception-caught
errors["base"] = "cannot_connect"
else:
return self.async_create_entry( return self.async_create_entry(
title=name, title=name,
data={ data={
@ -50,14 +60,6 @@ class TVWeatherConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
CONF_STATION: station, CONF_STATION: station,
}, },
) )
if validate == "Source: Security, message: Invalid authentication":
errors["base"] = "invalid_auth"
elif validate == "Could not find a weather station with the specified name":
errors["base"] = "invalid_station"
elif validate == "Found multiple weather stations with the specified name":
errors["base"] = "more_stations"
else:
errors["base"] = "cannot_connect"
return self.async_show_form( return self.async_show_form(
step_id="user", step_id="user",

View File

@ -4,11 +4,17 @@ from __future__ import annotations
from datetime import timedelta from datetime import timedelta
import logging import logging
from pytrafikverket.exceptions import (
InvalidAuthentication,
MultipleWeatherStationsFound,
NoWeatherStationFound,
)
from pytrafikverket.trafikverket_weather import TrafikverketWeather, WeatherStationInfo from pytrafikverket.trafikverket_weather import TrafikverketWeather, WeatherStationInfo
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_API_KEY from homeassistant.const import CONF_API_KEY
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed
from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
@ -38,6 +44,8 @@ class TVDataUpdateCoordinator(DataUpdateCoordinator[WeatherStationInfo]):
"""Fetch data from Trafikverket.""" """Fetch data from Trafikverket."""
try: try:
weatherdata = await self._weather_api.async_get_weather(self._station) weatherdata = await self._weather_api.async_get_weather(self._station)
except ValueError as error: except InvalidAuthentication as error:
raise ConfigEntryAuthFailed from error
except (NoWeatherStationFound, MultipleWeatherStationsFound) as error:
raise UpdateFailed from error raise UpdateFailed from error
return weatherdata return weatherdata

View File

@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/trafikverket_weatherstation", "documentation": "https://www.home-assistant.io/integrations/trafikverket_weatherstation",
"iot_class": "cloud_polling", "iot_class": "cloud_polling",
"loggers": ["pytrafikverket"], "loggers": ["pytrafikverket"],
"requirements": ["pytrafikverket==0.2.3"] "requirements": ["pytrafikverket==0.3.1"]
} }

View File

@ -3,6 +3,7 @@ from __future__ import annotations
from dataclasses import dataclass from dataclasses import dataclass
from datetime import datetime from datetime import datetime
from typing import TYPE_CHECKING
from homeassistant.components.sensor import ( from homeassistant.components.sensor import (
SensorDeviceClass, SensorDeviceClass,
@ -190,7 +191,9 @@ class TrafikverketWeatherStation(
def native_value(self) -> StateType | datetime: def native_value(self) -> StateType | datetime:
"""Return state of sensor.""" """Return state of sensor."""
if self.entity_description.api_key == "measure_time": if self.entity_description.api_key == "measure_time":
return _to_datetime(self.coordinator.data.measure_time) if TYPE_CHECKING:
assert self.coordinator.data.measure_time
return self.coordinator.data.measure_time
state: StateType = getattr( state: StateType = getattr(
self.coordinator.data, self.entity_description.api_key self.coordinator.data, self.entity_description.api_key
@ -204,4 +207,6 @@ class TrafikverketWeatherStation(
@property @property
def available(self) -> bool: def available(self) -> bool:
"""Return if entity is available.""" """Return if entity is available."""
if TYPE_CHECKING:
assert self.coordinator.data.active
return self.coordinator.data.active and super().available return self.coordinator.data.active and super().available

View File

@ -2146,7 +2146,7 @@ pytradfri[async]==9.0.1
# homeassistant.components.trafikverket_ferry # homeassistant.components.trafikverket_ferry
# homeassistant.components.trafikverket_train # homeassistant.components.trafikverket_train
# homeassistant.components.trafikverket_weatherstation # homeassistant.components.trafikverket_weatherstation
pytrafikverket==0.2.3 pytrafikverket==0.3.1
# homeassistant.components.usb # homeassistant.components.usb
pyudev==0.23.2 pyudev==0.23.2

View File

@ -1551,7 +1551,7 @@ pytradfri[async]==9.0.1
# homeassistant.components.trafikverket_ferry # homeassistant.components.trafikverket_ferry
# homeassistant.components.trafikverket_train # homeassistant.components.trafikverket_train
# homeassistant.components.trafikverket_weatherstation # homeassistant.components.trafikverket_weatherstation
pytrafikverket==0.2.3 pytrafikverket==0.3.1
# homeassistant.components.usb # homeassistant.components.usb
pyudev==0.23.2 pyudev==0.23.2

View File

@ -4,6 +4,7 @@ from __future__ import annotations
from unittest.mock import patch from unittest.mock import patch
import pytest import pytest
from pytrafikverket.exceptions import InvalidAuthentication, NoFerryFound
from homeassistant import config_entries from homeassistant import config_entries
from homeassistant.components.trafikverket_ferry.const import ( from homeassistant.components.trafikverket_ferry.const import (
@ -63,24 +64,24 @@ async def test_form(hass: HomeAssistant) -> None:
@pytest.mark.parametrize( @pytest.mark.parametrize(
("error_message", "base_error"), ("side_effect", "base_error"),
[ [
( (
"Source: Security, message: Invalid authentication", InvalidAuthentication,
"invalid_auth", "invalid_auth",
), ),
( (
"No FerryAnnouncement found", NoFerryFound,
"invalid_route", "invalid_route",
), ),
( (
"Unknown", Exception,
"cannot_connect", "cannot_connect",
), ),
], ],
) )
async def test_flow_fails( async def test_flow_fails(
hass: HomeAssistant, error_message: str, base_error: str hass: HomeAssistant, side_effect: str, base_error: str
) -> None: ) -> None:
"""Test config flow errors.""" """Test config flow errors."""
result4 = await hass.config_entries.flow.async_init( result4 = await hass.config_entries.flow.async_init(
@ -92,7 +93,7 @@ async def test_flow_fails(
with patch( with patch(
"homeassistant.components.trafikverket_ferry.config_flow.TrafikverketFerry.async_get_next_ferry_stop", "homeassistant.components.trafikverket_ferry.config_flow.TrafikverketFerry.async_get_next_ferry_stop",
side_effect=ValueError(error_message), side_effect=side_effect(),
): ):
result4 = await hass.config_entries.flow.async_configure( result4 = await hass.config_entries.flow.async_configure(
result4["flow_id"], result4["flow_id"],
@ -161,24 +162,24 @@ async def test_reauth_flow(hass: HomeAssistant) -> None:
@pytest.mark.parametrize( @pytest.mark.parametrize(
("sideeffect", "p_error"), ("side_effect", "p_error"),
[ [
( (
ValueError("Source: Security, message: Invalid authentication"), InvalidAuthentication,
"invalid_auth", "invalid_auth",
), ),
( (
ValueError("No FerryAnnouncement found"), NoFerryFound,
"invalid_route", "invalid_route",
), ),
( (
ValueError("Unknown"), Exception,
"cannot_connect", "cannot_connect",
), ),
], ],
) )
async def test_reauth_flow_error( async def test_reauth_flow_error(
hass: HomeAssistant, sideeffect: Exception, p_error: str hass: HomeAssistant, side_effect: Exception, p_error: str
) -> None: ) -> None:
"""Test a reauthentication flow with error.""" """Test a reauthentication flow with error."""
entry = MockConfigEntry( entry = MockConfigEntry(
@ -207,7 +208,7 @@ async def test_reauth_flow_error(
with patch( with patch(
"homeassistant.components.trafikverket_ferry.config_flow.TrafikverketFerry.async_get_next_ferry_stop", "homeassistant.components.trafikverket_ferry.config_flow.TrafikverketFerry.async_get_next_ferry_stop",
side_effect=sideeffect, side_effect=side_effect(),
): ):
result2 = await hass.config_entries.flow.async_configure( result2 = await hass.config_entries.flow.async_configure(
result["flow_id"], result["flow_id"],

View File

@ -2,10 +2,11 @@
from __future__ import annotations from __future__ import annotations
from datetime import date, datetime, timedelta from datetime import date, datetime, timedelta
from unittest.mock import AsyncMock, patch from unittest.mock import patch
from freezegun.api import FrozenDateTimeFactory from freezegun.api import FrozenDateTimeFactory
import pytest import pytest
from pytrafikverket.exceptions import InvalidAuthentication, NoFerryFound
from pytrafikverket.trafikverket_ferry import FerryStop from pytrafikverket.trafikverket_ferry import FerryStop
from homeassistant.components.trafikverket_ferry.const import DOMAIN from homeassistant.components.trafikverket_ferry.const import DOMAIN
@ -22,7 +23,7 @@ from tests.common import MockConfigEntry, async_fire_time_changed
async def test_coordinator( async def test_coordinator(
hass: HomeAssistant, hass: HomeAssistant,
entity_registry_enabled_by_default: AsyncMock, entity_registry_enabled_by_default: None,
monkeypatch: pytest.MonkeyPatch, monkeypatch: pytest.MonkeyPatch,
get_ferries: list[FerryStop], get_ferries: list[FerryStop],
) -> None: ) -> None:
@ -69,7 +70,7 @@ async def test_coordinator(
assert state3.state == str(dt.now().year + 2) + "-05-01T12:00:00+00:00" assert state3.state == str(dt.now().year + 2) + "-05-01T12:00:00+00:00"
mock_data.reset_mock() mock_data.reset_mock()
mock_data.side_effect = ValueError("info") mock_data.side_effect = NoFerryFound()
async_fire_time_changed(hass, dt.utcnow() + timedelta(minutes=6)) async_fire_time_changed(hass, dt.utcnow() + timedelta(minutes=6))
await hass.async_block_till_done() await hass.async_block_till_done()
mock_data.assert_called_once() mock_data.assert_called_once()
@ -81,11 +82,19 @@ async def test_coordinator(
mock_data.side_effect = None mock_data.side_effect = None
async_fire_time_changed(hass, dt.utcnow() + timedelta(minutes=6)) async_fire_time_changed(hass, dt.utcnow() + timedelta(minutes=6))
await hass.async_block_till_done() await hass.async_block_till_done()
mock_data.assert_called_once() # mock_data.assert_called_once()
state1 = hass.states.get("sensor.harbor1_departure_from") state1 = hass.states.get("sensor.harbor1_departure_from")
assert state1.state == "Harbor 1" assert state1.state == "Harbor 1"
mock_data.reset_mock() mock_data.reset_mock()
mock_data.side_effect = InvalidAuthentication()
async_fire_time_changed(hass, dt.utcnow() + timedelta(minutes=6))
await hass.async_block_till_done()
mock_data.assert_called_once()
state1 = hass.states.get("sensor.harbor1_departure_from")
assert state1.state == STATE_UNAVAILABLE
mock_data.reset_mock()
async def test_coordinator_next_departuredate(freezer: FrozenDateTimeFactory) -> None: async def test_coordinator_next_departuredate(freezer: FrozenDateTimeFactory) -> None:
"""Test the Trafikverket Ferry next_departuredate calculation.""" """Test the Trafikverket Ferry next_departuredate calculation."""

View File

@ -4,6 +4,11 @@ from __future__ import annotations
from unittest.mock import patch from unittest.mock import patch
import pytest import pytest
from pytrafikverket.exceptions import (
InvalidAuthentication,
MultipleTrainStationsFound,
NoTrainStationFound,
)
from homeassistant import config_entries from homeassistant import config_entries
from homeassistant.components.trafikverket_train.const import ( from homeassistant.components.trafikverket_train.const import (
@ -108,28 +113,28 @@ async def test_form_entry_already_exist(hass: HomeAssistant) -> None:
@pytest.mark.parametrize( @pytest.mark.parametrize(
("error_message", "base_error"), ("side_effect", "base_error"),
[ [
( (
"Source: Security, message: Invalid authentication", InvalidAuthentication,
"invalid_auth", "invalid_auth",
), ),
( (
"Could not find a station with the specified name", NoTrainStationFound,
"invalid_station", "invalid_station",
), ),
( (
"Found multiple stations with the specified name", MultipleTrainStationsFound,
"more_stations", "more_stations",
), ),
( (
"Unknown", Exception,
"cannot_connect", "cannot_connect",
), ),
], ],
) )
async def test_flow_fails( async def test_flow_fails(
hass: HomeAssistant, error_message: str, base_error: str hass: HomeAssistant, side_effect: Exception, base_error: str
) -> None: ) -> None:
"""Test config flow errors.""" """Test config flow errors."""
result4 = await hass.config_entries.flow.async_init( result4 = await hass.config_entries.flow.async_init(
@ -141,7 +146,7 @@ async def test_flow_fails(
with patch( with patch(
"homeassistant.components.trafikverket_train.config_flow.TrafikverketTrain.async_get_train_station", "homeassistant.components.trafikverket_train.config_flow.TrafikverketTrain.async_get_train_station",
side_effect=ValueError(error_message), side_effect=side_effect(),
): ):
result4 = await hass.config_entries.flow.async_configure( result4 = await hass.config_entries.flow.async_configure(
result4["flow_id"], result4["flow_id"],
@ -234,28 +239,28 @@ async def test_reauth_flow(hass: HomeAssistant) -> None:
@pytest.mark.parametrize( @pytest.mark.parametrize(
("sideeffect", "p_error"), ("side_effect", "p_error"),
[ [
( (
ValueError("Source: Security, message: Invalid authentication"), InvalidAuthentication,
"invalid_auth", "invalid_auth",
), ),
( (
ValueError("Could not find a station with the specified name"), NoTrainStationFound,
"invalid_station", "invalid_station",
), ),
( (
ValueError("Found multiple stations with the specified name"), MultipleTrainStationsFound,
"more_stations", "more_stations",
), ),
( (
ValueError("Unknown"), Exception,
"cannot_connect", "cannot_connect",
), ),
], ],
) )
async def test_reauth_flow_error( async def test_reauth_flow_error(
hass: HomeAssistant, sideeffect: Exception, p_error: str hass: HomeAssistant, side_effect: Exception, p_error: str
) -> None: ) -> None:
"""Test a reauthentication flow with error.""" """Test a reauthentication flow with error."""
entry = MockConfigEntry( entry = MockConfigEntry(
@ -284,7 +289,7 @@ async def test_reauth_flow_error(
with patch( with patch(
"homeassistant.components.trafikverket_train.config_flow.TrafikverketTrain.async_get_train_station", "homeassistant.components.trafikverket_train.config_flow.TrafikverketTrain.async_get_train_station",
side_effect=sideeffect, side_effect=side_effect(),
): ):
result2 = await hass.config_entries.flow.async_configure( result2 = await hass.config_entries.flow.async_configure(
result["flow_id"], result["flow_id"],

View File

@ -4,6 +4,11 @@ from __future__ import annotations
from unittest.mock import patch from unittest.mock import patch
import pytest import pytest
from pytrafikverket.exceptions import (
InvalidAuthentication,
MultipleWeatherStationsFound,
NoWeatherStationFound,
)
from homeassistant import config_entries from homeassistant import config_entries
from homeassistant.const import CONF_API_KEY from homeassistant.const import CONF_API_KEY
@ -48,28 +53,28 @@ async def test_form(hass: HomeAssistant) -> None:
@pytest.mark.parametrize( @pytest.mark.parametrize(
("error_message", "base_error"), ("side_effect", "base_error"),
[ [
( (
"Source: Security, message: Invalid authentication", InvalidAuthentication,
"invalid_auth", "invalid_auth",
), ),
( (
"Could not find a weather station with the specified name", NoWeatherStationFound,
"invalid_station", "invalid_station",
), ),
( (
"Found multiple weather stations with the specified name", MultipleWeatherStationsFound,
"more_stations", "more_stations",
), ),
( (
"Unknown", Exception,
"cannot_connect", "cannot_connect",
), ),
], ],
) )
async def test_flow_fails( async def test_flow_fails(
hass: HomeAssistant, error_message: str, base_error: str hass: HomeAssistant, side_effect: Exception, base_error: str
) -> None: ) -> None:
"""Test config flow errors.""" """Test config flow errors."""
result4 = await hass.config_entries.flow.async_init( result4 = await hass.config_entries.flow.async_init(
@ -81,7 +86,7 @@ async def test_flow_fails(
with patch( with patch(
"homeassistant.components.trafikverket_weatherstation.config_flow.TrafikverketWeather.async_get_weather", "homeassistant.components.trafikverket_weatherstation.config_flow.TrafikverketWeather.async_get_weather",
side_effect=ValueError(error_message), side_effect=side_effect(),
): ):
result4 = await hass.config_entries.flow.async_configure( result4 = await hass.config_entries.flow.async_configure(
result4["flow_id"], result4["flow_id"],