Fix PVOutput when no data is available (#66338)

This commit is contained in:
Franck Nijhof 2022-02-11 19:11:06 +01:00 committed by GitHub
parent df994a1e84
commit 8ff987d90c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 30 additions and 22 deletions

View file

@ -23,7 +23,7 @@ async def validate_input(hass: HomeAssistant, *, api_key: str, system_id: int) -
api_key=api_key, api_key=api_key,
system_id=system_id, system_id=system_id,
) )
await pvoutput.status() await pvoutput.system()
class PVOutputFlowHandler(ConfigFlow, domain=DOMAIN): class PVOutputFlowHandler(ConfigFlow, domain=DOMAIN):

View file

@ -1,14 +1,14 @@
"""DataUpdateCoordinator for the PVOutput integration.""" """DataUpdateCoordinator for the PVOutput integration."""
from __future__ import annotations from __future__ import annotations
from pvo import PVOutput, PVOutputAuthenticationError, Status from pvo import PVOutput, PVOutputAuthenticationError, PVOutputNoDataError, Status
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.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 from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from .const import CONF_SYSTEM_ID, DOMAIN, LOGGER, SCAN_INTERVAL from .const import CONF_SYSTEM_ID, DOMAIN, LOGGER, SCAN_INTERVAL
@ -33,5 +33,7 @@ class PVOutputDataUpdateCoordinator(DataUpdateCoordinator[Status]):
"""Fetch system status from PVOutput.""" """Fetch system status from PVOutput."""
try: try:
return await self.pvoutput.status() return await self.pvoutput.status()
except PVOutputNoDataError as err:
raise UpdateFailed("PVOutput has no data available") from err
except PVOutputAuthenticationError as err: except PVOutputAuthenticationError as err:
raise ConfigEntryAuthFailed from err raise ConfigEntryAuthFailed from err

View file

@ -4,7 +4,7 @@
"documentation": "https://www.home-assistant.io/integrations/pvoutput", "documentation": "https://www.home-assistant.io/integrations/pvoutput",
"config_flow": true, "config_flow": true,
"codeowners": ["@fabaff", "@frenck"], "codeowners": ["@fabaff", "@frenck"],
"requirements": ["pvo==0.2.1"], "requirements": ["pvo==0.2.2"],
"iot_class": "cloud_polling", "iot_class": "cloud_polling",
"quality_scale": "platinum" "quality_scale": "platinum"
} }

View file

@ -1313,7 +1313,7 @@ pushbullet.py==0.11.0
pushover_complete==1.1.1 pushover_complete==1.1.1
# homeassistant.components.pvoutput # homeassistant.components.pvoutput
pvo==0.2.1 pvo==0.2.2
# homeassistant.components.rpi_gpio_pwm # homeassistant.components.rpi_gpio_pwm
pwmled==1.6.9 pwmled==1.6.9

View file

@ -820,7 +820,7 @@ pure-python-adb[async]==0.3.0.dev0
pushbullet.py==0.11.0 pushbullet.py==0.11.0
# homeassistant.components.pvoutput # homeassistant.components.pvoutput
pvo==0.2.1 pvo==0.2.2
# homeassistant.components.canary # homeassistant.components.canary
py-canary==0.5.1 py-canary==0.5.1

View file

@ -47,7 +47,7 @@ async def test_full_user_flow(
} }
assert len(mock_setup_entry.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1
assert len(mock_pvoutput_config_flow.status.mock_calls) == 1 assert len(mock_pvoutput_config_flow.system.mock_calls) == 1
async def test_full_flow_with_authentication_error( async def test_full_flow_with_authentication_error(
@ -68,7 +68,7 @@ async def test_full_flow_with_authentication_error(
assert result.get("step_id") == SOURCE_USER assert result.get("step_id") == SOURCE_USER
assert "flow_id" in result assert "flow_id" in result
mock_pvoutput_config_flow.status.side_effect = PVOutputAuthenticationError mock_pvoutput_config_flow.system.side_effect = PVOutputAuthenticationError
result2 = await hass.config_entries.flow.async_configure( result2 = await hass.config_entries.flow.async_configure(
result["flow_id"], result["flow_id"],
user_input={ user_input={
@ -83,9 +83,9 @@ async def test_full_flow_with_authentication_error(
assert "flow_id" in result2 assert "flow_id" in result2
assert len(mock_setup_entry.mock_calls) == 0 assert len(mock_setup_entry.mock_calls) == 0
assert len(mock_pvoutput_config_flow.status.mock_calls) == 1 assert len(mock_pvoutput_config_flow.system.mock_calls) == 1
mock_pvoutput_config_flow.status.side_effect = None mock_pvoutput_config_flow.system.side_effect = None
result3 = await hass.config_entries.flow.async_configure( result3 = await hass.config_entries.flow.async_configure(
result2["flow_id"], result2["flow_id"],
user_input={ user_input={
@ -102,14 +102,14 @@ async def test_full_flow_with_authentication_error(
} }
assert len(mock_setup_entry.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1
assert len(mock_pvoutput_config_flow.status.mock_calls) == 2 assert len(mock_pvoutput_config_flow.system.mock_calls) == 2
async def test_connection_error( async def test_connection_error(
hass: HomeAssistant, mock_pvoutput_config_flow: MagicMock hass: HomeAssistant, mock_pvoutput_config_flow: MagicMock
) -> None: ) -> None:
"""Test API connection error.""" """Test API connection error."""
mock_pvoutput_config_flow.status.side_effect = PVOutputConnectionError mock_pvoutput_config_flow.system.side_effect = PVOutputConnectionError
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, DOMAIN,
@ -123,7 +123,7 @@ async def test_connection_error(
assert result.get("type") == RESULT_TYPE_FORM assert result.get("type") == RESULT_TYPE_FORM
assert result.get("errors") == {"base": "cannot_connect"} assert result.get("errors") == {"base": "cannot_connect"}
assert len(mock_pvoutput_config_flow.status.mock_calls) == 1 assert len(mock_pvoutput_config_flow.system.mock_calls) == 1
async def test_already_configured( async def test_already_configured(
@ -175,7 +175,7 @@ async def test_import_flow(
} }
assert len(mock_setup_entry.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1
assert len(mock_pvoutput_config_flow.status.mock_calls) == 1 assert len(mock_pvoutput_config_flow.system.mock_calls) == 1
async def test_reauth_flow( async def test_reauth_flow(
@ -214,7 +214,7 @@ async def test_reauth_flow(
} }
assert len(mock_setup_entry.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1
assert len(mock_pvoutput_config_flow.status.mock_calls) == 1 assert len(mock_pvoutput_config_flow.system.mock_calls) == 1
async def test_reauth_with_authentication_error( async def test_reauth_with_authentication_error(
@ -243,7 +243,7 @@ async def test_reauth_with_authentication_error(
assert result.get("step_id") == "reauth_confirm" assert result.get("step_id") == "reauth_confirm"
assert "flow_id" in result assert "flow_id" in result
mock_pvoutput_config_flow.status.side_effect = PVOutputAuthenticationError mock_pvoutput_config_flow.system.side_effect = PVOutputAuthenticationError
result2 = await hass.config_entries.flow.async_configure( result2 = await hass.config_entries.flow.async_configure(
result["flow_id"], result["flow_id"],
{CONF_API_KEY: "invalid_key"}, {CONF_API_KEY: "invalid_key"},
@ -256,9 +256,9 @@ async def test_reauth_with_authentication_error(
assert "flow_id" in result2 assert "flow_id" in result2
assert len(mock_setup_entry.mock_calls) == 0 assert len(mock_setup_entry.mock_calls) == 0
assert len(mock_pvoutput_config_flow.status.mock_calls) == 1 assert len(mock_pvoutput_config_flow.system.mock_calls) == 1
mock_pvoutput_config_flow.status.side_effect = None mock_pvoutput_config_flow.system.side_effect = None
result3 = await hass.config_entries.flow.async_configure( result3 = await hass.config_entries.flow.async_configure(
result2["flow_id"], result2["flow_id"],
user_input={CONF_API_KEY: "valid_key"}, user_input={CONF_API_KEY: "valid_key"},
@ -273,7 +273,7 @@ async def test_reauth_with_authentication_error(
} }
assert len(mock_setup_entry.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1
assert len(mock_pvoutput_config_flow.status.mock_calls) == 2 assert len(mock_pvoutput_config_flow.system.mock_calls) == 2
async def test_reauth_api_error( async def test_reauth_api_error(
@ -297,7 +297,7 @@ async def test_reauth_api_error(
assert result.get("step_id") == "reauth_confirm" assert result.get("step_id") == "reauth_confirm"
assert "flow_id" in result assert "flow_id" in result
mock_pvoutput_config_flow.status.side_effect = PVOutputConnectionError mock_pvoutput_config_flow.system.side_effect = PVOutputConnectionError
result2 = await hass.config_entries.flow.async_configure( result2 = await hass.config_entries.flow.async_configure(
result["flow_id"], result["flow_id"],
{CONF_API_KEY: "some_new_key"}, {CONF_API_KEY: "some_new_key"},

View file

@ -1,7 +1,11 @@
"""Tests for the PVOutput integration.""" """Tests for the PVOutput integration."""
from unittest.mock import MagicMock from unittest.mock import MagicMock
from pvo import PVOutputAuthenticationError, PVOutputConnectionError from pvo import (
PVOutputAuthenticationError,
PVOutputConnectionError,
PVOutputNoDataError,
)
import pytest import pytest
from homeassistant.components.pvoutput.const import CONF_SYSTEM_ID, DOMAIN from homeassistant.components.pvoutput.const import CONF_SYSTEM_ID, DOMAIN
@ -35,13 +39,15 @@ async def test_load_unload_config_entry(
assert mock_config_entry.state is ConfigEntryState.NOT_LOADED assert mock_config_entry.state is ConfigEntryState.NOT_LOADED
@pytest.mark.parametrize("side_effect", [PVOutputConnectionError, PVOutputNoDataError])
async def test_config_entry_not_ready( async def test_config_entry_not_ready(
hass: HomeAssistant, hass: HomeAssistant,
mock_config_entry: MockConfigEntry, mock_config_entry: MockConfigEntry,
mock_pvoutput: MagicMock, mock_pvoutput: MagicMock,
side_effect: Exception,
) -> None: ) -> None:
"""Test the PVOutput configuration entry not ready.""" """Test the PVOutput configuration entry not ready."""
mock_pvoutput.status.side_effect = PVOutputConnectionError mock_pvoutput.status.side_effect = side_effect
mock_config_entry.add_to_hass(hass) mock_config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(mock_config_entry.entry_id) await hass.config_entries.async_setup(mock_config_entry.entry_id)