Load user-provided descriptions for python_scripts (#26069)
* Load user-provided descriptions for python_scripts * Import SERVICE_DESCRIPTION_CACHE * Use async_set_service_schema to register service descriptions * Add python_script tests for loading service descriptions * Use async/await in test
This commit is contained in:
parent
2d432da14c
commit
aff151c90a
2 changed files with 114 additions and 1 deletions
|
@ -9,8 +9,10 @@ import voluptuous as vol
|
|||
|
||||
from homeassistant.const import SERVICE_RELOAD
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers.service import async_set_service_schema
|
||||
from homeassistant.loader import bind_hass
|
||||
from homeassistant.util import sanitize_filename
|
||||
from homeassistant.util.yaml.loader import load_yaml
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -90,10 +92,23 @@ def discover_scripts(hass):
|
|||
continue
|
||||
hass.services.remove(DOMAIN, existing_service)
|
||||
|
||||
# Load user-provided service descriptions from python_scripts/services.yaml
|
||||
services_yaml = os.path.join(path, "services.yaml")
|
||||
if os.path.exists(services_yaml):
|
||||
services_dict = load_yaml(services_yaml)
|
||||
else:
|
||||
services_dict = {}
|
||||
|
||||
for fil in glob.iglob(os.path.join(path, "*.py")):
|
||||
name = os.path.splitext(os.path.basename(fil))[0]
|
||||
hass.services.register(DOMAIN, name, python_script_service_handler)
|
||||
|
||||
service_desc = {
|
||||
"description": services_dict.get(name, {}).get("description", ""),
|
||||
"fields": services_dict.get(name, {}).get("fields", {}),
|
||||
}
|
||||
async_set_service_schema(hass, DOMAIN, name, service_desc)
|
||||
|
||||
|
||||
@bind_hass
|
||||
def execute_script(hass, name, data=None):
|
||||
|
|
|
@ -3,8 +3,11 @@ import asyncio
|
|||
import logging
|
||||
from unittest.mock import patch, mock_open
|
||||
|
||||
from homeassistant.helpers.service import async_get_all_descriptions
|
||||
from homeassistant.setup import async_setup_component
|
||||
from homeassistant.components.python_script import execute
|
||||
from homeassistant.components.python_script import DOMAIN, execute, FOLDER
|
||||
|
||||
from tests.common import patch_yaml_files
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
|
@ -289,6 +292,101 @@ def test_reload(hass):
|
|||
assert hass.services.has_service("python_script", "reload")
|
||||
|
||||
|
||||
async def test_service_descriptions(hass):
|
||||
"""Test that service descriptions are loaded and reloaded correctly."""
|
||||
# Test 1: no user-provided services.yaml file
|
||||
scripts1 = [
|
||||
"/some/config/dir/python_scripts/hello.py",
|
||||
"/some/config/dir/python_scripts/world_beer.py",
|
||||
]
|
||||
|
||||
service_descriptions1 = (
|
||||
"hello:\n"
|
||||
" description: Description of hello.py.\n"
|
||||
" fields:\n"
|
||||
" fake_param:\n"
|
||||
" description: Parameter used by hello.py.\n"
|
||||
" example: 'This is a test of python_script.hello'"
|
||||
)
|
||||
services_yaml1 = {
|
||||
"{}/{}/services.yaml".format(
|
||||
hass.config.config_dir, FOLDER
|
||||
): service_descriptions1
|
||||
}
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.python_script.os.path.isdir", return_value=True
|
||||
), patch(
|
||||
"homeassistant.components.python_script.glob.iglob", return_value=scripts1
|
||||
), patch(
|
||||
"homeassistant.components.python_script.os.path.exists", return_value=True
|
||||
), patch_yaml_files(
|
||||
services_yaml1
|
||||
):
|
||||
await async_setup_component(hass, DOMAIN, {})
|
||||
|
||||
descriptions = await async_get_all_descriptions(hass)
|
||||
|
||||
assert len(descriptions) == 1
|
||||
|
||||
assert descriptions[DOMAIN]["hello"]["description"] == "Description of hello.py."
|
||||
assert (
|
||||
descriptions[DOMAIN]["hello"]["fields"]["fake_param"]["description"]
|
||||
== "Parameter used by hello.py."
|
||||
)
|
||||
assert (
|
||||
descriptions[DOMAIN]["hello"]["fields"]["fake_param"]["example"]
|
||||
== "This is a test of python_script.hello"
|
||||
)
|
||||
|
||||
assert descriptions[DOMAIN]["world_beer"]["description"] == ""
|
||||
assert bool(descriptions[DOMAIN]["world_beer"]["fields"]) is False
|
||||
|
||||
# Test 2: user-provided services.yaml file
|
||||
scripts2 = [
|
||||
"/some/config/dir/python_scripts/hello2.py",
|
||||
"/some/config/dir/python_scripts/world_beer.py",
|
||||
]
|
||||
|
||||
service_descriptions2 = (
|
||||
"hello2:\n"
|
||||
" description: Description of hello2.py.\n"
|
||||
" fields:\n"
|
||||
" fake_param:\n"
|
||||
" description: Parameter used by hello2.py.\n"
|
||||
" example: 'This is a test of python_script.hello2'"
|
||||
)
|
||||
services_yaml2 = {
|
||||
"{}/{}/services.yaml".format(
|
||||
hass.config.config_dir, FOLDER
|
||||
): service_descriptions2
|
||||
}
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.python_script.os.path.isdir", return_value=True
|
||||
), patch(
|
||||
"homeassistant.components.python_script.glob.iglob", return_value=scripts2
|
||||
), patch(
|
||||
"homeassistant.components.python_script.os.path.exists", return_value=True
|
||||
), patch_yaml_files(
|
||||
services_yaml2
|
||||
):
|
||||
await hass.services.async_call(DOMAIN, "reload", {}, blocking=True)
|
||||
descriptions = await async_get_all_descriptions(hass)
|
||||
|
||||
assert len(descriptions) == 1
|
||||
|
||||
assert descriptions[DOMAIN]["hello2"]["description"] == "Description of hello2.py."
|
||||
assert (
|
||||
descriptions[DOMAIN]["hello2"]["fields"]["fake_param"]["description"]
|
||||
== "Parameter used by hello2.py."
|
||||
)
|
||||
assert (
|
||||
descriptions[DOMAIN]["hello2"]["fields"]["fake_param"]["example"]
|
||||
== "This is a test of python_script.hello2"
|
||||
)
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_sleep_warns_one(hass, caplog):
|
||||
"""Test time.sleep warns once."""
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue