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

View File

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

View File

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

View File

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

View File

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

View File

@ -5,7 +5,7 @@ import asyncio
import collections import collections
from collections import OrderedDict from collections import OrderedDict
from contextlib import contextmanager from contextlib import contextmanager
from datetime import timedelta from datetime import datetime, timedelta
import functools as ft import functools as ft
from io import StringIO from io import StringIO
import json import json
@ -44,7 +44,7 @@ from homeassistant.const import (
STATE_OFF, STATE_OFF,
STATE_ON, STATE_ON,
) )
from homeassistant.core import BLOCK_LOG_TIMEOUT, State from homeassistant.core import BLOCK_LOG_TIMEOUT, HomeAssistant, State
from homeassistant.helpers import ( from homeassistant.helpers import (
area_registry, area_registry,
device_registry, device_registry,
@ -361,7 +361,9 @@ fire_mqtt_message = threadsafe_callback_factory(async_fire_mqtt_message)
@ha.callback @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.""" """Fire a time changes event."""
hass.bus.async_fire(EVENT_TIME_CHANGED, {"now": date_util.as_utc(datetime_)}) 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 typing import Any
from unittest.mock import AsyncMock, Mock from unittest.mock import AsyncMock, Mock
from aiohttp import web # type: ignore from aiohttp import web
from aiohttp.web_exceptions import HTTPBadGateway from aiohttp.web_exceptions import HTTPBadGateway
from motioneye_client.client import ( from motioneye_client.client import (
MotionEyeClientError, 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) async_fire_time_changed(hass, dt_util.utcnow() + DEFAULT_SCAN_INTERVAL)
await hass.async_block_till_done() await hass.async_block_till_done()
entity_state = hass.states.get(TEST_CAMERA_ENTITY_ID) entity_state = hass.states.get(TEST_CAMERA_ENTITY_ID)
assert entity_state
assert entity_state.state == "unavailable" 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() client = create_mock_motioneye_client()
await setup_mock_motioneye_config_entry(hass, client=client) await setup_mock_motioneye_config_entry(hass, client=client)
entity_state = hass.states.get(TEST_CAMERA_ENTITY_ID) entity_state = hass.states.get(TEST_CAMERA_ENTITY_ID)
assert entity_state
assert entity_state.state == "idle" assert entity_state.state == "idle"
cameras = copy.deepcopy(TEST_CAMERAS) 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) async_fire_time_changed(hass, dt_util.utcnow() + DEFAULT_SCAN_INTERVAL)
await hass.async_block_till_done() await hass.async_block_till_done()
entity_state = hass.states.get(TEST_CAMERA_ENTITY_ID) entity_state = hass.states.get(TEST_CAMERA_ENTITY_ID)
assert entity_state
assert entity_state.state == "unavailable" 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["type"] == data_entry_flow.RESULT_TYPE_ABORT
assert result["reason"] == "reauth_successful" 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 len(mock_setup_entry.mock_calls) == 1
assert mock_client.async_client_close.called assert mock_client.async_client_close.called