Improve type hints in conversation tests (#120306)

This commit is contained in:
epenet 2024-06-24 13:41:55 +02:00 committed by GitHub
parent aef2f7d707
commit b4d0de9c0f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -1,6 +1,7 @@
"""Test for the default agent.""" """Test for the default agent."""
from collections import defaultdict from collections import defaultdict
from typing import Any
from unittest.mock import AsyncMock, patch from unittest.mock import AsyncMock, patch
from hassil.recognize import Intent, IntentData, MatchEntity, RecognizeResult from hassil.recognize import Intent, IntentData, MatchEntity, RecognizeResult
@ -34,7 +35,7 @@ from tests.common import MockConfigEntry, async_mock_service
@pytest.fixture @pytest.fixture
async def init_components(hass): async def init_components(hass: HomeAssistant) -> None:
"""Initialize relevant components with empty configs.""" """Initialize relevant components with empty configs."""
assert await async_setup_component(hass, "homeassistant", {}) assert await async_setup_component(hass, "homeassistant", {})
assert await async_setup_component(hass, "conversation", {}) assert await async_setup_component(hass, "conversation", {})
@ -50,8 +51,9 @@ async def init_components(hass):
{"entity_category": entity.EntityCategory.DIAGNOSTIC}, {"entity_category": entity.EntityCategory.DIAGNOSTIC},
], ],
) )
@pytest.mark.usefixtures("init_components")
async def test_hidden_entities_skipped( async def test_hidden_entities_skipped(
hass: HomeAssistant, init_components, er_kwargs, entity_registry: er.EntityRegistry hass: HomeAssistant, er_kwargs: dict[str, Any], entity_registry: er.EntityRegistry
) -> None: ) -> None:
"""Test we skip hidden entities.""" """Test we skip hidden entities."""
@ -69,7 +71,8 @@ async def test_hidden_entities_skipped(
assert result.response.error_code == intent.IntentResponseErrorCode.NO_VALID_TARGETS assert result.response.error_code == intent.IntentResponseErrorCode.NO_VALID_TARGETS
async def test_exposed_domains(hass: HomeAssistant, init_components) -> None: @pytest.mark.usefixtures("init_components")
async def test_exposed_domains(hass: HomeAssistant) -> None:
"""Test that we can't interact with entities that aren't exposed.""" """Test that we can't interact with entities that aren't exposed."""
hass.states.async_set( hass.states.async_set(
"lock.front_door", "off", attributes={ATTR_FRIENDLY_NAME: "Front Door"} "lock.front_door", "off", attributes={ATTR_FRIENDLY_NAME: "Front Door"}
@ -93,9 +96,9 @@ async def test_exposed_domains(hass: HomeAssistant, init_components) -> None:
assert result.response.error_code == intent.IntentResponseErrorCode.NO_VALID_TARGETS assert result.response.error_code == intent.IntentResponseErrorCode.NO_VALID_TARGETS
@pytest.mark.usefixtures("init_components")
async def test_exposed_areas( async def test_exposed_areas(
hass: HomeAssistant, hass: HomeAssistant,
init_components,
area_registry: ar.AreaRegistry, area_registry: ar.AreaRegistry,
device_registry: dr.DeviceRegistry, device_registry: dr.DeviceRegistry,
entity_registry: er.EntityRegistry, entity_registry: er.EntityRegistry,
@ -160,10 +163,8 @@ async def test_exposed_areas(
assert result.response.response_type == intent.IntentResponseType.QUERY_ANSWER assert result.response.response_type == intent.IntentResponseType.QUERY_ANSWER
async def test_conversation_agent( @pytest.mark.usefixtures("init_components")
hass: HomeAssistant, async def test_conversation_agent(hass: HomeAssistant) -> None:
init_components,
) -> None:
"""Test DefaultAgent.""" """Test DefaultAgent."""
agent = default_agent.async_get_default_agent(hass) agent = default_agent.async_get_default_agent(hass)
with patch( with patch(
@ -209,9 +210,9 @@ async def test_expose_flag_automatically_set(
} }
@pytest.mark.usefixtures("init_components")
async def test_unexposed_entities_skipped( async def test_unexposed_entities_skipped(
hass: HomeAssistant, hass: HomeAssistant,
init_components,
area_registry: ar.AreaRegistry, area_registry: ar.AreaRegistry,
entity_registry: er.EntityRegistry, entity_registry: er.EntityRegistry,
) -> None: ) -> None:
@ -262,7 +263,8 @@ async def test_unexposed_entities_skipped(
assert result.response.matched_states[0].entity_id == exposed_light.entity_id assert result.response.matched_states[0].entity_id == exposed_light.entity_id
async def test_trigger_sentences(hass: HomeAssistant, init_components) -> None: @pytest.mark.usefixtures("init_components")
async def test_trigger_sentences(hass: HomeAssistant) -> None:
"""Test registering/unregistering/matching a few trigger sentences.""" """Test registering/unregistering/matching a few trigger sentences."""
trigger_sentences = ["It's party time", "It is time to party"] trigger_sentences = ["It's party time", "It is time to party"]
trigger_response = "Cowabunga!" trigger_response = "Cowabunga!"
@ -303,9 +305,8 @@ async def test_trigger_sentences(hass: HomeAssistant, init_components) -> None:
assert len(callback.mock_calls) == 0 assert len(callback.mock_calls) == 0
async def test_shopping_list_add_item( @pytest.mark.usefixtures("init_components", "sl_setup")
hass: HomeAssistant, init_components, sl_setup async def test_shopping_list_add_item(hass: HomeAssistant) -> None:
) -> None:
"""Test adding an item to the shopping list through the default agent.""" """Test adding an item to the shopping list through the default agent."""
result = await conversation.async_converse( result = await conversation.async_converse(
hass, "add apples to my shopping list", None, Context() hass, "add apples to my shopping list", None, Context()
@ -316,7 +317,8 @@ async def test_shopping_list_add_item(
} }
async def test_nevermind_item(hass: HomeAssistant, init_components) -> None: @pytest.mark.usefixtures("init_components")
async def test_nevermind_item(hass: HomeAssistant) -> None:
"""Test HassNevermind intent through the default agent.""" """Test HassNevermind intent through the default agent."""
result = await conversation.async_converse(hass, "nevermind", None, Context()) result = await conversation.async_converse(hass, "nevermind", None, Context())
assert result.response.intent is not None assert result.response.intent is not None
@ -326,9 +328,9 @@ async def test_nevermind_item(hass: HomeAssistant, init_components) -> None:
assert not result.response.speech assert not result.response.speech
@pytest.mark.usefixtures("init_components")
async def test_device_area_context( async def test_device_area_context(
hass: HomeAssistant, hass: HomeAssistant,
init_components,
area_registry: ar.AreaRegistry, area_registry: ar.AreaRegistry,
device_registry: dr.DeviceRegistry, device_registry: dr.DeviceRegistry,
entity_registry: er.EntityRegistry, entity_registry: er.EntityRegistry,
@ -465,7 +467,8 @@ async def test_device_area_context(
} }
async def test_error_no_device(hass: HomeAssistant, init_components) -> None: @pytest.mark.usefixtures("init_components")
async def test_error_no_device(hass: HomeAssistant) -> None:
"""Test error message when device/entity is missing.""" """Test error message when device/entity is missing."""
result = await conversation.async_converse( result = await conversation.async_converse(
hass, "turn on missing entity", None, Context(), None hass, "turn on missing entity", None, Context(), None
@ -479,7 +482,8 @@ async def test_error_no_device(hass: HomeAssistant, init_components) -> None:
) )
async def test_error_no_area(hass: HomeAssistant, init_components) -> None: @pytest.mark.usefixtures("init_components")
async def test_error_no_area(hass: HomeAssistant) -> None:
"""Test error message when area is missing.""" """Test error message when area is missing."""
result = await conversation.async_converse( result = await conversation.async_converse(
hass, "turn on the lights in missing area", None, Context(), None hass, "turn on the lights in missing area", None, Context(), None
@ -493,7 +497,8 @@ async def test_error_no_area(hass: HomeAssistant, init_components) -> None:
) )
async def test_error_no_floor(hass: HomeAssistant, init_components) -> None: @pytest.mark.usefixtures("init_components")
async def test_error_no_floor(hass: HomeAssistant) -> None:
"""Test error message when floor is missing.""" """Test error message when floor is missing."""
result = await conversation.async_converse( result = await conversation.async_converse(
hass, "turn on all the lights on missing floor", None, Context(), None hass, "turn on all the lights on missing floor", None, Context(), None
@ -507,8 +512,9 @@ async def test_error_no_floor(hass: HomeAssistant, init_components) -> None:
) )
@pytest.mark.usefixtures("init_components")
async def test_error_no_device_in_area( async def test_error_no_device_in_area(
hass: HomeAssistant, init_components, area_registry: ar.AreaRegistry hass: HomeAssistant, area_registry: ar.AreaRegistry
) -> None: ) -> None:
"""Test error message when area is missing a device/entity.""" """Test error message when area is missing a device/entity."""
area_kitchen = area_registry.async_get_or_create("kitchen_id") area_kitchen = area_registry.async_get_or_create("kitchen_id")
@ -525,9 +531,8 @@ async def test_error_no_device_in_area(
) )
async def test_error_no_domain( @pytest.mark.usefixtures("init_components")
hass: HomeAssistant, init_components, area_registry: ar.AreaRegistry async def test_error_no_domain(hass: HomeAssistant) -> None:
) -> None:
"""Test error message when no devices/entities exist for a domain.""" """Test error message when no devices/entities exist for a domain."""
# We don't have a sentence for turning on all fans # We don't have a sentence for turning on all fans
@ -558,8 +563,9 @@ async def test_error_no_domain(
) )
@pytest.mark.usefixtures("init_components")
async def test_error_no_domain_in_area( async def test_error_no_domain_in_area(
hass: HomeAssistant, init_components, area_registry: ar.AreaRegistry hass: HomeAssistant, area_registry: ar.AreaRegistry
) -> None: ) -> None:
"""Test error message when no devices/entities for a domain exist in an area.""" """Test error message when no devices/entities for a domain exist in an area."""
area_kitchen = area_registry.async_get_or_create("kitchen_id") area_kitchen = area_registry.async_get_or_create("kitchen_id")
@ -576,9 +582,9 @@ async def test_error_no_domain_in_area(
) )
@pytest.mark.usefixtures("init_components")
async def test_error_no_domain_in_floor( async def test_error_no_domain_in_floor(
hass: HomeAssistant, hass: HomeAssistant,
init_components,
area_registry: ar.AreaRegistry, area_registry: ar.AreaRegistry,
floor_registry: fr.FloorRegistry, floor_registry: fr.FloorRegistry,
) -> None: ) -> None:
@ -618,7 +624,8 @@ async def test_error_no_domain_in_floor(
) )
async def test_error_no_device_class(hass: HomeAssistant, init_components) -> None: @pytest.mark.usefixtures("init_components")
async def test_error_no_device_class(hass: HomeAssistant) -> None:
"""Test error message when no entities of a device class exist.""" """Test error message when no entities of a device class exist."""
# Create a cover entity that is not a window. # Create a cover entity that is not a window.
# This ensures that the filtering below won't exit early because there are # This ensures that the filtering below won't exit early because there are
@ -658,8 +665,9 @@ async def test_error_no_device_class(hass: HomeAssistant, init_components) -> No
) )
@pytest.mark.usefixtures("init_components")
async def test_error_no_device_class_in_area( async def test_error_no_device_class_in_area(
hass: HomeAssistant, init_components, area_registry: ar.AreaRegistry hass: HomeAssistant, area_registry: ar.AreaRegistry
) -> None: ) -> None:
"""Test error message when no entities of a device class exist in an area.""" """Test error message when no entities of a device class exist in an area."""
area_bedroom = area_registry.async_get_or_create("bedroom_id") area_bedroom = area_registry.async_get_or_create("bedroom_id")
@ -676,7 +684,8 @@ async def test_error_no_device_class_in_area(
) )
async def test_error_no_intent(hass: HomeAssistant, init_components) -> None: @pytest.mark.usefixtures("init_components")
async def test_error_no_intent(hass: HomeAssistant) -> None:
"""Test response with an intent match failure.""" """Test response with an intent match failure."""
with patch( with patch(
"homeassistant.components.conversation.default_agent.recognize_all", "homeassistant.components.conversation.default_agent.recognize_all",
@ -696,8 +705,9 @@ async def test_error_no_intent(hass: HomeAssistant, init_components) -> None:
) )
@pytest.mark.usefixtures("init_components")
async def test_error_duplicate_names( async def test_error_duplicate_names(
hass: HomeAssistant, init_components, entity_registry: er.EntityRegistry hass: HomeAssistant, entity_registry: er.EntityRegistry
) -> None: ) -> None:
"""Test error message when multiple devices have the same name (or alias).""" """Test error message when multiple devices have the same name (or alias)."""
kitchen_light_1 = entity_registry.async_get_or_create("light", "demo", "1234") kitchen_light_1 = entity_registry.async_get_or_create("light", "demo", "1234")
@ -747,9 +757,9 @@ async def test_error_duplicate_names(
) )
@pytest.mark.usefixtures("init_components")
async def test_error_duplicate_names_in_area( async def test_error_duplicate_names_in_area(
hass: HomeAssistant, hass: HomeAssistant,
init_components,
area_registry: ar.AreaRegistry, area_registry: ar.AreaRegistry,
entity_registry: er.EntityRegistry, entity_registry: er.EntityRegistry,
) -> None: ) -> None:
@ -805,7 +815,8 @@ async def test_error_duplicate_names_in_area(
) )
async def test_error_wrong_state(hass: HomeAssistant, init_components) -> None: @pytest.mark.usefixtures("init_components")
async def test_error_wrong_state(hass: HomeAssistant) -> None:
"""Test error message when no entities are in the correct state.""" """Test error message when no entities are in the correct state."""
assert await async_setup_component(hass, media_player.DOMAIN, {}) assert await async_setup_component(hass, media_player.DOMAIN, {})
@ -824,9 +835,8 @@ async def test_error_wrong_state(hass: HomeAssistant, init_components) -> None:
assert result.response.speech["plain"]["speech"] == "Sorry, no device is playing" assert result.response.speech["plain"]["speech"] == "Sorry, no device is playing"
async def test_error_feature_not_supported( @pytest.mark.usefixtures("init_components")
hass: HomeAssistant, init_components async def test_error_feature_not_supported(hass: HomeAssistant) -> None:
) -> None:
"""Test error message when no devices support a required feature.""" """Test error message when no devices support a required feature."""
assert await async_setup_component(hass, media_player.DOMAIN, {}) assert await async_setup_component(hass, media_player.DOMAIN, {})
@ -849,7 +859,8 @@ async def test_error_feature_not_supported(
) )
async def test_error_no_timer_support(hass: HomeAssistant, init_components) -> None: @pytest.mark.usefixtures("init_components")
async def test_error_no_timer_support(hass: HomeAssistant) -> None:
"""Test error message when a device does not support timers (no handler is registered).""" """Test error message when a device does not support timers (no handler is registered)."""
device_id = "test_device" device_id = "test_device"
@ -866,7 +877,8 @@ async def test_error_no_timer_support(hass: HomeAssistant, init_components) -> N
) )
async def test_error_timer_not_found(hass: HomeAssistant, init_components) -> None: @pytest.mark.usefixtures("init_components")
async def test_error_timer_not_found(hass: HomeAssistant) -> None:
"""Test error message when a timer cannot be matched.""" """Test error message when a timer cannot be matched."""
device_id = "test_device" device_id = "test_device"
@ -888,9 +900,9 @@ async def test_error_timer_not_found(hass: HomeAssistant, init_components) -> No
) )
@pytest.mark.usefixtures("init_components")
async def test_error_multiple_timers_matched( async def test_error_multiple_timers_matched(
hass: HomeAssistant, hass: HomeAssistant,
init_components,
area_registry: ar.AreaRegistry, area_registry: ar.AreaRegistry,
device_registry: dr.DeviceRegistry, device_registry: dr.DeviceRegistry,
) -> None: ) -> None:
@ -938,8 +950,9 @@ async def test_error_multiple_timers_matched(
) )
@pytest.mark.usefixtures("init_components")
async def test_no_states_matched_default_error( async def test_no_states_matched_default_error(
hass: HomeAssistant, init_components, area_registry: ar.AreaRegistry hass: HomeAssistant, area_registry: ar.AreaRegistry
) -> None: ) -> None:
"""Test default response when no states match and slots are missing.""" """Test default response when no states match and slots are missing."""
area_kitchen = area_registry.async_get_or_create("kitchen_id") area_kitchen = area_registry.async_get_or_create("kitchen_id")
@ -966,9 +979,9 @@ async def test_no_states_matched_default_error(
) )
@pytest.mark.usefixtures("init_components")
async def test_empty_aliases( async def test_empty_aliases(
hass: HomeAssistant, hass: HomeAssistant,
init_components,
area_registry: ar.AreaRegistry, area_registry: ar.AreaRegistry,
device_registry: dr.DeviceRegistry, device_registry: dr.DeviceRegistry,
entity_registry: er.EntityRegistry, entity_registry: er.EntityRegistry,
@ -1031,7 +1044,8 @@ async def test_empty_aliases(
assert floors.values[0].text_in.text == floor_1.name assert floors.values[0].text_in.text == floor_1.name
async def test_all_domains_loaded(hass: HomeAssistant, init_components) -> None: @pytest.mark.usefixtures("init_components")
async def test_all_domains_loaded(hass: HomeAssistant) -> None:
"""Test that sentences for all domains are always loaded.""" """Test that sentences for all domains are always loaded."""
# light domain is not loaded # light domain is not loaded
@ -1050,9 +1064,9 @@ async def test_all_domains_loaded(hass: HomeAssistant, init_components) -> None:
) )
@pytest.mark.usefixtures("init_components")
async def test_same_named_entities_in_different_areas( async def test_same_named_entities_in_different_areas(
hass: HomeAssistant, hass: HomeAssistant,
init_components,
area_registry: ar.AreaRegistry, area_registry: ar.AreaRegistry,
entity_registry: er.EntityRegistry, entity_registry: er.EntityRegistry,
) -> None: ) -> None:
@ -1147,9 +1161,9 @@ async def test_same_named_entities_in_different_areas(
assert result.response.response_type == intent.IntentResponseType.QUERY_ANSWER assert result.response.response_type == intent.IntentResponseType.QUERY_ANSWER
@pytest.mark.usefixtures("init_components")
async def test_same_aliased_entities_in_different_areas( async def test_same_aliased_entities_in_different_areas(
hass: HomeAssistant, hass: HomeAssistant,
init_components,
area_registry: ar.AreaRegistry, area_registry: ar.AreaRegistry,
entity_registry: er.EntityRegistry, entity_registry: er.EntityRegistry,
) -> None: ) -> None:
@ -1238,7 +1252,8 @@ async def test_same_aliased_entities_in_different_areas(
assert result.response.response_type == intent.IntentResponseType.QUERY_ANSWER assert result.response.response_type == intent.IntentResponseType.QUERY_ANSWER
async def test_device_id_in_handler(hass: HomeAssistant, init_components) -> None: @pytest.mark.usefixtures("init_components")
async def test_device_id_in_handler(hass: HomeAssistant) -> None:
"""Test that the default agent passes device_id to intent handler.""" """Test that the default agent passes device_id to intent handler."""
device_id = "test_device" device_id = "test_device"
@ -1270,9 +1285,8 @@ async def test_device_id_in_handler(hass: HomeAssistant, init_components) -> Non
assert handler.device_id == device_id assert handler.device_id == device_id
async def test_name_wildcard_lower_priority( @pytest.mark.usefixtures("init_components")
hass: HomeAssistant, init_components async def test_name_wildcard_lower_priority(hass: HomeAssistant) -> None:
) -> None:
"""Test that the default agent does not prioritize a {name} slot when it's a wildcard.""" """Test that the default agent does not prioritize a {name} slot when it's a wildcard."""
class OrderBeerIntentHandler(intent.IntentHandler): class OrderBeerIntentHandler(intent.IntentHandler):