diff --git a/custom_components/frigate/__init__.py b/custom_components/frigate/__init__.py index d73aad89..030702f8 100644 --- a/custom_components/frigate/__init__.py +++ b/custom_components/frigate/__init__.py @@ -272,7 +272,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: name=new_name, ) - hass.config_entries.async_setup_platforms(entry, PLATFORMS) + await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) entry.async_on_unload(entry.add_update_listener(_async_entry_updated)) return True diff --git a/custom_components/frigate/camera.py b/custom_components/frigate/camera.py index 10aea4e7..f8991250 100644 --- a/custom_components/frigate/camera.py +++ b/custom_components/frigate/camera.py @@ -209,7 +209,7 @@ async def async_camera_image( % ({"h": height} if height is not None and height > 0 else {}) ) - with async_timeout.timeout(10): + async with async_timeout.timeout(10): response = await websession.get(image_url) return await response.read() diff --git a/custom_components/frigate/media_source.py b/custom_components/frigate/media_source.py index 2151ec9b..365fed57 100644 --- a/custom_components/frigate/media_source.py +++ b/custom_components/frigate/media_source.py @@ -496,9 +496,9 @@ def get_integration_proxy_path(self) -> str: def get_changes_to_set_next_empty(self, data: str) -> dict[str, str]: """Get the changes that would set the next attribute in the hierarchy.""" - for attribute in self.__attrs_attrs__: # type: ignore[attr-defined] - if getattr(self, attribute.name) is None: - return {attribute.name: data} + for attribute in self.__attrs_attrs__: + if getattr(self, attribute.name) is None: # type: ignore[attr-defined] + return {attribute.name: data} # type: ignore[attr-defined] raise ValueError("No empty attribute available") @property diff --git a/custom_components/frigate/views.py b/custom_components/frigate/views.py index e1c5c321..60db1471 100644 --- a/custom_components/frigate/views.py +++ b/custom_components/frigate/views.py @@ -461,8 +461,8 @@ async def _handle_request( ) as ws_to_frigate: await asyncio.wait( [ - self._proxy_msgs(ws_to_frigate, ws_to_user), - self._proxy_msgs(ws_to_user, ws_to_frigate), + asyncio.create_task(self._proxy_msgs(ws_to_frigate, ws_to_user)), + asyncio.create_task(self._proxy_msgs(ws_to_user, ws_to_frigate)), ], return_when=asyncio.tasks.FIRST_COMPLETED, ) diff --git a/pyproject.toml b/pyproject.toml index 83d0639a..e19f1217 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -116,6 +116,7 @@ py-version = "3.8" runtime-typing = false [tool.pytest.ini_options] +asyncio_mode = "auto" testpaths = [ "tests", ] @@ -123,6 +124,16 @@ norecursedirs = [ ".git", "testing_config", ] +filterwarnings = [ + # Can be removed after there is a new pytest-cov release with + # https://github.com/pytest-dev/pytest-cov/issues/561 . + "ignore:.*hookimpl CovPlugin.*old-style configuration options.*:pytest.PytestDeprecationWarning", + + # Can be removed once we can update to pytest-asyncio==0.20.3 (which in + # turn requires a release of pytest-homeassistant-custom-component > + # 0.12.49) + "ignore:.*There is no current event loop.*:DeprecationWarning" +] addopts = "--timeout=10 --cov-report=xml:coverage.xml --cov-report=term-missing --cov=custom_components.frigate --cov-fail-under=100" [tool.mypy] @@ -146,4 +157,4 @@ warn_return_any = true warn_unreachable = true # Custom Frigate configuration. -show_error_codes = true \ No newline at end of file +show_error_codes = true diff --git a/requirements.txt b/requirements.txt index f9d82608..7f2a02cb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,8 @@ aiohttp -aiohttp_cors==0.7.0 +aiohttp_cors attr -homeassistant~=2022.7.0 -paho-mqtt==1.6.1 +janus +homeassistant==2023.1.7 +paho-mqtt python-dateutil yarl diff --git a/requirements_dev.txt b/requirements_dev.txt index 28780b10..cde9bfc6 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -1,11 +1,12 @@ -r requirements.txt black flake8 -mypy==0.910 +mypy pre-commit pytest -pytest-homeassistant-custom-component~=0.10.2 +pytest-homeassistant-custom-component==0.12.49 pylint-pytest -pylint==2.8.3 -pytest-aiohttp==0.3.0 +pylint +pytest-aiohttp +pytest-asyncio types-python-dateutil diff --git a/tests/__init__.py b/tests/__init__.py index c14775b5..947cc0c7 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -328,7 +328,7 @@ async def setup_mock_frigate_config_entry( return config_entry -async def test_entities_are_setup_correctly_in_registry( +async def verify_entities_are_setup_correctly_in_registry( hass: HomeAssistant, entities_enabled: set[str] | None = None, entities_disabled: set[str] | None = None, diff --git a/tests/test_api.py b/tests/test_api.py index f3feb242..9f99edcf 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -5,7 +5,7 @@ from collections.abc import AsyncGenerator import logging from typing import Any -from unittest.mock import Mock, patch +from unittest.mock import AsyncMock, patch import aiohttp from aiohttp import web @@ -44,7 +44,7 @@ async def test_async_get_stats( ) -> None: """Test async_get_config.""" stats_in = {"detection_fps": 8.1} - stats_handler = Mock(return_value=web.json_response(stats_in)) + stats_handler = AsyncMock(return_value=web.json_response(stats_in)) server = await start_frigate_server( aiohttp_server, [web.get("/api/stats", stats_handler)] @@ -148,7 +148,7 @@ async def test_async_get_config( ) -> None: """Test async_get_event_summary.""" config_in = {"cameras": {"front_door": {"camera_config": "goes here"}}} - config_handler = Mock(return_value=web.json_response(config_in)) + config_handler = AsyncMock(return_value=web.json_response(config_in)) server = await start_frigate_server( aiohttp_server, [web.get("/api/config", config_handler)] @@ -170,7 +170,7 @@ async def test_async_get_path( } ] - recordings_handler = Mock(return_value=web.json_response(recordings_in)) + recordings_handler = AsyncMock(return_value=web.json_response(recordings_in)) server = await start_frigate_server( aiohttp_server, [web.get("/recordings/moo/", recordings_handler)] @@ -185,10 +185,10 @@ async def test_api_wrapper_methods( ) -> None: """Test the general api_wrapper.""" - get_handler = Mock(return_value=web.json_response({"method": "GET"})) - put_handler = Mock(return_value=web.json_response({"method": "PUT"})) - patch_handler = Mock(return_value=web.json_response({"method": "PATCH"})) - post_handler = Mock(return_value=web.json_response({"method": "POST"})) + get_handler = AsyncMock(return_value=web.json_response({"method": "GET"})) + put_handler = AsyncMock(return_value=web.json_response({"method": "PUT"})) + patch_handler = AsyncMock(return_value=web.json_response({"method": "PATCH"})) + post_handler = AsyncMock(return_value=web.json_response({"method": "POST"})) server = await start_frigate_server( aiohttp_server, @@ -225,7 +225,7 @@ async def test_api_wrapper_exceptions( server = await start_frigate_server( aiohttp_server, [ - web.get("/get", Mock(return_value=web.json_response({}))), + web.get("/get", AsyncMock(return_value=web.json_response({}))), ], ) frigate_client = FrigateApiClient(str(server.make_url("/")), aiohttp_session) @@ -272,10 +272,10 @@ async def test_async_retain( """Test async_retain.""" post_success = {"success": True, "message": "Post success"} - post_handler = Mock(return_value=web.json_response(post_success)) + post_handler = AsyncMock(return_value=web.json_response(post_success)) delete_success = {"success": True, "message": "Delete success"} - delete_handler = Mock(return_value=web.json_response(delete_success)) + delete_handler = AsyncMock(return_value=web.json_response(delete_success)) event_id = "1656282822.206673-bovnfg" server = await start_frigate_server( @@ -301,7 +301,7 @@ async def test_async_get_recordings_summary( """Test async_recordings_summary.""" summary_success = {"summary": "goes_here"} - summary_handler = Mock(return_value=web.json_response(summary_success)) + summary_handler = AsyncMock(return_value=web.json_response(summary_success)) camera = "front_door" server = await start_frigate_server( diff --git a/tests/test_binary_sensor.py b/tests/test_binary_sensor.py index 03032c0c..79f39b8d 100644 --- a/tests/test_binary_sensor.py +++ b/tests/test_binary_sensor.py @@ -23,7 +23,7 @@ TEST_SERVER_VERSION, create_mock_frigate_client, setup_mock_frigate_config_entry, - test_entities_are_setup_correctly_in_registry, + verify_entities_are_setup_correctly_in_registry, ) _LOGGER = logging.getLogger(__name__) @@ -170,7 +170,7 @@ async def test_binary_sensors_setup_correctly_in_registry( await setup_mock_frigate_config_entry(hass) - await test_entities_are_setup_correctly_in_registry( + await verify_entities_are_setup_correctly_in_registry( hass, entities_enabled={ TEST_BINARY_SENSOR_FRONT_DOOR_MOTION_ENTITY_ID, diff --git a/tests/test_camera.py b/tests/test_camera.py index 2ca7970f..774c945a 100644 --- a/tests/test_camera.py +++ b/tests/test_camera.py @@ -37,7 +37,7 @@ create_mock_frigate_client, create_mock_frigate_config_entry, setup_mock_frigate_config_entry, - test_entities_are_setup_correctly_in_registry, + verify_entities_are_setup_correctly_in_registry, ) _LOGGER = logging.getLogger(__name__) @@ -298,7 +298,7 @@ async def test_cameras_setup_correctly_in_registry( """Verify entities are enabled/visible as appropriate.""" await setup_mock_frigate_config_entry(hass) - await test_entities_are_setup_correctly_in_registry( + await verify_entities_are_setup_correctly_in_registry( hass, entities_enabled={ TEST_CAMERA_FRONT_DOOR_ENTITY_ID, diff --git a/tests/test_number.py b/tests/test_number.py index 76a8b95f..31baf8d5 100644 --- a/tests/test_number.py +++ b/tests/test_number.py @@ -17,7 +17,7 @@ create_mock_frigate_client, enable_and_load_entity, setup_mock_frigate_config_entry, - test_entities_are_setup_correctly_in_registry, + verify_entities_are_setup_correctly_in_registry, ) _LOGGER = logging.getLogger(__name__) @@ -171,7 +171,7 @@ async def test_numbers_setup_correctly_in_registry( await setup_mock_frigate_config_entry(hass) - await test_entities_are_setup_correctly_in_registry( + await verify_entities_are_setup_correctly_in_registry( hass, entities_disabled=DISABLED_NUMBER_ENTITY_IDS, ) diff --git a/tests/test_sensor.py b/tests/test_sensor.py index 7e4f6ad5..8f4a5225 100644 --- a/tests/test_sensor.py +++ b/tests/test_sensor.py @@ -55,7 +55,7 @@ create_mock_frigate_client, enable_and_load_entity, setup_mock_frigate_config_entry, - test_entities_are_setup_correctly_in_registry, + verify_entities_are_setup_correctly_in_registry, ) _LOGGER = logging.getLogger(__name__) @@ -457,7 +457,7 @@ async def test_sensors_setup_correctly_in_registry( """Verify entities are enabled/visible as appropriate.""" await setup_mock_frigate_config_entry(hass) - await test_entities_are_setup_correctly_in_registry( + await verify_entities_are_setup_correctly_in_registry( hass, entities_enabled={ TEST_SENSOR_STEPS_ALL_ENTITY_ID, diff --git a/tests/test_switch.py b/tests/test_switch.py index 77b2582e..b173253c 100644 --- a/tests/test_switch.py +++ b/tests/test_switch.py @@ -23,7 +23,7 @@ create_mock_frigate_client, enable_and_load_entity, setup_mock_frigate_config_entry, - test_entities_are_setup_correctly_in_registry, + verify_entities_are_setup_correctly_in_registry, ) _LOGGER = logging.getLogger(__name__) @@ -193,7 +193,7 @@ async def test_switches_setup_correctly_in_registry( await setup_mock_frigate_config_entry(hass) - await test_entities_are_setup_correctly_in_registry( + await verify_entities_are_setup_correctly_in_registry( hass, entities_enabled=ENABLED_SWITCH_ENTITY_IDS, entities_disabled=DISABLED_SWITCH_ENTITY_IDS, diff --git a/tests/test_update.py b/tests/test_update.py index cffe884b..0908f3e5 100644 --- a/tests/test_update.py +++ b/tests/test_update.py @@ -23,7 +23,7 @@ TEST_UPDATE_FRIGATE_CONTAINER_ENTITY_ID, create_mock_frigate_client, setup_mock_frigate_config_entry, - test_entities_are_setup_correctly_in_registry, + verify_entities_are_setup_correctly_in_registry, ) _LOGGER = logging.getLogger(__name__) @@ -116,7 +116,7 @@ async def test_update_sensor_setup_correctly_in_registry( await setup_mock_frigate_config_entry(hass) - await test_entities_are_setup_correctly_in_registry( + await verify_entities_are_setup_correctly_in_registry( hass, entities_enabled={TEST_UPDATE_FRIGATE_CONTAINER_ENTITY_ID}, entities_visible={TEST_UPDATE_FRIGATE_CONTAINER_ENTITY_ID},