Extend typing on scaffold templates (#48232)

This commit is contained in:
Franck Nijhof 2021-03-26 15:19:44 +01:00 committed by GitHub
parent 3bc6497cbd
commit d2d78d6205
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 85 additions and 44 deletions

View File

@ -1,5 +1,8 @@
"""The NEW_NAME integration."""
from __future__ import annotations
import asyncio
from typing import Any
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
@ -11,12 +14,12 @@ from .const import DOMAIN
PLATFORMS = ["light"]
async def async_setup(hass: HomeAssistant, config: dict):
async def async_setup(hass: HomeAssistant, config: dict[str, Any]) -> bool:
"""Set up the NEW_NAME component."""
return True
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up NEW_NAME from a config entry."""
# TODO Store an API object for your platforms to access
# hass.data[DOMAIN][entry.entry_id] = MyApi(...)
@ -29,7 +32,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
return True
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a config entry."""
unload_ok = all(
await asyncio.gather(

View File

@ -1,9 +1,14 @@
"""Config flow for NEW_NAME integration."""
from __future__ import annotations
import logging
from typing import Any
import voluptuous as vol
from homeassistant import config_entries, core, exceptions
from homeassistant import config_entries
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from .const import DOMAIN # pylint:disable=unused-import
@ -19,16 +24,16 @@ class PlaceholderHub:
TODO Remove this placeholder class and replace with things from your PyPI package.
"""
def __init__(self, host):
def __init__(self, host: str) -> None:
"""Initialize."""
self.host = host
async def authenticate(self, username, password) -> bool:
async def authenticate(self, username: str, password: str) -> bool:
"""Test if we can authenticate with the host."""
return True
async def validate_input(hass: core.HomeAssistant, data):
async def validate_input(hass: HomeAssistant, data: dict[str, Any]) -> dict[str, Any]:
"""Validate the user input allows us to connect.
Data has the keys from STEP_USER_DATA_SCHEMA with values provided by the user.
@ -62,7 +67,9 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
# TODO pick one of the available connection classes in homeassistant/config_entries.py
CONNECTION_CLASS = config_entries.CONN_CLASS_UNKNOWN
async def async_step_user(self, user_input=None):
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> dict[str, Any]:
"""Handle the initial step."""
if user_input is None:
return self.async_show_form(
@ -88,9 +95,9 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
)
class CannotConnect(exceptions.HomeAssistantError):
class CannotConnect(HomeAssistantError):
"""Error to indicate we cannot connect."""
class InvalidAuth(exceptions.HomeAssistantError):
class InvalidAuth(HomeAssistantError):
"""Error to indicate there is invalid auth."""

View File

@ -4,9 +4,10 @@ from unittest.mock import patch
from homeassistant import config_entries, setup
from homeassistant.components.NEW_DOMAIN.config_flow import CannotConnect, InvalidAuth
from homeassistant.components.NEW_DOMAIN.const import DOMAIN
from homeassistant.core import HomeAssistant
async def test_form(hass):
async def test_form(hass: HomeAssistant) -> None:
"""Test we get the form."""
await setup.async_setup_component(hass, "persistent_notification", {})
result = await hass.config_entries.flow.async_init(
@ -45,7 +46,7 @@ async def test_form(hass):
assert len(mock_setup_entry.mock_calls) == 1
async def test_form_invalid_auth(hass):
async def test_form_invalid_auth(hass: HomeAssistant) -> None:
"""Test we handle invalid auth."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
@ -68,7 +69,7 @@ async def test_form_invalid_auth(hass):
assert result2["errors"] == {"base": "invalid_auth"}
async def test_form_cannot_connect(hass):
async def test_form_cannot_connect(hass: HomeAssistant) -> None:
"""Test we handle cannot connect error."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}

View File

@ -1,5 +1,8 @@
"""The NEW_NAME integration."""
from __future__ import annotations
import asyncio
from typing import Any
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
@ -11,12 +14,12 @@ from .const import DOMAIN
PLATFORMS = ["light"]
async def async_setup(hass: HomeAssistant, config: dict):
async def async_setup(hass: HomeAssistant, config: dict[str, Any]) -> bool:
"""Set up the NEW_NAME component."""
return True
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up NEW_NAME from a config entry."""
# TODO Store an API object for your platforms to access
# hass.data[DOMAIN][entry.entry_id] = MyApi(...)
@ -29,7 +32,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
return True
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a config entry."""
unload_ok = all(
await asyncio.gather(

View File

@ -2,12 +2,13 @@
import my_pypi_dependency
from homeassistant import config_entries
from homeassistant.core import HomeAssistant
from homeassistant.helpers import config_entry_flow
from .const import DOMAIN
async def _async_has_devices(hass) -> bool:
async def _async_has_devices(hass: HomeAssistant) -> bool:
"""Return if there are devices that can be discovered."""
# TODO Check if there are any devices that can be discovered in the network.
devices = await hass.async_add_executor_job(my_pypi_dependency.discover)

View File

@ -1,5 +1,8 @@
"""The NEW_NAME integration."""
from __future__ import annotations
import asyncio
from typing import Any
import voluptuous as vol
@ -32,7 +35,7 @@ CONFIG_SCHEMA = vol.Schema(
PLATFORMS = ["light"]
async def async_setup(hass: HomeAssistant, config: dict):
async def async_setup(hass: HomeAssistant, config: dict[str, Any]) -> bool:
"""Set up the NEW_NAME component."""
hass.data[DOMAIN] = {}
@ -54,7 +57,7 @@ async def async_setup(hass: HomeAssistant, config: dict):
return True
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up NEW_NAME from a config entry."""
implementation = (
await config_entry_oauth2_flow.async_get_config_entry_implementation(
@ -80,7 +83,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
return True
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a config entry."""
unload_ok = all(
await asyncio.gather(

View File

@ -4,7 +4,7 @@ from asyncio import run_coroutine_threadsafe
from aiohttp import ClientSession
import my_pypi_package
from homeassistant import core
from homeassistant.core import HomeAssistant
from homeassistant.helpers import config_entry_oauth2_flow
# TODO the following two API examples are based on our suggested best practices
@ -17,9 +17,9 @@ class ConfigEntryAuth(my_pypi_package.AbstractAuth):
def __init__(
self,
hass: core.HomeAssistant,
hass: HomeAssistant,
oauth_session: config_entry_oauth2_flow.OAuth2Session,
):
) -> None:
"""Initialize NEW_NAME Auth."""
self.hass = hass
self.session = oauth_session
@ -41,7 +41,7 @@ class AsyncConfigEntryAuth(my_pypi_package.AbstractAuth):
self,
websession: ClientSession,
oauth_session: config_entry_oauth2_flow.OAuth2Session,
):
) -> None:
"""Initialize NEW_NAME auth."""
super().__init__(websession)
self._oauth_session = oauth_session

View File

@ -7,6 +7,7 @@ from homeassistant.components.NEW_DOMAIN.const import (
OAUTH2_AUTHORIZE,
OAUTH2_TOKEN,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import config_entry_oauth2_flow
CLIENT_ID = "1234"
@ -14,8 +15,11 @@ CLIENT_SECRET = "5678"
async def test_full_flow(
hass, aiohttp_client, aioclient_mock, current_request_with_host
):
hass: HomeAssistant,
aiohttp_client,
aioclient_mock,
current_request_with_host,
) -> None:
"""Check full flow."""
assert await setup.async_setup_component(
hass,

View File

@ -3,7 +3,8 @@ import pytest
from homeassistant.components import automation
from homeassistant.components.NEW_DOMAIN import DOMAIN
from homeassistant.helpers import device_registry
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry, entity_registry
from homeassistant.setup import async_setup_component
from tests.common import (
@ -17,18 +18,22 @@ from tests.common import (
@pytest.fixture
def device_reg(hass):
def device_reg(hass: HomeAssistant) -> device_registry.DeviceRegistry:
"""Return an empty, loaded, registry."""
return mock_device_registry(hass)
@pytest.fixture
def entity_reg(hass):
def entity_reg(hass: HomeAssistant) -> entity_registry.EntityRegistry:
"""Return an empty, loaded, registry."""
return mock_registry(hass)
async def test_get_actions(hass, device_reg, entity_reg):
async def test_get_actions(
hass: HomeAssistant,
device_reg: device_registry.DeviceRegistry,
entity_reg: entity_registry.EntityRegistry,
) -> None:
"""Test we get the expected actions from a NEW_DOMAIN."""
config_entry = MockConfigEntry(domain="test", data={})
config_entry.add_to_hass(hass)
@ -55,7 +60,7 @@ async def test_get_actions(hass, device_reg, entity_reg):
assert_lists_same(actions, expected_actions)
async def test_action(hass):
async def test_action(hass: HomeAssistant) -> None:
"""Test for turn_on and turn_off actions."""
assert await async_setup_component(
hass,

View File

@ -1,10 +1,13 @@
"""The tests for NEW_NAME device conditions."""
from __future__ import annotations
import pytest
from homeassistant.components import automation
from homeassistant.components.NEW_DOMAIN import DOMAIN
from homeassistant.const import STATE_OFF, STATE_ON
from homeassistant.helpers import device_registry
from homeassistant.core import HomeAssistant, ServiceCall
from homeassistant.helpers import device_registry, entity_registry
from homeassistant.setup import async_setup_component
from tests.common import (
@ -18,24 +21,28 @@ from tests.common import (
@pytest.fixture
def device_reg(hass):
def device_reg(hass: HomeAssistant) -> device_registry.DeviceRegistry:
"""Return an empty, loaded, registry."""
return mock_device_registry(hass)
@pytest.fixture
def entity_reg(hass):
def entity_reg(hass: HomeAssistant) -> entity_registry.EntityRegistry:
"""Return an empty, loaded, registry."""
return mock_registry(hass)
@pytest.fixture
def calls(hass):
def calls(hass: HomeAssistant) -> list[ServiceCall]:
"""Track calls to a mock service."""
return async_mock_service(hass, "test", "automation")
async def test_get_conditions(hass, device_reg, entity_reg):
async def test_get_conditions(
hass: HomeAssistant,
device_reg: device_registry.DeviceRegistry,
entity_reg: entity_registry.EntityRegistry,
) -> None:
"""Test we get the expected conditions from a NEW_DOMAIN."""
config_entry = MockConfigEntry(domain="test", data={})
config_entry.add_to_hass(hass)
@ -64,7 +71,7 @@ async def test_get_conditions(hass, device_reg, entity_reg):
assert_lists_same(conditions, expected_conditions)
async def test_if_state(hass, calls):
async def test_if_state(hass: HomeAssistant, calls: list[ServiceCall]) -> None:
"""Test for turn_on and turn_off conditions."""
hass.states.async_set("NEW_DOMAIN.entity", STATE_ON)

View File

@ -1,4 +1,8 @@
"""The NEW_NAME integration."""
from __future__ import annotations
from typing import Any
import voluptuous as vol
from homeassistant.core import HomeAssistant
@ -8,6 +12,6 @@ from .const import DOMAIN
CONFIG_SCHEMA = vol.Schema({vol.Optional(DOMAIN): {}}, extra=vol.ALLOW_EXTRA)
async def async_setup(hass: HomeAssistant, config: dict):
async def async_setup(hass: HomeAssistant, config: dict[str, Any]) -> bool:
"""Set up the NEW_NAME integration."""
return True

View File

@ -12,8 +12,7 @@ from homeassistant.const import (
STATE_OFF,
STATE_ON,
)
from homeassistant.core import Context, State
from homeassistant.helpers.typing import HomeAssistantType
from homeassistant.core import Context, HomeAssistant, State
from . import DOMAIN
@ -24,7 +23,7 @@ VALID_STATES = {STATE_ON, STATE_OFF}
async def _async_reproduce_state(
hass: HomeAssistantType,
hass: HomeAssistant,
state: State,
*,
context: Context | None = None,
@ -69,7 +68,7 @@ async def _async_reproduce_state(
async def async_reproduce_states(
hass: HomeAssistantType,
hass: HomeAssistant,
states: Iterable[State],
*,
context: Context | None = None,

View File

@ -1,10 +1,14 @@
"""Test reproduce state for NEW_NAME."""
from homeassistant.core import State
import pytest
from homeassistant.core import HomeAssistant, State
from tests.common import async_mock_service
async def test_reproducing_states(hass, caplog):
async def test_reproducing_states(
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
) -> None:
"""Test reproducing NEW_NAME states."""
hass.states.async_set("NEW_DOMAIN.entity_off", "off", {})
hass.states.async_set("NEW_DOMAIN.entity_on", "on", {"color": "red"})