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
```
This commit is contained in:
J. Nick Koston 2022-07-19 11:50:30 -05:00 committed by GitHub
parent 5ae5ae5392
commit 32311f240b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -5,7 +5,6 @@ import asyncio
from collections import ChainMap from collections import ChainMap
from collections.abc import Callable, Coroutine, Iterable, Mapping from collections.abc import Callable, Coroutine, Iterable, Mapping
from contextvars import ContextVar from contextvars import ContextVar
import dataclasses
from enum import Enum from enum import Enum
import functools import functools
import logging import logging
@ -1446,13 +1445,19 @@ class ConfigFlow(data_entry_flow.FlowHandler):
if self._async_in_progress(include_uninitialized=True): if self._async_in_progress(include_uninitialized=True):
raise data_entry_flow.AbortFlow("already_in_progress") raise data_entry_flow.AbortFlow("already_in_progress")
async def async_step_discovery( async def _async_step_discovery_without_unique_id(
self, discovery_info: DiscoveryInfoType self,
) -> data_entry_flow.FlowResult: ) -> data_entry_flow.FlowResult:
"""Handle a flow initialized by discovery.""" """Handle a flow initialized by discovery."""
await self._async_handle_discovery_without_unique_id() await self._async_handle_discovery_without_unique_id()
return await self.async_step_user() 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 @callback
def async_abort( def async_abort(
self, self,
@ -1481,55 +1486,55 @@ class ConfigFlow(data_entry_flow.FlowHandler):
self, discovery_info: BluetoothServiceInfo self, discovery_info: BluetoothServiceInfo
) -> data_entry_flow.FlowResult: ) -> data_entry_flow.FlowResult:
"""Handle a flow initialized by Bluetooth discovery.""" """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( async def async_step_dhcp(
self, discovery_info: DhcpServiceInfo self, discovery_info: DhcpServiceInfo
) -> data_entry_flow.FlowResult: ) -> data_entry_flow.FlowResult:
"""Handle a flow initialized by DHCP discovery.""" """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( async def async_step_hassio(
self, discovery_info: HassioServiceInfo self, discovery_info: HassioServiceInfo
) -> data_entry_flow.FlowResult: ) -> data_entry_flow.FlowResult:
"""Handle a flow initialized by HASS IO discovery.""" """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( async def async_step_integration_discovery(
self, discovery_info: DiscoveryInfoType self, discovery_info: DiscoveryInfoType
) -> data_entry_flow.FlowResult: ) -> data_entry_flow.FlowResult:
"""Handle a flow initialized by integration specific discovery.""" """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( async def async_step_homekit(
self, discovery_info: ZeroconfServiceInfo self, discovery_info: ZeroconfServiceInfo
) -> data_entry_flow.FlowResult: ) -> data_entry_flow.FlowResult:
"""Handle a flow initialized by Homekit discovery.""" """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( async def async_step_mqtt(
self, discovery_info: MqttServiceInfo self, discovery_info: MqttServiceInfo
) -> data_entry_flow.FlowResult: ) -> data_entry_flow.FlowResult:
"""Handle a flow initialized by MQTT discovery.""" """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( async def async_step_ssdp(
self, discovery_info: SsdpServiceInfo self, discovery_info: SsdpServiceInfo
) -> data_entry_flow.FlowResult: ) -> data_entry_flow.FlowResult:
"""Handle a flow initialized by SSDP discovery.""" """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( async def async_step_usb(
self, discovery_info: UsbServiceInfo self, discovery_info: UsbServiceInfo
) -> data_entry_flow.FlowResult: ) -> data_entry_flow.FlowResult:
"""Handle a flow initialized by USB discovery.""" """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( async def async_step_zeroconf(
self, discovery_info: ZeroconfServiceInfo self, discovery_info: ZeroconfServiceInfo
) -> data_entry_flow.FlowResult: ) -> data_entry_flow.FlowResult:
"""Handle a flow initialized by Zeroconf discovery.""" """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 @callback
def async_create_entry( def async_create_entry(