Clean up frontend services and events (#31654)
* Clean up frontend services and events * Fix bug in core instead * Add test that core works correctly with callback marked async funcspull/31690/head
parent
28eeed1db3
commit
12de3f1e47
|
@ -16,6 +16,7 @@ from homeassistant.components.http.view import HomeAssistantView
|
||||||
from homeassistant.config import async_hass_config_yaml
|
from homeassistant.config import async_hass_config_yaml
|
||||||
from homeassistant.const import CONF_NAME, EVENT_THEMES_UPDATED
|
from homeassistant.const import CONF_NAME, EVENT_THEMES_UPDATED
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
|
from homeassistant.helpers import service
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.translation import async_get_translations
|
from homeassistant.helpers.translation import async_get_translations
|
||||||
from homeassistant.loader import bind_hass
|
from homeassistant.loader import bind_hass
|
||||||
|
@ -103,19 +104,6 @@ CONFIG_SCHEMA = vol.Schema(
|
||||||
|
|
||||||
SERVICE_SET_THEME = "set_theme"
|
SERVICE_SET_THEME = "set_theme"
|
||||||
SERVICE_RELOAD_THEMES = "reload_themes"
|
SERVICE_RELOAD_THEMES = "reload_themes"
|
||||||
SERVICE_SET_THEME_SCHEMA = vol.Schema({vol.Required(CONF_NAME): cv.string})
|
|
||||||
WS_TYPE_GET_PANELS = "get_panels"
|
|
||||||
SCHEMA_GET_PANELS = websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend(
|
|
||||||
{vol.Required("type"): WS_TYPE_GET_PANELS}
|
|
||||||
)
|
|
||||||
WS_TYPE_GET_THEMES = "frontend/get_themes"
|
|
||||||
SCHEMA_GET_THEMES = websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend(
|
|
||||||
{vol.Required("type"): WS_TYPE_GET_THEMES}
|
|
||||||
)
|
|
||||||
WS_TYPE_GET_TRANSLATIONS = "frontend/get_translations"
|
|
||||||
SCHEMA_GET_TRANSLATIONS = websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend(
|
|
||||||
{vol.Required("type"): WS_TYPE_GET_TRANSLATIONS, vol.Required("language"): str}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class Panel:
|
class Panel:
|
||||||
|
@ -251,15 +239,9 @@ def _frontend_root(dev_repo_path):
|
||||||
async def async_setup(hass, config):
|
async def async_setup(hass, config):
|
||||||
"""Set up the serving of the frontend."""
|
"""Set up the serving of the frontend."""
|
||||||
await async_setup_frontend_storage(hass)
|
await async_setup_frontend_storage(hass)
|
||||||
hass.components.websocket_api.async_register_command(
|
hass.components.websocket_api.async_register_command(websocket_get_panels)
|
||||||
WS_TYPE_GET_PANELS, websocket_get_panels, SCHEMA_GET_PANELS
|
hass.components.websocket_api.async_register_command(websocket_get_themes)
|
||||||
)
|
hass.components.websocket_api.async_register_command(websocket_get_translations)
|
||||||
hass.components.websocket_api.async_register_command(
|
|
||||||
WS_TYPE_GET_THEMES, websocket_get_themes, SCHEMA_GET_THEMES
|
|
||||||
)
|
|
||||||
hass.components.websocket_api.async_register_command(
|
|
||||||
WS_TYPE_GET_TRANSLATIONS, websocket_get_translations, SCHEMA_GET_TRANSLATIONS
|
|
||||||
)
|
|
||||||
hass.http.register_view(ManifestJSONView)
|
hass.http.register_view(ManifestJSONView)
|
||||||
|
|
||||||
conf = config.get(DOMAIN, {})
|
conf = config.get(DOMAIN, {})
|
||||||
|
@ -331,11 +313,7 @@ async def async_setup(hass, config):
|
||||||
def _async_setup_themes(hass, themes):
|
def _async_setup_themes(hass, themes):
|
||||||
"""Set up themes data and services."""
|
"""Set up themes data and services."""
|
||||||
hass.data[DATA_DEFAULT_THEME] = DEFAULT_THEME
|
hass.data[DATA_DEFAULT_THEME] = DEFAULT_THEME
|
||||||
if themes is None:
|
hass.data[DATA_THEMES] = themes or {}
|
||||||
hass.data[DATA_THEMES] = {}
|
|
||||||
return
|
|
||||||
|
|
||||||
hass.data[DATA_THEMES] = themes
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def update_theme_and_fire_event():
|
def update_theme_and_fire_event():
|
||||||
|
@ -348,9 +326,7 @@ def _async_setup_themes(hass, themes):
|
||||||
"app-header-background-color",
|
"app-header-background-color",
|
||||||
themes[name].get(PRIMARY_COLOR, DEFAULT_THEME_COLOR),
|
themes[name].get(PRIMARY_COLOR, DEFAULT_THEME_COLOR),
|
||||||
)
|
)
|
||||||
hass.bus.async_fire(
|
hass.bus.async_fire(EVENT_THEMES_UPDATED)
|
||||||
EVENT_THEMES_UPDATED, {"themes": themes, "default_theme": name}
|
|
||||||
)
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def set_theme(call):
|
def set_theme(call):
|
||||||
|
@ -373,10 +349,17 @@ def _async_setup_themes(hass, themes):
|
||||||
hass.data[DATA_DEFAULT_THEME] = DEFAULT_THEME
|
hass.data[DATA_DEFAULT_THEME] = DEFAULT_THEME
|
||||||
update_theme_and_fire_event()
|
update_theme_and_fire_event()
|
||||||
|
|
||||||
hass.services.async_register(
|
service.async_register_admin_service(
|
||||||
DOMAIN, SERVICE_SET_THEME, set_theme, schema=SERVICE_SET_THEME_SCHEMA
|
hass,
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_SET_THEME,
|
||||||
|
set_theme,
|
||||||
|
vol.Schema({vol.Required(CONF_NAME): cv.string}),
|
||||||
|
)
|
||||||
|
|
||||||
|
service.async_register_admin_service(
|
||||||
|
hass, DOMAIN, SERVICE_RELOAD_THEMES, reload_themes
|
||||||
)
|
)
|
||||||
hass.services.async_register(DOMAIN, SERVICE_RELOAD_THEMES, reload_themes)
|
|
||||||
|
|
||||||
|
|
||||||
class IndexView(web_urldispatcher.AbstractResource):
|
class IndexView(web_urldispatcher.AbstractResource):
|
||||||
|
@ -498,6 +481,7 @@ class ManifestJSONView(HomeAssistantView):
|
||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
|
@websocket_api.websocket_command({"type": "get_panels"})
|
||||||
def websocket_get_panels(hass, connection, msg):
|
def websocket_get_panels(hass, connection, msg):
|
||||||
"""Handle get panels command.
|
"""Handle get panels command.
|
||||||
|
|
||||||
|
@ -514,6 +498,7 @@ def websocket_get_panels(hass, connection, msg):
|
||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
|
@websocket_api.websocket_command({"type": "frontend/get_themes"})
|
||||||
def websocket_get_themes(hass, connection, msg):
|
def websocket_get_themes(hass, connection, msg):
|
||||||
"""Handle get themes command.
|
"""Handle get themes command.
|
||||||
|
|
||||||
|
@ -530,6 +515,9 @@ def websocket_get_themes(hass, connection, msg):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@websocket_api.websocket_command(
|
||||||
|
{"type": "frontend/get_translations", vol.Required("language"): str}
|
||||||
|
)
|
||||||
@websocket_api.async_response
|
@websocket_api.async_response
|
||||||
async def websocket_get_translations(hass, connection, msg):
|
async def websocket_get_translations(hass, connection, msg):
|
||||||
"""Handle get translations command.
|
"""Handle get translations command.
|
||||||
|
|
|
@ -298,10 +298,10 @@ class HomeAssistant:
|
||||||
|
|
||||||
if asyncio.iscoroutine(check_target):
|
if asyncio.iscoroutine(check_target):
|
||||||
task = self.loop.create_task(target) # type: ignore
|
task = self.loop.create_task(target) # type: ignore
|
||||||
elif is_callback(check_target):
|
|
||||||
self.loop.call_soon(target, *args)
|
|
||||||
elif asyncio.iscoroutinefunction(check_target):
|
elif asyncio.iscoroutinefunction(check_target):
|
||||||
task = self.loop.create_task(target(*args))
|
task = self.loop.create_task(target(*args))
|
||||||
|
elif is_callback(check_target):
|
||||||
|
self.loop.call_soon(target, *args)
|
||||||
else:
|
else:
|
||||||
task = self.loop.run_in_executor( # type: ignore
|
task = self.loop.run_in_executor( # type: ignore
|
||||||
None, target, *args
|
None, target, *args
|
||||||
|
@ -360,7 +360,11 @@ class HomeAssistant:
|
||||||
target: target to call.
|
target: target to call.
|
||||||
args: parameters for method to call.
|
args: parameters for method to call.
|
||||||
"""
|
"""
|
||||||
if not asyncio.iscoroutine(target) and is_callback(target):
|
if (
|
||||||
|
not asyncio.iscoroutine(target)
|
||||||
|
and not asyncio.iscoroutinefunction(target)
|
||||||
|
and is_callback(target)
|
||||||
|
):
|
||||||
target(*args)
|
target(*args)
|
||||||
else:
|
else:
|
||||||
self.async_add_job(target, *args)
|
self.async_add_job(target, *args)
|
||||||
|
@ -1245,10 +1249,10 @@ class ServiceRegistry:
|
||||||
self, handler: Service, service_call: ServiceCall
|
self, handler: Service, service_call: ServiceCall
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Execute a service."""
|
"""Execute a service."""
|
||||||
if handler.is_callback:
|
if handler.is_coroutinefunction:
|
||||||
handler.func(service_call)
|
|
||||||
elif handler.is_coroutinefunction:
|
|
||||||
await handler.func(service_call)
|
await handler.func(service_call)
|
||||||
|
elif handler.is_callback:
|
||||||
|
handler.func(service_call)
|
||||||
else:
|
else:
|
||||||
await self._hass.async_add_executor_job(handler.func, service_call)
|
await self._hass.async_add_executor_job(handler.func, service_call)
|
||||||
|
|
||||||
|
|
|
@ -461,7 +461,9 @@ def async_register_admin_service(
|
||||||
if not user.is_admin:
|
if not user.is_admin:
|
||||||
raise Unauthorized(context=call.context)
|
raise Unauthorized(context=call.context)
|
||||||
|
|
||||||
await hass.async_add_job(service_func, call)
|
result = hass.async_add_job(service_func, call)
|
||||||
|
if result is not None:
|
||||||
|
await result
|
||||||
|
|
||||||
hass.services.async_register(domain, service, admin_handler, schema)
|
hass.services.async_register(domain, service, admin_handler, schema)
|
||||||
|
|
||||||
|
|
|
@ -1180,3 +1180,28 @@ def test_context():
|
||||||
assert c.user_id == 23
|
assert c.user_id == 23
|
||||||
assert c.parent_id == 100
|
assert c.parent_id == 100
|
||||||
assert c.id is not None
|
assert c.id is not None
|
||||||
|
|
||||||
|
|
||||||
|
async def test_async_functions_with_callback(hass):
|
||||||
|
"""Test we deal with async functions accidentally marked as callback."""
|
||||||
|
runs = []
|
||||||
|
|
||||||
|
@ha.callback
|
||||||
|
async def test():
|
||||||
|
runs.append(True)
|
||||||
|
|
||||||
|
await hass.async_add_job(test)
|
||||||
|
assert len(runs) == 1
|
||||||
|
|
||||||
|
hass.async_run_job(test)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert len(runs) == 2
|
||||||
|
|
||||||
|
@ha.callback
|
||||||
|
async def service_handler(call):
|
||||||
|
runs.append(True)
|
||||||
|
|
||||||
|
hass.services.async_register("test_domain", "test_service", service_handler)
|
||||||
|
|
||||||
|
await hass.services.async_call("test_domain", "test_service", blocking=True)
|
||||||
|
assert len(runs) == 3
|
||||||
|
|
Loading…
Reference in New Issue