Skip to content

Commit

Permalink
Enable strict typing for onboarding (#108097)
Browse files Browse the repository at this point in the history
  • Loading branch information
cdce8p committed Jan 15, 2024
1 parent 5dde45e commit 6a9fdaa
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 21 deletions.
1 change: 1 addition & 0 deletions .strict-typing
Expand Up @@ -304,6 +304,7 @@ homeassistant.components.notify.*
homeassistant.components.notion.*
homeassistant.components.number.*
homeassistant.components.nut.*
homeassistant.components.onboarding.*
homeassistant.components.oncue.*
homeassistant.components.onewire.*
homeassistant.components.open_meteo.*
Expand Down
12 changes: 10 additions & 2 deletions homeassistant/components/onboarding/__init__.py
@@ -1,4 +1,6 @@
"""Support to help onboard new users."""
from __future__ import annotations

from typing import TYPE_CHECKING

from homeassistant.core import HomeAssistant, callback
Expand All @@ -23,10 +25,15 @@
CONFIG_SCHEMA = cv.empty_config_schema(DOMAIN)


class OnboadingStorage(Store):
class OnboadingStorage(Store[dict[str, list[str]]]):
"""Store onboarding data."""

async def _async_migrate_func(self, old_major_version, old_minor_version, old_data):
async def _async_migrate_func(
self,
old_major_version: int,
old_minor_version: int,
old_data: dict[str, list[str]],
) -> dict[str, list[str]]:
"""Migrate to the new version."""
# From version 1 -> 2, we automatically mark the integration step done
if old_major_version < 2:
Expand Down Expand Up @@ -56,6 +63,7 @@ def async_is_user_onboarded(hass: HomeAssistant) -> bool:
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the onboarding component."""
store = OnboadingStorage(hass, STORAGE_VERSION, STORAGE_KEY, private=True)
data: dict[str, list[str]] | None
if (data := await store.async_load()) is None:
data = {"done": []}

Expand Down
42 changes: 24 additions & 18 deletions homeassistant/components/onboarding/views.py
Expand Up @@ -3,7 +3,7 @@

import asyncio
from http import HTTPStatus
from typing import cast
from typing import TYPE_CHECKING, Any, cast

from aiohttp import web
from aiohttp.web_exceptions import HTTPUnauthorized
Expand All @@ -21,6 +21,9 @@
from homeassistant.helpers.system_info import async_get_system_info
from homeassistant.helpers.translation import async_get_translations

if TYPE_CHECKING:
from . import OnboadingStorage

from .const import (
DEFAULT_AREAS,
DOMAIN,
Expand All @@ -32,7 +35,9 @@
)


async def async_setup(hass, data, store):
async def async_setup(
hass: HomeAssistant, data: dict[str, list[str]], store: OnboadingStorage
) -> None:
"""Set up the onboarding view."""
hass.http.register_view(OnboardingView(data, store))
hass.http.register_view(InstallationTypeOnboardingView(data))
Expand All @@ -49,12 +54,12 @@ class OnboardingView(HomeAssistantView):
url = "/api/onboarding"
name = "api:onboarding"

def __init__(self, data, store):
def __init__(self, data: dict[str, list[str]], store: OnboadingStorage) -> None:
"""Initialize the onboarding view."""
self._store = store
self._data = data

async def get(self, request):
async def get(self, request: web.Request) -> web.Response:
"""Return the onboarding status."""
return self.json(
[{"step": key, "done": key in self._data["done"]} for key in STEPS]
Expand All @@ -68,37 +73,37 @@ class InstallationTypeOnboardingView(HomeAssistantView):
url = "/api/onboarding/installation_type"
name = "api:onboarding:installation_type"

def __init__(self, data):
def __init__(self, data: dict[str, list[str]]) -> None:
"""Initialize the onboarding installation type view."""
self._data = data

async def get(self, request):
async def get(self, request: web.Request) -> web.Response:
"""Return the onboarding status."""
if self._data["done"]:
raise HTTPUnauthorized()

hass = request.app["hass"]
hass: HomeAssistant = request.app["hass"]
info = await async_get_system_info(hass)
return self.json({"installation_type": info["installation_type"]})


class _BaseOnboardingView(HomeAssistantView):
"""Base class for onboarding."""

step: str | None = None
step: str

def __init__(self, data, store):
def __init__(self, data: dict[str, list[str]], store: OnboadingStorage) -> None:
"""Initialize the onboarding view."""
self._store = store
self._data = data
self._lock = asyncio.Lock()

@callback
def _async_is_done(self):
def _async_is_done(self) -> bool:
"""Return if this step is done."""
return self.step in self._data["done"]

async def _async_mark_done(self, hass):
async def _async_mark_done(self, hass: HomeAssistant) -> None:
"""Mark step as done."""
self._data["done"].append(self.step)
await self._store.async_save(self._data)
Expand Down Expand Up @@ -180,9 +185,9 @@ class CoreConfigOnboardingView(_BaseOnboardingView):
name = "api:onboarding:core_config"
step = STEP_CORE_CONFIG

async def post(self, request):
async def post(self, request: web.Request) -> web.Response:
"""Handle finishing core config step."""
hass = request.app["hass"]
hass: HomeAssistant = request.app["hass"]

async with self._lock:
if self._async_is_done():
Expand All @@ -205,7 +210,8 @@ async def post(self, request):

if (
hassio.is_hassio(hass)
and "raspberrypi" in hassio.get_core_info(hass)["machine"]
and (core_info := hassio.get_core_info(hass))
and "raspberrypi" in core_info["machine"]
):
onboard_integrations.append("rpi_power")

Expand All @@ -232,9 +238,9 @@ class IntegrationOnboardingView(_BaseOnboardingView):
@RequestDataValidator(
vol.Schema({vol.Required("client_id"): str, vol.Required("redirect_uri"): str})
)
async def post(self, request, data):
async def post(self, request: web.Request, data: dict[str, Any]) -> web.Response:
"""Handle token creation."""
hass = request.app["hass"]
hass: HomeAssistant = request.app["hass"]
refresh_token_id = request[KEY_HASS_REFRESH_TOKEN_ID]

async with self._lock:
Expand Down Expand Up @@ -276,9 +282,9 @@ class AnalyticsOnboardingView(_BaseOnboardingView):
name = "api:onboarding:analytics"
step = STEP_ANALYTICS

async def post(self, request):
async def post(self, request: web.Request) -> web.Response:
"""Handle finishing analytics step."""
hass = request.app["hass"]
hass: HomeAssistant = request.app["hass"]

async with self._lock:
if self._async_is_done():
Expand Down
8 changes: 7 additions & 1 deletion homeassistant/components/person/__init__.py
Expand Up @@ -92,7 +92,13 @@


@bind_hass
async def async_create_person(hass, name, *, user_id=None, device_trackers=None):
async def async_create_person(
hass: HomeAssistant,
name: str,
*,
user_id: str | None = None,
device_trackers: list[str] | None = None,
) -> None:
"""Create a new person."""
await hass.data[DOMAIN][1].async_create_item(
{
Expand Down
10 changes: 10 additions & 0 deletions mypy.ini
Expand Up @@ -2801,6 +2801,16 @@ disallow_untyped_defs = true
warn_return_any = true
warn_unreachable = true

[mypy-homeassistant.components.onboarding.*]
check_untyped_defs = true
disallow_incomplete_defs = true
disallow_subclassing_any = true
disallow_untyped_calls = true
disallow_untyped_decorators = true
disallow_untyped_defs = true
warn_return_any = true
warn_unreachable = true

[mypy-homeassistant.components.oncue.*]
check_untyped_defs = true
disallow_incomplete_defs = true
Expand Down

0 comments on commit 6a9fdaa

Please sign in to comment.