Enable mypy for motionEye (aye aye!) (#49738)

This commit is contained in:
Dermot Duffy 2021-05-03 23:19:41 -07:00 committed by GitHub
parent 55c96ae86f
commit 809c1394d4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 31 additions and 28 deletions

View file

@ -65,10 +65,10 @@ def get_motioneye_entity_unique_id(
def get_camera_from_cameras(
camera_id: int, data: dict[str, Any]
camera_id: int, data: dict[str, Any] | None
) -> dict[str, Any] | None:
"""Get an individual camera dict from a multiple cameras data response."""
for camera in data.get(KEY_CAMERAS) or []:
for camera in data.get(KEY_CAMERAS, []) if data else []:
if camera.get(KEY_ID) == camera_id:
val: dict[str, Any] = camera
return val
@ -105,7 +105,7 @@ def _add_camera(
entry: ConfigEntry,
camera_id: int,
camera: dict[str, Any],
device_identifier: tuple[str, str, int],
device_identifier: tuple[str, str],
) -> None:
"""Add a motionEye camera to hass."""
@ -164,14 +164,14 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
CONF_COORDINATOR: coordinator,
}
current_cameras: set[tuple[str, str, int]] = set()
current_cameras: set[tuple[str, str]] = set()
device_registry = await dr.async_get_registry(hass)
@callback
def _async_process_motioneye_cameras() -> None:
"""Process motionEye camera additions and removals."""
inbound_camera: set[tuple[str, str, int]] = set()
if KEY_CAMERAS not in coordinator.data:
inbound_camera: set[tuple[str, str]] = set()
if coordinator.data is None or KEY_CAMERAS not in coordinator.data:
return
for camera in coordinator.data[KEY_CAMERAS]:

View file

@ -2,7 +2,7 @@
from __future__ import annotations
import logging
from typing import Any
from typing import Any, Dict, Optional
import aiohttp
from motioneye_client.client import MotionEyeClient
@ -86,7 +86,7 @@ async def async_setup_entry(
listen_for_new_cameras(hass, entry, camera_add)
class MotionEyeMjpegCamera(MjpegCamera, CoordinatorEntity):
class MotionEyeMjpegCamera(MjpegCamera, CoordinatorEntity[Optional[Dict[str, Any]]]):
"""motionEye mjpeg camera."""
def __init__(
@ -96,7 +96,7 @@ class MotionEyeMjpegCamera(MjpegCamera, CoordinatorEntity):
password: str,
camera: dict[str, Any],
client: MotionEyeClient,
coordinator: DataUpdateCoordinator,
coordinator: DataUpdateCoordinator[dict[str, Any] | None],
) -> None:
"""Initialize a MJPEG camera."""
self._surveillance_username = username
@ -191,7 +191,7 @@ class MotionEyeMjpegCamera(MjpegCamera, CoordinatorEntity):
self._motion_detection_enabled = camera.get(KEY_MOTION_DETECTION, False)
available = True
self._available = available
CoordinatorEntity._handle_coordinator_update(self)
super()._handle_coordinator_update()
@property
def brand(self) -> str:

View file

@ -2,7 +2,7 @@
from __future__ import annotations
import logging
from typing import Any
from typing import Any, Dict, cast
from motioneye_client.client import (
MotionEyeClientConnectionError,
@ -13,8 +13,8 @@ import voluptuous as vol
from homeassistant.config_entries import SOURCE_REAUTH, ConfigFlow
from homeassistant.const import CONF_SOURCE, CONF_URL
from homeassistant.data_entry_flow import FlowResult
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.typing import ConfigType
from . import create_motioneye_client
from .const import (
@ -34,13 +34,13 @@ class MotionEyeConfigFlow(ConfigFlow, domain=DOMAIN):
VERSION = 1
async def async_step_user(
self, user_input: ConfigType | None = None
) -> dict[str, Any]:
self, user_input: dict[str, Any] | None = None
) -> FlowResult:
"""Handle the initial step."""
def _get_form(
user_input: ConfigType, errors: dict[str, str] | None = None
) -> dict[str, Any]:
user_input: dict[str, Any], errors: dict[str, str] | None = None
) -> FlowResult:
"""Show the form to the user."""
return self.async_show_form(
step_id="user",
@ -77,7 +77,9 @@ class MotionEyeConfigFlow(ConfigFlow, domain=DOMAIN):
)
if user_input is None:
return _get_form(reauth_entry.data if reauth_entry else {})
return _get_form(
cast(Dict[str, Any], reauth_entry.data) if reauth_entry else {}
)
try:
# Cannot use cv.url validation in the schema itself, so
@ -130,7 +132,7 @@ class MotionEyeConfigFlow(ConfigFlow, domain=DOMAIN):
async def async_step_reauth(
self,
config_data: ConfigType | None = None,
) -> dict[str, Any]:
config_data: dict[str, Any] | None = None,
) -> FlowResult:
"""Handle a reauthentication flow."""
return await self.async_step_user(config_data)

View file

@ -996,9 +996,6 @@ ignore_errors = true
[mypy-homeassistant.components.motion_blinds.*]
ignore_errors = true
[mypy-homeassistant.components.motioneye.*]
ignore_errors = true
[mypy-homeassistant.components.mqtt.*]
ignore_errors = true

View file

@ -135,7 +135,6 @@ IGNORED_MODULES: Final[list[str]] = [
"homeassistant.components.minecraft_server.*",
"homeassistant.components.mobile_app.*",
"homeassistant.components.motion_blinds.*",
"homeassistant.components.motioneye.*",
"homeassistant.components.mqtt.*",
"homeassistant.components.mullvad.*",
"homeassistant.components.mysensors.*",

View file

@ -5,7 +5,7 @@ import asyncio
import collections
from collections import OrderedDict
from contextlib import contextmanager
from datetime import timedelta
from datetime import datetime, timedelta
import functools as ft
from io import StringIO
import json
@ -44,7 +44,7 @@ from homeassistant.const import (
STATE_OFF,
STATE_ON,
)
from homeassistant.core import BLOCK_LOG_TIMEOUT, State
from homeassistant.core import BLOCK_LOG_TIMEOUT, HomeAssistant, State
from homeassistant.helpers import (
area_registry,
device_registry,
@ -361,7 +361,9 @@ fire_mqtt_message = threadsafe_callback_factory(async_fire_mqtt_message)
@ha.callback
def async_fire_time_changed(hass, datetime_, fire_all=False):
def async_fire_time_changed(
hass: HomeAssistant, datetime_: datetime, fire_all: bool = False
) -> None:
"""Fire a time changes event."""
hass.bus.async_fire(EVENT_TIME_CHANGED, {"now": date_util.as_utc(datetime_)})

View file

@ -4,7 +4,7 @@ import logging
from typing import Any
from unittest.mock import AsyncMock, Mock
from aiohttp import web # type: ignore
from aiohttp import web
from aiohttp.web_exceptions import HTTPBadGateway
from motioneye_client.client import (
MotionEyeClientError,
@ -165,6 +165,7 @@ async def test_setup_camera_new_data_error(hass: HomeAssistant) -> None:
async_fire_time_changed(hass, dt_util.utcnow() + DEFAULT_SCAN_INTERVAL)
await hass.async_block_till_done()
entity_state = hass.states.get(TEST_CAMERA_ENTITY_ID)
assert entity_state
assert entity_state.state == "unavailable"
@ -173,6 +174,7 @@ async def test_setup_camera_new_data_without_streaming(hass: HomeAssistant) -> N
client = create_mock_motioneye_client()
await setup_mock_motioneye_config_entry(hass, client=client)
entity_state = hass.states.get(TEST_CAMERA_ENTITY_ID)
assert entity_state
assert entity_state.state == "idle"
cameras = copy.deepcopy(TEST_CAMERAS)
@ -181,6 +183,7 @@ async def test_setup_camera_new_data_without_streaming(hass: HomeAssistant) -> N
async_fire_time_changed(hass, dt_util.utcnow() + DEFAULT_SCAN_INTERVAL)
await hass.async_block_till_done()
entity_state = hass.states.get(TEST_CAMERA_ENTITY_ID)
assert entity_state
assert entity_state.state == "unavailable"

View file

@ -235,7 +235,7 @@ async def test_reauth(hass: HomeAssistant) -> None:
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
assert result["reason"] == "reauth_successful"
assert config_entry.data == new_data
assert dict(config_entry.data) == new_data
assert len(mock_setup_entry.mock_calls) == 1
assert mock_client.async_client_close.called