From 32311f240b20548d9c619f681833f54cb833557f Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 19 Jul 2022 11:50:30 -0500 Subject: [PATCH] Avoid converting discovery_info dataclasses to dict that will be thrown away in config flows (#75451) * Avoid converting BluetoothServiceInfo to a dict for default discovery Fixes ``` 2022-07-19 09:46:48.303 ERROR (MainThread) [homeassistant] Error doing job: Task exception was never retrieved Traceback (most recent call last): File "/Users/bdraco/home-assistant/homeassistant/helpers/discovery_flow.py", line 74, in _async_process_pending_flows await gather_with_concurrency( File "/Users/bdraco/home-assistant/homeassistant/util/async_.py", line 201, in gather_with_concurrency return await gather( File "/Users/bdraco/home-assistant/homeassistant/util/async_.py", line 199, in sem_task return await task File "/Users/bdraco/home-assistant/homeassistant/data_entry_flow.py", line 222, in async_init flow, result = await task File "/Users/bdraco/home-assistant/homeassistant/data_entry_flow.py", line 249, in _async_init result = await self._async_handle_step(flow, flow.init_step, data, init_done) File "/Users/bdraco/home-assistant/homeassistant/data_entry_flow.py", line 359, in _async_handle_step result: FlowResult = await getattr(flow, method)(user_input) File "/Users/bdraco/home-assistant/homeassistant/config_entries.py", line 1484, in async_step_bluetooth return await self.async_step_discovery(dataclasses.asdict(discovery_info)) File "/opt/homebrew/Cellar/python@3.10/3.10.5/Frameworks/Python.framework/Versions/3.10/lib/python3.10/dataclasses.py", line 1239, in asdict return _asdict_inner(obj, dict_factory) File "/opt/homebrew/Cellar/python@3.10/3.10.5/Frameworks/Python.framework/Versions/3.10/lib/python3.10/dataclasses.py", line 1246, in _asdict_inner value = _asdict_inner(getattr(obj, f.name), dict_factory) File "/opt/homebrew/Cellar/python@3.10/3.10.5/Frameworks/Python.framework/Versions/3.10/lib/python3.10/dataclasses.py", line 1280, in _asdict_inner return copy.deepcopy(obj) File "/opt/homebrew/Cellar/python@3.10/3.10.5/Frameworks/Python.framework/Versions/3.10/lib/python3.10/copy.py", line 172, in deepcopy y = _reconstruct(x, memo, *rv) File "/opt/homebrew/Cellar/python@3.10/3.10.5/Frameworks/Python.framework/Versions/3.10/lib/python3.10/copy.py", line 271, in _reconstruct state = deepcopy(state, memo) File "/opt/homebrew/Cellar/python@3.10/3.10.5/Frameworks/Python.framework/Versions/3.10/lib/python3.10/copy.py", line 146, in deepcopy y = copier(x, memo) File "/opt/homebrew/Cellar/python@3.10/3.10.5/Frameworks/Python.framework/Versions/3.10/lib/python3.10/copy.py", line 231, in _deepcopy_dict y[deepcopy(key, memo)] = deepcopy(value, memo) File "/opt/homebrew/Cellar/python@3.10/3.10.5/Frameworks/Python.framework/Versions/3.10/lib/python3.10/copy.py", line 161, in deepcopy rv = reductor(4) TypeError: Cannot pickle Objective-C objects ``` * Avoid converting BluetoothServiceInfo to a dict for default discovery Fixes ``` 2022-07-19 09:46:48.303 ERROR (MainThread) [homeassistant] Error doing job: Task exception was never retrieved Traceback (most recent call last): File "/Users/bdraco/home-assistant/homeassistant/helpers/discovery_flow.py", line 74, in _async_process_pending_flows await gather_with_concurrency( File "/Users/bdraco/home-assistant/homeassistant/util/async_.py", line 201, in gather_with_concurrency return await gather( File "/Users/bdraco/home-assistant/homeassistant/util/async_.py", line 199, in sem_task return await task File "/Users/bdraco/home-assistant/homeassistant/data_entry_flow.py", line 222, in async_init flow, result = await task File "/Users/bdraco/home-assistant/homeassistant/data_entry_flow.py", line 249, in _async_init result = await self._async_handle_step(flow, flow.init_step, data, init_done) File "/Users/bdraco/home-assistant/homeassistant/data_entry_flow.py", line 359, in _async_handle_step result: FlowResult = await getattr(flow, method)(user_input) File "/Users/bdraco/home-assistant/homeassistant/config_entries.py", line 1484, in async_step_bluetooth return await self.async_step_discovery(dataclasses.asdict(discovery_info)) File "/opt/homebrew/Cellar/python@3.10/3.10.5/Frameworks/Python.framework/Versions/3.10/lib/python3.10/dataclasses.py", line 1239, in asdict return _asdict_inner(obj, dict_factory) File "/opt/homebrew/Cellar/python@3.10/3.10.5/Frameworks/Python.framework/Versions/3.10/lib/python3.10/dataclasses.py", line 1246, in _asdict_inner value = _asdict_inner(getattr(obj, f.name), dict_factory) File "/opt/homebrew/Cellar/python@3.10/3.10.5/Frameworks/Python.framework/Versions/3.10/lib/python3.10/dataclasses.py", line 1280, in _asdict_inner return copy.deepcopy(obj) File "/opt/homebrew/Cellar/python@3.10/3.10.5/Frameworks/Python.framework/Versions/3.10/lib/python3.10/copy.py", line 172, in deepcopy y = _reconstruct(x, memo, *rv) File "/opt/homebrew/Cellar/python@3.10/3.10.5/Frameworks/Python.framework/Versions/3.10/lib/python3.10/copy.py", line 271, in _reconstruct state = deepcopy(state, memo) File "/opt/homebrew/Cellar/python@3.10/3.10.5/Frameworks/Python.framework/Versions/3.10/lib/python3.10/copy.py", line 146, in deepcopy y = copier(x, memo) File "/opt/homebrew/Cellar/python@3.10/3.10.5/Frameworks/Python.framework/Versions/3.10/lib/python3.10/copy.py", line 231, in _deepcopy_dict y[deepcopy(key, memo)] = deepcopy(value, memo) File "/opt/homebrew/Cellar/python@3.10/3.10.5/Frameworks/Python.framework/Versions/3.10/lib/python3.10/copy.py", line 161, in deepcopy rv = reductor(4) TypeError: Cannot pickle Objective-C objects ``` --- homeassistant/config_entries.py | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/homeassistant/config_entries.py b/homeassistant/config_entries.py index e5a36b980ed..232d3e5cbf1 100644 --- a/homeassistant/config_entries.py +++ b/homeassistant/config_entries.py @@ -5,7 +5,6 @@ import asyncio from collections import ChainMap from collections.abc import Callable, Coroutine, Iterable, Mapping from contextvars import ContextVar -import dataclasses from enum import Enum import functools import logging @@ -1446,13 +1445,19 @@ class ConfigFlow(data_entry_flow.FlowHandler): if self._async_in_progress(include_uninitialized=True): raise data_entry_flow.AbortFlow("already_in_progress") - async def async_step_discovery( - self, discovery_info: DiscoveryInfoType + async def _async_step_discovery_without_unique_id( + self, ) -> data_entry_flow.FlowResult: """Handle a flow initialized by discovery.""" await self._async_handle_discovery_without_unique_id() return await self.async_step_user() + async def async_step_discovery( + self, discovery_info: DiscoveryInfoType + ) -> data_entry_flow.FlowResult: + """Handle a flow initialized by discovery.""" + return await self._async_step_discovery_without_unique_id() + @callback def async_abort( self, @@ -1481,55 +1486,55 @@ class ConfigFlow(data_entry_flow.FlowHandler): self, discovery_info: BluetoothServiceInfo ) -> data_entry_flow.FlowResult: """Handle a flow initialized by Bluetooth discovery.""" - return await self.async_step_discovery(dataclasses.asdict(discovery_info)) + return await self._async_step_discovery_without_unique_id() async def async_step_dhcp( self, discovery_info: DhcpServiceInfo ) -> data_entry_flow.FlowResult: """Handle a flow initialized by DHCP discovery.""" - return await self.async_step_discovery(dataclasses.asdict(discovery_info)) + return await self._async_step_discovery_without_unique_id() async def async_step_hassio( self, discovery_info: HassioServiceInfo ) -> data_entry_flow.FlowResult: """Handle a flow initialized by HASS IO discovery.""" - return await self.async_step_discovery(discovery_info.config) + return await self._async_step_discovery_without_unique_id() async def async_step_integration_discovery( self, discovery_info: DiscoveryInfoType ) -> data_entry_flow.FlowResult: """Handle a flow initialized by integration specific discovery.""" - return await self.async_step_discovery(discovery_info) + return await self._async_step_discovery_without_unique_id() async def async_step_homekit( self, discovery_info: ZeroconfServiceInfo ) -> data_entry_flow.FlowResult: """Handle a flow initialized by Homekit discovery.""" - return await self.async_step_discovery(dataclasses.asdict(discovery_info)) + return await self._async_step_discovery_without_unique_id() async def async_step_mqtt( self, discovery_info: MqttServiceInfo ) -> data_entry_flow.FlowResult: """Handle a flow initialized by MQTT discovery.""" - return await self.async_step_discovery(dataclasses.asdict(discovery_info)) + return await self._async_step_discovery_without_unique_id() async def async_step_ssdp( self, discovery_info: SsdpServiceInfo ) -> data_entry_flow.FlowResult: """Handle a flow initialized by SSDP discovery.""" - return await self.async_step_discovery(dataclasses.asdict(discovery_info)) + return await self._async_step_discovery_without_unique_id() async def async_step_usb( self, discovery_info: UsbServiceInfo ) -> data_entry_flow.FlowResult: """Handle a flow initialized by USB discovery.""" - return await self.async_step_discovery(dataclasses.asdict(discovery_info)) + return await self._async_step_discovery_without_unique_id() async def async_step_zeroconf( self, discovery_info: ZeroconfServiceInfo ) -> data_entry_flow.FlowResult: """Handle a flow initialized by Zeroconf discovery.""" - return await self.async_step_discovery(dataclasses.asdict(discovery_info)) + return await self._async_step_discovery_without_unique_id() @callback def async_create_entry(