Import and create pyudev for usb in the executor (#113478)

pull/113552/head
J. Nick Koston 2024-03-15 09:05:18 -10:00 committed by GitHub
parent 29f07260f9
commit b7f7bed46c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 28 additions and 11 deletions

View File

@ -35,7 +35,7 @@ from .models import USBDevice
from .utils import usb_device_from_port
if TYPE_CHECKING:
from pyudev import Device
from pyudev import Device, MonitorObserver
_LOGGER = logging.getLogger(__name__)
@ -228,6 +228,25 @@ class USBDiscovery:
if info.get("docker"):
return
if not (
observer := await self.hass.async_add_executor_job(
self._get_monitor_observer
)
):
return
def _stop_observer(event: Event) -> None:
observer.stop()
self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, _stop_observer)
self.observer_active = True
def _get_monitor_observer(self) -> MonitorObserver | None:
"""Get the monitor observer.
This runs in the executor because the import
does blocking I/O.
"""
from pyudev import ( # pylint: disable=import-outside-toplevel
Context,
Monitor,
@ -237,7 +256,7 @@ class USBDiscovery:
try:
context = Context()
except (ImportError, OSError):
return
return None
monitor = Monitor.from_netlink(context)
try:
@ -246,17 +265,14 @@ class USBDiscovery:
_LOGGER.debug(
"Unable to setup pyudev filtering; This is expected on WSL: %s", ex
)
return
return None
observer = MonitorObserver(
monitor, callback=self._device_discovered, name="usb-observer"
)
observer.start()
def _stop_observer(event: Event) -> None:
observer.stop()
self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, _stop_observer)
self.observer_active = True
return observer
def _device_discovered(self, device: Device) -> None:
"""Call when the observer discovers a new usb tty device."""

View File

@ -590,6 +590,7 @@ async def test_supervisor_issues_initial_failure(
with patch("homeassistant.components.hassio.issues.REQUEST_REFRESH_DELAY", new=0.1):
result = await async_setup_component(hass, "hassio", {})
await hass.async_block_till_done()
assert result
client = await hass_ws_client(hass)

View File

@ -85,7 +85,7 @@ async def test_observer_discovery(
def _create_mock_monitor_observer(monitor, callback, name):
nonlocal mock_observer
hass.async_create_task(_mock_monitor_observer_callback(callback))
hass.create_task(_mock_monitor_observer_callback(callback))
mock_observer = MagicMock()
return mock_observer
@ -107,7 +107,7 @@ async def test_observer_discovery(
hass.bus.async_fire(EVENT_HOMEASSISTANT_STOP)
await hass.async_block_till_done()
assert mock_observer.mock_calls == [call.start(), call.stop()]
assert mock_observer.mock_calls == [call.start(), call.__bool__(), call.stop()]
@pytest.mark.skipif(