From 2c904c09747e9e25439a479f3395970cd9d9896b Mon Sep 17 00:00:00 2001 From: Tobias Sauerwein Date: Mon, 27 Dec 2021 17:55:17 +0100 Subject: [PATCH] Bump mypy to 0.930 (#62642) Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com> --- homeassistant/auth/mfa_modules/__init__.py | 4 ++-- homeassistant/auth/providers/__init__.py | 5 ++-- homeassistant/backports/enum.py | 2 +- .../components/device_tracker/legacy.py | 8 +++---- homeassistant/components/esphome/camera.py | 6 +++-- homeassistant/components/http/forwarded.py | 2 +- homeassistant/components/notify/legacy.py | 4 ++-- homeassistant/config.py | 14 +++++------ homeassistant/config_entries.py | 24 +++++++++++-------- homeassistant/core.py | 4 ++-- homeassistant/helpers/check_config.py | 4 +--- homeassistant/helpers/condition.py | 4 ++-- homeassistant/helpers/config_validation.py | 14 +++++++++-- homeassistant/helpers/reload.py | 4 ++-- homeassistant/helpers/script.py | 4 ++-- homeassistant/helpers/service.py | 5 ++-- homeassistant/loader.py | 2 +- homeassistant/scripts/__init__.py | 2 +- homeassistant/setup.py | 7 +++--- homeassistant/util/color.py | 4 ++-- homeassistant/util/executor.py | 6 ++--- requirements_test.txt | 2 +- 22 files changed, 73 insertions(+), 58 deletions(-) diff --git a/homeassistant/auth/mfa_modules/__init__.py b/homeassistant/auth/mfa_modules/__init__.py index 4adaf4776a0..60f790fa490 100644 --- a/homeassistant/auth/mfa_modules/__init__.py +++ b/homeassistant/auth/mfa_modules/__init__.py @@ -133,7 +133,7 @@ async def auth_mfa_module_from_config( module = await _load_mfa_module(hass, module_name) try: - config = module.CONFIG_SCHEMA(config) # type: ignore + config = module.CONFIG_SCHEMA(config) except vol.Invalid as err: _LOGGER.error( "Invalid configuration for multi-factor module %s: %s", @@ -168,7 +168,7 @@ async def _load_mfa_module(hass: HomeAssistant, module_name: str) -> types.Modul # https://github.com/python/mypy/issues/1424 await requirements.async_process_requirements( - hass, module_path, module.REQUIREMENTS # type: ignore + hass, module_path, module.REQUIREMENTS ) processed.add(module_name) diff --git a/homeassistant/auth/providers/__init__.py b/homeassistant/auth/providers/__init__.py index dc5f8f2580c..73968191182 100644 --- a/homeassistant/auth/providers/__init__.py +++ b/homeassistant/auth/providers/__init__.py @@ -142,7 +142,7 @@ async def auth_provider_from_config( module = await load_auth_provider_module(hass, provider_name) try: - config = module.CONFIG_SCHEMA(config) # type: ignore + config = module.CONFIG_SCHEMA(config) except vol.Invalid as err: _LOGGER.error( "Invalid configuration for auth provider %s: %s", @@ -174,8 +174,7 @@ async def load_auth_provider_module( elif provider in processed: return module - # https://github.com/python/mypy/issues/1424 - reqs = module.REQUIREMENTS # type: ignore + reqs = module.REQUIREMENTS await requirements.async_process_requirements( hass, f"auth provider {provider}", reqs ) diff --git a/homeassistant/backports/enum.py b/homeassistant/backports/enum.py index 3fa9a582f79..21302fe9f7b 100644 --- a/homeassistant/backports/enum.py +++ b/homeassistant/backports/enum.py @@ -14,7 +14,7 @@ class StrEnum(str, Enum): """Create a new StrEnum instance.""" if not isinstance(value, str): raise TypeError(f"{value!r} is not a string") - return super().__new__(cls, value, *args, **kwargs) # type: ignore[call-overload,no-any-return] + return super().__new__(cls, value, *args, **kwargs) def __str__(self) -> str: """Return self.value.""" diff --git a/homeassistant/components/device_tracker/legacy.py b/homeassistant/components/device_tracker/legacy.py index d81743c530a..3614beccdfa 100644 --- a/homeassistant/components/device_tracker/legacy.py +++ b/homeassistant/components/device_tracker/legacy.py @@ -238,22 +238,22 @@ class DeviceTrackerPlatform: scanner = None setup = None if hasattr(self.platform, "async_get_scanner"): - scanner = await self.platform.async_get_scanner( # type: ignore[attr-defined] + scanner = await self.platform.async_get_scanner( hass, {DOMAIN: self.config} ) elif hasattr(self.platform, "get_scanner"): scanner = await hass.async_add_executor_job( - self.platform.get_scanner, # type: ignore[attr-defined] + self.platform.get_scanner, hass, {DOMAIN: self.config}, ) elif hasattr(self.platform, "async_setup_scanner"): - setup = await self.platform.async_setup_scanner( # type: ignore[attr-defined] + setup = await self.platform.async_setup_scanner( hass, self.config, tracker.async_see, discovery_info ) elif hasattr(self.platform, "setup_scanner"): setup = await hass.async_add_executor_job( - self.platform.setup_scanner, # type: ignore[attr-defined] + self.platform.setup_scanner, hass, self.config, tracker.see, diff --git a/homeassistant/components/esphome/camera.py b/homeassistant/components/esphome/camera.py index 47010324290..390208f689d 100644 --- a/homeassistant/components/esphome/camera.py +++ b/homeassistant/components/esphome/camera.py @@ -60,7 +60,8 @@ class EsphomeCamera(Camera, EsphomeEntity[CameraInfo, CameraState]): async with self._image_cond: await self._image_cond.wait() if not self.available: - return None + # Availability can change while waiting for 'self._image.cond' + return None # type: ignore[unreachable] return self._state.data[:] async def _async_camera_stream_image(self) -> bytes | None: @@ -71,7 +72,8 @@ class EsphomeCamera(Camera, EsphomeEntity[CameraInfo, CameraState]): async with self._image_cond: await self._image_cond.wait() if not self.available: - return None + # Availability can change while waiting for 'self._image.cond' + return None # type: ignore[unreachable] return self._state.data[:] async def handle_async_mjpeg_stream( diff --git a/homeassistant/components/http/forwarded.py b/homeassistant/components/http/forwarded.py index 4cc330a85ed..ff50e9bd965 100644 --- a/homeassistant/components/http/forwarded.py +++ b/homeassistant/components/http/forwarded.py @@ -88,7 +88,7 @@ def async_setup_forwarded( remote = False # Skip requests from Remote UI - if remote and remote.is_cloud_request.get(): # type: ignore + if remote and remote.is_cloud_request.get(): return await handler(request) # Handle X-Forwarded-For diff --git a/homeassistant/components/notify/legacy.py b/homeassistant/components/notify/legacy.py index 8eb007b6398..c5be8a1800e 100644 --- a/homeassistant/components/notify/legacy.py +++ b/homeassistant/components/notify/legacy.py @@ -58,12 +58,12 @@ async def async_setup_legacy(hass: HomeAssistant, config: ConfigType) -> None: notify_service = None try: if hasattr(platform, "async_get_service"): - notify_service = await platform.async_get_service( # type: ignore + notify_service = await platform.async_get_service( hass, p_config, discovery_info ) elif hasattr(platform, "get_service"): notify_service = await hass.async_add_executor_job( - platform.get_service, hass, p_config, discovery_info # type: ignore + platform.get_service, hass, p_config, discovery_info ) else: raise HomeAssistantError("Invalid notify platform.") diff --git a/homeassistant/config.py b/homeassistant/config.py index ed9ffa7c47d..3d1ff4f3c1d 100644 --- a/homeassistant/config.py +++ b/homeassistant/config.py @@ -642,10 +642,10 @@ def _log_pkg_error(package: str, component: str, config: dict, message: str) -> def _identify_config_schema(module: ModuleType) -> str | None: """Extract the schema and identify list or dict based.""" - if not isinstance(module.CONFIG_SCHEMA, vol.Schema): # type: ignore + if not isinstance(module.CONFIG_SCHEMA, vol.Schema): return None - schema = module.CONFIG_SCHEMA.schema # type: ignore + schema = module.CONFIG_SCHEMA.schema if isinstance(schema, vol.All): for subschema in schema.validators: @@ -656,7 +656,7 @@ def _identify_config_schema(module: ModuleType) -> str | None: return None try: - key = next(k for k in schema if k == module.DOMAIN) # type: ignore + key = next(k for k in schema if k == module.DOMAIN) except (TypeError, AttributeError, StopIteration): return None except Exception: # pylint: disable=broad-except @@ -666,8 +666,8 @@ def _identify_config_schema(module: ModuleType) -> str | None: if hasattr(key, "default") and not isinstance( key.default, vol.schema_builder.Undefined ): - default_value = module.CONFIG_SCHEMA({module.DOMAIN: key.default()})[ # type: ignore - module.DOMAIN # type: ignore + default_value = module.CONFIG_SCHEMA({module.DOMAIN: key.default()})[ + module.DOMAIN ] if isinstance(default_value, dict): @@ -747,7 +747,7 @@ async def merge_packages_config( # If integration has a custom config validator, it needs to provide a hint. if config_platform is not None: - merge_list = config_platform.PACKAGE_MERGE_HINT == "list" # type: ignore[attr-defined] + merge_list = config_platform.PACKAGE_MERGE_HINT == "list" if not merge_list: merge_list = hasattr(component, "PLATFORM_SCHEMA") @@ -889,7 +889,7 @@ async def async_process_component_config( # noqa: C901 # Validate platform specific schema if hasattr(platform, "PLATFORM_SCHEMA"): try: - p_validated = platform.PLATFORM_SCHEMA(p_config) # type: ignore + p_validated = platform.PLATFORM_SCHEMA(p_config) except vol.Invalid as ex: async_log_exception( ex, diff --git a/homeassistant/config_entries.py b/homeassistant/config_entries.py index 063040dc398..da524bf068d 100644 --- a/homeassistant/config_entries.py +++ b/homeassistant/config_entries.py @@ -9,7 +9,7 @@ from enum import Enum import functools import logging from types import MappingProxyType, MethodType -from typing import TYPE_CHECKING, Any, Callable, Optional, cast +from typing import TYPE_CHECKING, Any, Callable, Optional, TypeVar, cast import weakref from . import data_entry_flow, loader @@ -70,6 +70,8 @@ PATH_CONFIG = ".config_entries.json" SAVE_DELAY = 1 +_T = TypeVar("_T", bound="ConfigEntryState") + class ConfigEntryState(Enum): """Config entry state.""" @@ -89,12 +91,12 @@ class ConfigEntryState(Enum): _recoverable: bool - def __new__(cls: type[object], value: str, recoverable: bool) -> ConfigEntryState: + def __new__(cls: type[_T], value: str, recoverable: bool) -> _T: """Create new ConfigEntryState.""" obj = object.__new__(cls) obj._value_ = value obj._recoverable = recoverable - return cast("ConfigEntryState", obj) + return obj @property def recoverable(self) -> bool: @@ -321,7 +323,7 @@ class ConfigEntry: error_reason = None try: - result = await component.async_setup_entry(hass, self) # type: ignore + result = await component.async_setup_entry(hass, self) if not isinstance(result, bool): _LOGGER.error( @@ -460,7 +462,7 @@ class ConfigEntry: return False try: - result = await component.async_unload_entry(hass, self) # type: ignore + result = await component.async_unload_entry(hass, self) assert isinstance(result, bool) @@ -471,7 +473,8 @@ class ConfigEntry: self._async_process_on_unload() - return result + # https://github.com/python/mypy/issues/11839 + return result # type: ignore[no-any-return] except Exception: # pylint: disable=broad-except _LOGGER.exception( "Error unloading entry %s for %s", self.title, integration.domain @@ -499,7 +502,7 @@ class ConfigEntry: if not hasattr(component, "async_remove_entry"): return try: - await component.async_remove_entry(hass, self) # type: ignore + await component.async_remove_entry(hass, self) except Exception: # pylint: disable=broad-except _LOGGER.exception( "Error calling entry remove callback %s for %s", @@ -536,7 +539,7 @@ class ConfigEntry: return False try: - result = await component.async_migrate_entry(hass, self) # type: ignore + result = await component.async_migrate_entry(hass, self) if not isinstance(result, bool): _LOGGER.error( "%s.async_migrate_entry did not return boolean", self.domain @@ -545,7 +548,8 @@ class ConfigEntry: if result: # pylint: disable=protected-access hass.config_entries._async_schedule_save() - return result + # https://github.com/python/mypy/issues/11839 + return result # type: ignore[no-any-return] except Exception: # pylint: disable=broad-except _LOGGER.exception( "Error migrating entry %s for %s", self.title, self.domain @@ -1169,7 +1173,7 @@ class ConfigFlow(data_entry_flow.FlowHandler): def __init_subclass__(cls, domain: str | None = None, **kwargs: Any) -> None: """Initialize a subclass, register if possible.""" - super().__init_subclass__(**kwargs) # type: ignore + super().__init_subclass__(**kwargs) if domain is not None: HANDLERS.register(domain)(cls) diff --git a/homeassistant/core.py b/homeassistant/core.py index 9566ad6c596..819db0b6825 100644 --- a/homeassistant/core.py +++ b/homeassistant/core.py @@ -362,7 +362,7 @@ class HomeAssistant: raise ValueError("Don't call async_add_job with None") if asyncio.iscoroutine(target): - return self.async_create_task(cast(Coroutine, target)) + return self.async_create_task(target) return self.async_add_hass_job(HassJob(target), *args) @@ -462,7 +462,7 @@ class HomeAssistant: args: parameters for method to call. """ if asyncio.iscoroutine(target): - return self.async_create_task(cast(Coroutine, target)) + return self.async_create_task(target) return self.async_run_hass_job(HassJob(target), *args) diff --git a/homeassistant/helpers/check_config.py b/homeassistant/helpers/check_config.py index 6e0415b2a54..3da444a8549 100644 --- a/homeassistant/helpers/check_config.py +++ b/homeassistant/helpers/check_config.py @@ -159,9 +159,7 @@ async def async_check_ha_config_file( # noqa: C901 ): try: result[domain] = ( - await config_validator.async_validate_config( # type: ignore - hass, config - ) + await config_validator.async_validate_config(hass, config) )[domain] continue except (vol.Invalid, HomeAssistantError) as ex: diff --git a/homeassistant/helpers/condition.py b/homeassistant/helpers/condition.py index 404eea5ea4a..45fb4bc6aa1 100644 --- a/homeassistant/helpers/condition.py +++ b/homeassistant/helpers/condition.py @@ -880,7 +880,7 @@ async def async_device_from_config( return trace_condition_function( cast( ConditionCheckerType, - platform.async_condition_from_config(hass, config), # type: ignore + platform.async_condition_from_config(hass, config), ) ) @@ -946,7 +946,7 @@ async def async_validate_condition_config( ) if hasattr(platform, "async_validate_condition_config"): return await platform.async_validate_condition_config(hass, config) # type: ignore - return cast(ConfigType, platform.CONDITION_SCHEMA(config)) # type: ignore + return cast(ConfigType, platform.CONDITION_SCHEMA(config)) if condition in ("numeric_state", "state"): validator = getattr( diff --git a/homeassistant/helpers/config_validation.py b/homeassistant/helpers/config_validation.py index ffd1f7586c0..06560de815d 100644 --- a/homeassistant/helpers/config_validation.py +++ b/homeassistant/helpers/config_validation.py @@ -16,7 +16,7 @@ from numbers import Number import os import re from socket import _GLOBAL_DEFAULT_TIMEOUT # type: ignore # private, not in typeshed -from typing import Any, Dict, TypeVar, cast +from typing import Any, Dict, TypeVar, cast, overload from urllib.parse import urlparse from uuid import UUID @@ -245,7 +245,17 @@ def isdir(value: Any) -> str: return dir_in -def ensure_list(value: T | list[T] | None) -> list[T]: +@overload +def ensure_list(value: None) -> list[Any]: + ... + + +@overload +def ensure_list(value: T | list[T]) -> list[T]: + ... + + +def ensure_list(value: T | list[T] | None) -> list[T] | list[Any]: """Wrap value in list if it is not one.""" if value is None: return [] diff --git a/homeassistant/helpers/reload.py b/homeassistant/helpers/reload.py index baa31bb41fc..a0388f53a93 100644 --- a/homeassistant/helpers/reload.py +++ b/homeassistant/helpers/reload.py @@ -79,8 +79,8 @@ async def _resetup_platform( if hasattr(component, "async_reset_platform"): # If the integration has its own way to reset # use this method. - await component.async_reset_platform(hass, integration_name) # type: ignore - await component.async_setup(hass, root_config) # type: ignore + await component.async_reset_platform(hass, integration_name) + await component.async_setup(hass, root_config) return # If it's an entity platform, we use the entity_platform diff --git a/homeassistant/helpers/script.py b/homeassistant/helpers/script.py index 77e4fd38508..925a5b9746f 100644 --- a/homeassistant/helpers/script.py +++ b/homeassistant/helpers/script.py @@ -248,9 +248,9 @@ async def async_validate_action_config( hass, config[CONF_DOMAIN], device_automation.DeviceAutomationType.ACTION ) if hasattr(platform, "async_validate_action_config"): - config = await platform.async_validate_action_config(hass, config) # type: ignore + config = await platform.async_validate_action_config(hass, config) else: - config = platform.ACTION_SCHEMA(config) # type: ignore + config = platform.ACTION_SCHEMA(config) elif action_type == cv.SCRIPT_ACTION_CHECK_CONDITION: config = await condition.async_validate_condition_config(hass, config) diff --git a/homeassistant/helpers/service.py b/homeassistant/helpers/service.py index 13ec3cb5df5..bbf605e6bff 100644 --- a/homeassistant/helpers/service.py +++ b/homeassistant/helpers/service.py @@ -8,6 +8,7 @@ from functools import partial, wraps import logging from typing import TYPE_CHECKING, Any, TypedDict +from typing_extensions import TypeGuard import voluptuous as vol from homeassistant.auth.permissions.const import CAT_ENTITIES, POLICY_CONTROL @@ -319,7 +320,7 @@ async def async_extract_entity_ids( return referenced.referenced | referenced.indirectly_referenced -def _has_match(ids: str | list | None) -> bool: +def _has_match(ids: str | list[str] | None) -> TypeGuard[str | list[str]]: """Check if ids can match anything.""" return ids not in (None, ENTITY_MATCH_NONE) @@ -706,7 +707,7 @@ async def _handle_entity_call( func, entity.entity_id, ) - await result # type: ignore + await result @bind_hass diff --git a/homeassistant/loader.py b/homeassistant/loader.py index 6fd66dab2fa..3fc9edfaf74 100644 --- a/homeassistant/loader.py +++ b/homeassistant/loader.py @@ -318,7 +318,7 @@ class Integration: cls, hass: HomeAssistant, root_module: ModuleType, domain: str ) -> Integration | None: """Resolve an integration from a root module.""" - for base in root_module.__path__: # type: ignore + for base in root_module.__path__: manifest_path = pathlib.Path(base) / domain / "manifest.json" if not manifest_path.is_file(): diff --git a/homeassistant/scripts/__init__.py b/homeassistant/scripts/__init__.py index 69ca1d6083b..5b781d4eb37 100644 --- a/homeassistant/scripts/__init__.py +++ b/homeassistant/scripts/__init__.py @@ -64,7 +64,7 @@ def run(args: list[str]) -> int: asyncio.set_event_loop_policy(runner.HassEventLoopPolicy(False)) - return script.run(args[1:]) # type: ignore + return script.run(args[1:]) def extract_config_dir(args: Sequence[str] | None = None) -> str: diff --git a/homeassistant/setup.py b/homeassistant/setup.py index 44dc6fe1014..b509419bcb5 100644 --- a/homeassistant/setup.py +++ b/homeassistant/setup.py @@ -7,6 +7,7 @@ import contextlib import logging.handlers from timeit import default_timer as timer from types import ModuleType +from typing import Any from . import config as conf_util, core, loader, requirements from .config import async_notify_setup_error @@ -210,15 +211,15 @@ async def _async_setup_component( ) task = None - result = True + result: Any | bool = True try: if hasattr(component, "async_setup"): - task = component.async_setup(hass, processed_config) # type: ignore + task = component.async_setup(hass, processed_config) elif hasattr(component, "setup"): # This should not be replaced with hass.async_add_executor_job because # we don't want to track this task in case it blocks startup. task = hass.loop.run_in_executor( - None, component.setup, hass, processed_config # type: ignore + None, component.setup, hass, processed_config ) elif not hasattr(component, "async_setup_entry"): log_error("No setup or config entry setup function defined.") diff --git a/homeassistant/util/color.py b/homeassistant/util/color.py index ccb4980492f..9c01c3040c2 100644 --- a/homeassistant/util/color.py +++ b/homeassistant/util/color.py @@ -3,7 +3,7 @@ from __future__ import annotations import colorsys import math -from typing import NamedTuple +from typing import NamedTuple, cast import attr @@ -299,7 +299,7 @@ def color_xy_brightness_to_RGB( r, g, b = map( lambda x: (12.92 * x) if (x <= 0.0031308) - else ((1.0 + 0.055) * pow(x, (1.0 / 2.4)) - 0.055), + else ((1.0 + 0.055) * cast(float, pow(x, (1.0 / 2.4))) - 0.055), [r, g, b], ) diff --git a/homeassistant/util/executor.py b/homeassistant/util/executor.py index 8451e71e0ec..5a8f15f434f 100644 --- a/homeassistant/util/executor.py +++ b/homeassistant/util/executor.py @@ -64,7 +64,7 @@ class InterruptibleThreadPoolExecutor(ThreadPoolExecutor): def shutdown(self, *args, **kwargs) -> None: # type: ignore """Shutdown backport from cpython 3.9 with interrupt support added.""" - with self._shutdown_lock: # type: ignore[attr-defined] + with self._shutdown_lock: self._shutdown = True # Drain all work items from the queue, and then cancel their # associated futures. @@ -77,7 +77,7 @@ class InterruptibleThreadPoolExecutor(ThreadPoolExecutor): work_item.future.cancel() # Send a wake-up to prevent threads calling # _work_queue.get(block=True) from permanently blocking. - self._work_queue.put(None) + self._work_queue.put(None) # type: ignore[arg-type] # The above code is backported from python 3.9 # @@ -89,7 +89,7 @@ class InterruptibleThreadPoolExecutor(ThreadPoolExecutor): def join_threads_or_timeout(self) -> None: """Join threads or timeout.""" - remaining_threads = set(self._threads) # type: ignore[attr-defined] + remaining_threads = set(self._threads) start_time = time.monotonic() timeout_remaining: float = EXECUTOR_SHUTDOWN_TIMEOUT attempt = 0 diff --git a/requirements_test.txt b/requirements_test.txt index 6f580cb5159..7beef3dd792 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -12,7 +12,7 @@ coverage==6.2.0 freezegun==1.1.0 jsonpickle==1.4.1 mock-open==1.4.0 -mypy==0.910 +mypy==0.930 pre-commit==2.16.0 pylint==2.12.1 pipdeptree==2.2.0