diff --git a/homeassistant/components/dlna_dmr/media_player.py b/homeassistant/components/dlna_dmr/media_player.py index 101b59c7125..807a983983b 100644 --- a/homeassistant/components/dlna_dmr/media_player.py +++ b/homeassistant/components/dlna_dmr/media_player.py @@ -67,8 +67,8 @@ _P = ParamSpec("_P") def catch_request_errors( - func: Callable[Concatenate[_T, _P], Awaitable[_R]] # type: ignore[misc] -) -> Callable[Concatenate[_T, _P], Coroutine[Any, Any, _R | None]]: # type: ignore[misc] + func: Callable[Concatenate[_T, _P], Awaitable[_R]] +) -> Callable[Concatenate[_T, _P], Coroutine[Any, Any, _R | None]]: """Catch UpnpError errors.""" @functools.wraps(func) @@ -80,7 +80,7 @@ def catch_request_errors( ) return None try: - return await func(self, *args, **kwargs) # type: ignore[no-any-return] # mypy can't yet infer 'func' + return await func(self, *args, **kwargs) except UpnpError as err: self.check_available = True _LOGGER.error("Error during call %s: %r", func.__name__, err) diff --git a/homeassistant/components/evil_genius_labs/util.py b/homeassistant/components/evil_genius_labs/util.py index 40ba375a2b4..7cbcc821bfe 100644 --- a/homeassistant/components/evil_genius_labs/util.py +++ b/homeassistant/components/evil_genius_labs/util.py @@ -15,8 +15,8 @@ _P = ParamSpec("_P") def update_when_done( - func: Callable[Concatenate[_T, _P], Awaitable[_R]] # type: ignore[misc] -) -> Callable[Concatenate[_T, _P], Coroutine[Any, Any, _R]]: # type: ignore[misc] + func: Callable[Concatenate[_T, _P], Awaitable[_R]] +) -> Callable[Concatenate[_T, _P], Coroutine[Any, Any, _R]]: """Decorate function to trigger update when function is done.""" @wraps(func) @@ -24,6 +24,6 @@ def update_when_done( """Wrap function.""" result = await func(self, *args, **kwargs) await self.coordinator.async_request_refresh() - return result # type: ignore[no-any-return] # mypy can't yet infer 'func' + return result return wrapper diff --git a/homeassistant/components/http/auth.py b/homeassistant/components/http/auth.py index 117d1b2d92e..4788680a6fa 100644 --- a/homeassistant/components/http/auth.py +++ b/homeassistant/components/http/auth.py @@ -96,7 +96,7 @@ def async_user_not_allowed_do_auth( return "User is local only" try: - remote = ip_address(request.remote) + remote = ip_address(request.remote) # type: ignore[arg-type] except ValueError: return "Invalid remote IP" diff --git a/homeassistant/components/http/ban.py b/homeassistant/components/http/ban.py index 292c46e55f9..620bdc7613c 100644 --- a/homeassistant/components/http/ban.py +++ b/homeassistant/components/http/ban.py @@ -67,7 +67,7 @@ async def ban_middleware( return await handler(request) # Verify if IP is not banned - ip_address_ = ip_address(request.remote) + ip_address_ = ip_address(request.remote) # type: ignore[arg-type] is_banned = any( ip_ban.ip_address == ip_address_ for ip_ban in request.app[KEY_BANNED_IPS] ) @@ -107,7 +107,7 @@ async def process_wrong_login(request: Request) -> None: """ hass = request.app["hass"] - remote_addr = ip_address(request.remote) + remote_addr = ip_address(request.remote) # type: ignore[arg-type] remote_host = request.remote with suppress(herror): remote_host, _, _ = await hass.async_add_executor_job( @@ -170,7 +170,7 @@ async def process_success_login(request: Request) -> None: No release IP address from banned list function, it can only be done by manual modify ip bans config file. """ - remote_addr = ip_address(request.remote) + remote_addr = ip_address(request.remote) # type: ignore[arg-type] # Check if ban middleware is loaded if KEY_BANNED_IPS not in request.app or request.app[KEY_LOGIN_THRESHOLD] < 1: diff --git a/homeassistant/components/plugwise/util.py b/homeassistant/components/plugwise/util.py index 58c7715815e..769bfc4ecea 100644 --- a/homeassistant/components/plugwise/util.py +++ b/homeassistant/components/plugwise/util.py @@ -15,8 +15,8 @@ _T = TypeVar("_T", bound=PlugwiseEntity) def plugwise_command( - func: Callable[Concatenate[_T, _P], Awaitable[_R]] # type: ignore[misc] -) -> Callable[Concatenate[_T, _P], Coroutine[Any, Any, _R]]: # type: ignore[misc] + func: Callable[Concatenate[_T, _P], Awaitable[_R]] +) -> Callable[Concatenate[_T, _P], Coroutine[Any, Any, _R]]: """Decorate Plugwise calls that send commands/make changes to the device. A decorator that wraps the passed in function, catches Plugwise errors, diff --git a/homeassistant/components/roku/helpers.py b/homeassistant/components/roku/helpers.py index 26fdb53c935..d7e28066f90 100644 --- a/homeassistant/components/roku/helpers.py +++ b/homeassistant/components/roku/helpers.py @@ -29,8 +29,8 @@ def roku_exception_handler(ignore_timeout: bool = False) -> Callable[..., Callab """Decorate Roku calls to handle Roku exceptions.""" def decorator( - func: Callable[Concatenate[_T, _P], Awaitable[None]], # type: ignore[misc] - ) -> Callable[Concatenate[_T, _P], Coroutine[Any, Any, None]]: # type: ignore[misc] + func: Callable[Concatenate[_T, _P], Awaitable[None]], + ) -> Callable[Concatenate[_T, _P], Coroutine[Any, Any, None]]: @wraps(func) async def wrapper(self: _T, *args: _P.args, **kwargs: _P.kwargs) -> None: try: diff --git a/homeassistant/components/sentry/__init__.py b/homeassistant/components/sentry/__init__.py index 7ea26c04810..c02b16fcfb0 100644 --- a/homeassistant/components/sentry/__init__.py +++ b/homeassistant/components/sentry/__init__.py @@ -79,7 +79,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: ), } - sentry_sdk.init( # pylint: disable=abstract-class-instantiated + # pylint: disable-next=abstract-class-instantiated + sentry_sdk.init( # type: ignore[abstract] dsn=entry.data[CONF_DSN], environment=entry.options.get(CONF_ENVIRONMENT), integrations=[sentry_logging, AioHttpIntegration(), SqlalchemyIntegration()], diff --git a/homeassistant/components/sonarr/sensor.py b/homeassistant/components/sonarr/sensor.py index c182bb2bbeb..1604f500ab9 100644 --- a/homeassistant/components/sonarr/sensor.py +++ b/homeassistant/components/sonarr/sensor.py @@ -109,8 +109,8 @@ async def async_setup_entry( def sonarr_exception_handler( - func: Callable[Concatenate[_T, _P], Awaitable[None]] # type: ignore[misc] -) -> Callable[Concatenate[_T, _P], Coroutine[Any, Any, None]]: # type: ignore[misc] + func: Callable[Concatenate[_T, _P], Awaitable[None]] +) -> Callable[Concatenate[_T, _P], Coroutine[Any, Any, None]]: """Decorate Sonarr calls to handle Sonarr exceptions. A decorator that wraps the passed in function, catches Sonarr errors, diff --git a/homeassistant/components/sonos/helpers.py b/homeassistant/components/sonos/helpers.py index 3edf23f0c3c..22d9f6c08a5 100644 --- a/homeassistant/components/sonos/helpers.py +++ b/homeassistant/components/sonos/helpers.py @@ -35,16 +35,14 @@ _P = ParamSpec("_P") @overload def soco_error( errorcodes: None = ..., -) -> Callable[ # type: ignore[misc] - [Callable[Concatenate[_T, _P], _R]], Callable[Concatenate[_T, _P], _R] -]: +) -> Callable[[Callable[Concatenate[_T, _P], _R]], Callable[Concatenate[_T, _P], _R]]: ... @overload def soco_error( errorcodes: list[str], -) -> Callable[ # type: ignore[misc] +) -> Callable[ [Callable[Concatenate[_T, _P], _R]], Callable[Concatenate[_T, _P], _R | None] ]: ... @@ -52,14 +50,14 @@ def soco_error( def soco_error( errorcodes: list[str] | None = None, -) -> Callable[ # type: ignore[misc] +) -> Callable[ [Callable[Concatenate[_T, _P], _R]], Callable[Concatenate[_T, _P], _R | None] ]: """Filter out specified UPnP errors and raise exceptions for service calls.""" def decorator( - funct: Callable[Concatenate[_T, _P], _R] # type: ignore[misc] - ) -> Callable[Concatenate[_T, _P], _R | None]: # type: ignore[misc] + funct: Callable[Concatenate[_T, _P], _R] + ) -> Callable[Concatenate[_T, _P], _R | None]: """Decorate functions.""" def wrapper(self: _T, *args: _P.args, **kwargs: _P.kwargs) -> _R | None: diff --git a/homeassistant/components/sonos/media.py b/homeassistant/components/sonos/media.py index 1b4dbd00d59..e661a8320dc 100644 --- a/homeassistant/components/sonos/media.py +++ b/homeassistant/components/sonos/media.py @@ -135,7 +135,7 @@ class SonosMedia: self.title = track_info.get("title") self.image_url = track_info.get("album_art") - playlist_position = int(track_info.get("playlist_position")) + playlist_position = int(track_info.get("playlist_position", -1)) if playlist_position > 0: self.queue_position = playlist_position diff --git a/homeassistant/components/tplink/entity.py b/homeassistant/components/tplink/entity.py index 173d1d7930f..471d32631c4 100644 --- a/homeassistant/components/tplink/entity.py +++ b/homeassistant/components/tplink/entity.py @@ -19,8 +19,8 @@ _P = ParamSpec("_P") def async_refresh_after( - func: Callable[Concatenate[_T, _P], Awaitable[None]] # type: ignore[misc] -) -> Callable[Concatenate[_T, _P], Coroutine[Any, Any, None]]: # type: ignore[misc] + func: Callable[Concatenate[_T, _P], Awaitable[None]] +) -> Callable[Concatenate[_T, _P], Coroutine[Any, Any, None]]: """Define a wrapper to refresh after.""" async def _async_wrap(self: _T, *args: _P.args, **kwargs: _P.kwargs) -> None: diff --git a/homeassistant/components/vlc_telnet/media_player.py b/homeassistant/components/vlc_telnet/media_player.py index 9d4e0a5a7a8..c7009c6c14d 100644 --- a/homeassistant/components/vlc_telnet/media_player.py +++ b/homeassistant/components/vlc_telnet/media_player.py @@ -48,8 +48,8 @@ async def async_setup_entry( def catch_vlc_errors( - func: Callable[Concatenate[_T, _P], Awaitable[None]] # type: ignore[misc] -) -> Callable[Concatenate[_T, _P], Coroutine[Any, Any, None]]: # type: ignore[misc] + func: Callable[Concatenate[_T, _P], Awaitable[None]] +) -> Callable[Concatenate[_T, _P], Coroutine[Any, Any, None]]: """Catch VLC errors.""" @wraps(func) diff --git a/homeassistant/components/webhook/__init__.py b/homeassistant/components/webhook/__init__.py index 798f863b8ee..fb9927f1b37 100644 --- a/homeassistant/components/webhook/__init__.py +++ b/homeassistant/components/webhook/__init__.py @@ -108,7 +108,7 @@ async def async_handle_webhook( if webhook["local_only"]: try: - remote = ip_address(request.remote) + remote = ip_address(request.remote) # type: ignore[arg-type] except ValueError: _LOGGER.debug("Unable to parse remote ip %s", request.remote) return Response(status=HTTPStatus.OK) diff --git a/homeassistant/components/webostv/media_player.py b/homeassistant/components/webostv/media_player.py index 49f9a29052b..3806ee6c2bb 100644 --- a/homeassistant/components/webostv/media_player.py +++ b/homeassistant/components/webostv/media_player.py @@ -87,8 +87,8 @@ _P = ParamSpec("_P") def cmd( - func: Callable[Concatenate[_T, _P], Awaitable[None]] # type: ignore[misc] -) -> Callable[Concatenate[_T, _P], Coroutine[Any, Any, None]]: # type: ignore[misc] + func: Callable[Concatenate[_T, _P], Awaitable[None]] +) -> Callable[Concatenate[_T, _P], Coroutine[Any, Any, None]]: """Catch command exceptions.""" @wraps(func) diff --git a/homeassistant/components/zabbix/__init__.py b/homeassistant/components/zabbix/__init__.py index 21c3edd56bf..3fc38af4cf1 100644 --- a/homeassistant/components/zabbix/__init__.py +++ b/homeassistant/components/zabbix/__init__.py @@ -90,7 +90,11 @@ def setup(hass: HomeAssistant, config: ConfigType) -> bool: _LOGGER.error("HTTPError when connecting to Zabbix API: %s", http_error) zapi = None _LOGGER.error(RETRY_MESSAGE, http_error) - event_helper.call_later(hass, RETRY_INTERVAL, lambda _: setup(hass, config)) + event_helper.call_later( + hass, + RETRY_INTERVAL, + lambda _: setup(hass, config), # type: ignore[arg-type,return-value] + ) return True hass.data[DOMAIN] = zapi diff --git a/homeassistant/helpers/event.py b/homeassistant/helpers/event.py index 427297b2f1d..686fde89fbb 100644 --- a/homeassistant/helpers/event.py +++ b/homeassistant/helpers/event.py @@ -111,8 +111,8 @@ class TrackTemplateResult: def threaded_listener_factory( - async_factory: Callable[Concatenate[HomeAssistant, _P], Any] # type: ignore[misc] -) -> Callable[Concatenate[HomeAssistant, _P], CALLBACK_TYPE]: # type: ignore[misc] + async_factory: Callable[Concatenate[HomeAssistant, _P], Any] +) -> Callable[Concatenate[HomeAssistant, _P], CALLBACK_TYPE]: """Convert an async event helper to a threaded one.""" @ft.wraps(async_factory) diff --git a/homeassistant/helpers/integration_platform.py b/homeassistant/helpers/integration_platform.py index 21d15e4fc73..9255824cddf 100644 --- a/homeassistant/helpers/integration_platform.py +++ b/homeassistant/helpers/integration_platform.py @@ -48,7 +48,7 @@ async def _async_process_single_integration_platform_component( return try: - await integration_platform.process_platform(hass, component_name, platform) # type: ignore[misc,operator] # https://github.com/python/mypy/issues/5485 + await integration_platform.process_platform(hass, component_name, platform) except Exception: # pylint: disable=broad-except _LOGGER.exception( "Error processing platform %s.%s", component_name, platform_name diff --git a/homeassistant/runner.py b/homeassistant/runner.py index 472d399713d..5788a6b155a 100644 --- a/homeassistant/runner.py +++ b/homeassistant/runner.py @@ -48,7 +48,7 @@ class RuntimeConfig: open_ui: bool = False -class HassEventLoopPolicy(asyncio.DefaultEventLoopPolicy): # type: ignore[valid-type,misc] +class HassEventLoopPolicy(asyncio.DefaultEventLoopPolicy): """Event loop policy for Home Assistant.""" def __init__(self, debug: bool) -> None: @@ -59,7 +59,7 @@ class HassEventLoopPolicy(asyncio.DefaultEventLoopPolicy): # type: ignore[valid @property def loop_name(self) -> str: """Return name of the loop.""" - return self._loop_factory.__name__ # type: ignore[no-any-return] + return self._loop_factory.__name__ # type: ignore[no-any-return,attr-defined] def new_event_loop(self) -> asyncio.AbstractEventLoop: """Get the event loop.""" diff --git a/mypy.ini b/mypy.ini index 96228c5c93e..5df02c46252 100644 --- a/mypy.ini +++ b/mypy.ini @@ -13,6 +13,7 @@ warn_redundant_casts = true warn_unused_configs = true warn_unused_ignores = true enable_error_code = ignore-without-code +strict_concatenate = false check_untyped_defs = true disallow_incomplete_defs = true disallow_subclassing_any = true diff --git a/requirements_test.txt b/requirements_test.txt index 31a87356fcc..744ca7bebcf 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -11,7 +11,7 @@ codecov==2.1.12 coverage==6.3.2 freezegun==1.2.1 mock-open==1.4.0 -mypy==0.942 +mypy==0.950 pre-commit==2.17.0 pylint==2.13.7 pipdeptree==2.2.1 diff --git a/script/hassfest/mypy_config.py b/script/hassfest/mypy_config.py index cf3ef92fbdb..d21dc0faf7d 100644 --- a/script/hassfest/mypy_config.py +++ b/script/hassfest/mypy_config.py @@ -221,6 +221,8 @@ GENERAL_SETTINGS: Final[dict[str, str]] = { "warn_unused_configs": "true", "warn_unused_ignores": "true", "enable_error_code": "ignore-without-code", + # Strict_concatenate breaks passthrough ParamSpec typing + "strict_concatenate": "false", } # This is basically the list of checks which is enabled for "strict=true".