mirror of
https://github.com/home-assistant/core.git
synced 2025-07-22 20:57:21 +00:00
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:
parent
e721d8ed02
commit
180b296426
@ -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
|
||||||
|
@ -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}"
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
@ -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."""
|
||||||
|
57
tests/components/ipma/test_init.py
Normal file
57
tests/components/ipma/test_init.py
Normal 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
|
@ -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."""
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user