IPMA Code quality improvement (#77771)

* merge upstream/dev

* remove comment

* coverage increase

* merge upstream/dev

* refactor

* wait for another PR

* remove left overs

* wait for next PR

* only remove on successful unload

Co-authored-by: Shay Levy <levyshay1@gmail.com>

Co-authored-by: Shay Levy <levyshay1@gmail.com>
This commit is contained in:
Diogo Gomes 2022-10-13 22:18:57 +01:00 committed by GitHub
parent e721d8ed02
commit 180b296426
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 184 additions and 151 deletions

View File

@ -57,4 +57,11 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a config entry.""" """Unload a config entry."""
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS):
hass.data[DOMAIN].pop(entry.entry_id)
if not hass.data[DOMAIN]:
hass.data.pop(DOMAIN)
return unload_ok

View File

@ -5,7 +5,7 @@ DOMAIN = "ipma"
HOME_LOCATION_NAME = "Home" HOME_LOCATION_NAME = "Home"
ENTITY_ID_SENSOR_FORMAT_HOME = f"{WEATHER_DOMAIN}.ipma_{HOME_LOCATION_NAME}"
DATA_LOCATION = "location"
DATA_API = "api" DATA_API = "api"
DATA_LOCATION = "location"
ENTITY_ID_SENSOR_FORMAT_HOME = f"{WEATHER_DOMAIN}.ipma_{HOME_LOCATION_NAME}"

View File

@ -8,7 +8,6 @@ import async_timeout
from pyipma.api import IPMA_API from pyipma.api import IPMA_API
from pyipma.forecast import Forecast from pyipma.forecast import Forecast
from pyipma.location import Location from pyipma.location import Location
import voluptuous as vol
from homeassistant.components.weather import ( from homeassistant.components.weather import (
ATTR_CONDITION_CLEAR_NIGHT, ATTR_CONDITION_CLEAR_NIGHT,
@ -33,13 +32,10 @@ from homeassistant.components.weather import (
ATTR_FORECAST_PRECIPITATION_PROBABILITY, ATTR_FORECAST_PRECIPITATION_PROBABILITY,
ATTR_FORECAST_TIME, ATTR_FORECAST_TIME,
ATTR_FORECAST_WIND_BEARING, ATTR_FORECAST_WIND_BEARING,
PLATFORM_SCHEMA,
WeatherEntity, WeatherEntity,
) )
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ( from homeassistant.const import (
CONF_LATITUDE,
CONF_LONGITUDE,
CONF_MODE, CONF_MODE,
CONF_NAME, CONF_NAME,
PRESSURE_HPA, PRESSURE_HPA,
@ -47,7 +43,7 @@ from homeassistant.const import (
TEMP_CELSIUS, TEMP_CELSIUS,
) )
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import config_validation as cv, entity_registry from homeassistant.helpers import entity_registry
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.sun import is_up from homeassistant.helpers.sun import is_up
from homeassistant.util import Throttle from homeassistant.util import Throttle
@ -80,15 +76,6 @@ CONDITION_CLASSES = {
FORECAST_MODE = ["hourly", "daily"] FORECAST_MODE = ["hourly", "daily"]
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
{
vol.Optional(CONF_NAME): cv.string,
vol.Optional(CONF_LATITUDE): cv.latitude,
vol.Optional(CONF_LONGITUDE): cv.longitude,
vol.Optional(CONF_MODE, default="daily"): vol.In(FORECAST_MODE),
}
)
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,

View File

@ -1 +1,111 @@
"""Tests for the IPMA component.""" """Tests for the IPMA component."""
from collections import namedtuple
from datetime import datetime, timezone
from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE, CONF_MODE, CONF_NAME
ENTRY_CONFIG = {
CONF_NAME: "Home Town",
CONF_LATITUDE: "1",
CONF_LONGITUDE: "2",
CONF_MODE: "hourly",
}
class MockLocation:
"""Mock Location from pyipma."""
async def observation(self, api):
"""Mock Observation."""
Observation = namedtuple(
"Observation",
[
"accumulated_precipitation",
"humidity",
"pressure",
"radiation",
"temperature",
"wind_direction",
"wind_intensity_km",
],
)
return Observation(0.0, 71.0, 1000.0, 0.0, 18.0, "NW", 3.94)
async def forecast(self, api, period):
"""Mock Forecast."""
Forecast = namedtuple(
"Forecast",
[
"feels_like_temperature",
"forecast_date",
"forecasted_hours",
"humidity",
"max_temperature",
"min_temperature",
"precipitation_probability",
"temperature",
"update_date",
"weather_type",
"wind_direction",
"wind_strength",
],
)
WeatherType = namedtuple("WeatherType", ["id", "en", "pt"])
if period == 24:
return [
Forecast(
None,
datetime(2020, 1, 16, 0, 0, 0),
24,
None,
16.2,
10.6,
"100.0",
13.4,
"2020-01-15T07:51:00",
WeatherType(9, "Rain/showers", "Chuva/aguaceiros"),
"S",
"10",
),
]
if period == 1:
return [
Forecast(
"7.7",
datetime(2020, 1, 15, 1, 0, 0, tzinfo=timezone.utc),
1,
"86.9",
12.0,
None,
80.0,
10.6,
"2020-01-15T02:51:00",
WeatherType(10, "Light rain", "Chuva fraca ou chuvisco"),
"S",
"32.7",
),
Forecast(
"5.7",
datetime(2020, 1, 15, 2, 0, 0, tzinfo=timezone.utc),
1,
"86.9",
12.0,
None,
80.0,
10.6,
"2020-01-15T02:51:00",
WeatherType(1, "Clear sky", "C\u00e9u limpo"),
"S",
"32.7",
),
]
name = "HomeTown"
station = "HomeTown Station"
station_latitude = 0
station_longitude = 0
global_id_local = 1130600
id_station = 1200545

View File

@ -3,21 +3,14 @@
from unittest.mock import Mock, patch from unittest.mock import Mock, patch
from homeassistant.components.ipma import DOMAIN, config_flow from homeassistant.components.ipma import DOMAIN, config_flow
from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE, CONF_MODE, CONF_NAME from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE, CONF_MODE
from homeassistant.helpers import entity_registry as er from homeassistant.helpers import entity_registry as er
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
from .test_weather import MockLocation from . import MockLocation
from tests.common import MockConfigEntry, mock_registry from tests.common import MockConfigEntry, mock_registry
ENTRY_CONFIG = {
CONF_NAME: "Home Town",
CONF_LATITUDE: "1",
CONF_LONGITUDE: "2",
CONF_MODE: "hourly",
}
async def test_show_config_form(): async def test_show_config_form():
"""Test show configuration form.""" """Test show configuration form."""

View File

@ -0,0 +1,57 @@
"""Test the IPMA integration."""
from unittest.mock import patch
from pyipma import IPMAException
from homeassistant.components.ipma import DOMAIN
from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE, CONF_MODE
from .test_weather import MockLocation
from tests.common import MockConfigEntry
async def test_async_setup_raises_entry_not_ready(hass):
"""Test that it throws ConfigEntryNotReady when exception occurs during setup."""
with patch(
"pyipma.location.Location.get", side_effect=IPMAException("API unavailable")
):
config_entry = MockConfigEntry(
domain=DOMAIN,
title="Home",
data={CONF_LATITUDE: 0, CONF_LONGITUDE: 0, CONF_MODE: "daily"},
)
config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(config_entry.entry_id)
assert config_entry.state is ConfigEntryState.SETUP_RETRY
async def test_unload_config_entry(hass):
"""Test entry unloading."""
with patch(
"pyipma.location.Location.get",
return_value=MockLocation(),
):
config_entry = MockConfigEntry(
domain="ipma",
data={CONF_LATITUDE: 0, CONF_LONGITUDE: 0, CONF_MODE: "daily"},
)
config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
assert config_entry.state is ConfigEntryState.LOADED
await hass.config_entries.async_unload(config_entry.entry_id)
await hass.async_block_till_done()
assert config_entry.state is ConfigEntryState.NOT_LOADED

View File

@ -1,6 +1,5 @@
"""The tests for the IPMA weather component.""" """The tests for the IPMA weather component."""
from collections import namedtuple from datetime import datetime
from datetime import datetime, timezone
from unittest.mock import patch from unittest.mock import patch
from freezegun import freeze_time from freezegun import freeze_time
@ -22,6 +21,8 @@ from homeassistant.components.weather import (
) )
from homeassistant.const import STATE_UNKNOWN from homeassistant.const import STATE_UNKNOWN
from . import MockLocation
from tests.common import MockConfigEntry from tests.common import MockConfigEntry
TEST_CONFIG = { TEST_CONFIG = {
@ -39,128 +40,6 @@ TEST_CONFIG_HOURLY = {
} }
class MockLocation:
"""Mock Location from pyipma."""
async def observation(self, api):
"""Mock Observation."""
Observation = namedtuple(
"Observation",
[
"accumulated_precipitation",
"humidity",
"pressure",
"radiation",
"temperature",
"wind_direction",
"wind_intensity_km",
],
)
return Observation(0.0, 71.0, 1000.0, 0.0, 18.0, "NW", 3.94)
async def forecast(self, api, period):
"""Mock Forecast."""
Forecast = namedtuple(
"Forecast",
[
"feels_like_temperature",
"forecast_date",
"forecasted_hours",
"humidity",
"max_temperature",
"min_temperature",
"precipitation_probability",
"temperature",
"update_date",
"weather_type",
"wind_direction",
"wind_strength",
],
)
WeatherType = namedtuple("WeatherType", ["id", "en", "pt"])
if period == 24:
return [
Forecast(
None,
datetime(2020, 1, 16, 0, 0, 0),
24,
None,
16.2,
10.6,
"100.0",
13.4,
"2020-01-15T07:51:00",
WeatherType(9, "Rain/showers", "Chuva/aguaceiros"),
"S",
"10",
),
]
if period == 1:
return [
Forecast(
"7.7",
datetime(2020, 1, 15, 1, 0, 0, tzinfo=timezone.utc),
1,
"86.9",
12.0,
None,
80.0,
10.6,
"2020-01-15T02:51:00",
WeatherType(10, "Light rain", "Chuva fraca ou chuvisco"),
"S",
"32.7",
),
Forecast(
"5.7",
datetime(2020, 1, 15, 2, 0, 0, tzinfo=timezone.utc),
1,
"86.9",
12.0,
None,
80.0,
10.6,
"2020-01-15T02:51:00",
WeatherType(1, "Clear sky", "C\u00e9u limpo"),
"S",
"32.7",
),
]
@property
def name(self):
"""Mock location."""
return "HomeTown"
@property
def station(self):
"""Mock station."""
return "HomeTown Station"
@property
def station_latitude(self):
"""Mock latitude."""
return 0
@property
def global_id_local(self):
"""Mock global identifier of the location."""
return 1130600
@property
def id_station(self):
"""Mock identifier of the station."""
return 1200545
@property
def station_longitude(self):
"""Mock longitude."""
return 0
class MockBadLocation(MockLocation): class MockBadLocation(MockLocation):
"""Mock Location with unresponsive api.""" """Mock Location with unresponsive api."""