Skip to content

Commit c804da8

Browse files
committed
Code refactoring after #16
1 parent 138eb37 commit c804da8

File tree

1 file changed

+21
-68
lines changed

1 file changed

+21
-68
lines changed
Lines changed: 21 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,16 @@
1-
"""Component to allow running Python scripts.
2-
https://docs.python.org/3/library/functions.html#compile
3-
"""
41
import hashlib
52
import logging
63

74
import voluptuous as vol
8-
from homeassistant.core import HomeAssistant
9-
from homeassistant.helpers import config_validation as cv
10-
from homeassistant.helpers.typing import ServiceCallType
11-
from homeassistant.requirements import async_process_requirements
12-
from homeassistant.config_entries import ConfigEntry
135
from homeassistant.core import (
146
HomeAssistant,
157
ServiceCall,
168
ServiceResponse,
179
SupportsResponse,
1810
)
19-
from homeassistant.helpers import config_validation as cv, entity_platform, service
20-
from homeassistant.util.json import JsonObjectType
11+
from homeassistant.helpers import config_validation as cv
12+
from homeassistant.helpers.typing import ConfigType
13+
from homeassistant.requirements import async_process_requirements
2114

2215
_LOGGER = logging.getLogger(__name__)
2316

@@ -34,29 +27,22 @@
3427
},
3528
extra=vol.ALLOW_EXTRA,
3629
)
37-
PYTHON_SCRIPTS_PRO_SERVICE_SCHEMA = vol.Schema(
30+
31+
SERVICE_SCHEMA = vol.Schema(
3832
{
3933
vol.Optional("file"): str,
4034
vol.Optional("source"): str,
4135
vol.Optional("cache"): bool,
42-
}
36+
},
37+
extra=vol.ALLOW_EXTRA,
4338
)
4439

4540

4641
def md5(data: str) -> str:
47-
"""
48-
Calculate the MD5 hash of the input string.
49-
50-
Args:
51-
data (str): The input string to calculate the MD5 hash for.
52-
53-
Returns:
54-
str: The MD5 hash of the input string.
55-
"""
5642
return hashlib.md5(data.encode()).hexdigest()
5743

5844

59-
async def async_setup(hass: HomeAssistant, hass_config: dict):
45+
async def async_setup(hass: HomeAssistant, hass_config: ConfigType):
6046
config: dict = hass_config[DOMAIN]
6147
if CONF_REQUIREMENTS in config:
6248
hass.async_create_task(
@@ -66,29 +52,6 @@ async def async_setup(hass: HomeAssistant, hass_config: dict):
6652
cache_code = {}
6753

6854
def handler(call: ServiceCall) -> ServiceResponse:
69-
"""
70-
Handler function for processing a service call.
71-
72-
Args:
73-
call (ServiceCall): The service call object containing the data for the call.
74-
75-
Returns:
76-
ServiceResponse: The response returned by the function.
77-
78-
Raises:
79-
None
80-
81-
Description:
82-
This function is responsible for handling a service call. It receives a ServiceCall object as the input parameter, which contains the data for the call. The function first checks if the 'file' or 'source' parameter is present in the call data. If neither of them is present, an error message is logged and the function returns without any response.
83-
84-
If either 'file' or 'source' is present, the function proceeds to retrieve the code from the cache or load it from the file or inline source. If the 'cache' parameter is set to False or the code is not found in the cache, the function loads the code from the specified file or inline source and compiles it.
85-
86-
If the 'cache' parameter is set to True and the code is loaded from a file, the compiled code is stored in the cache for future use. Similarly, if the code is loaded from an inline source, it is stored in the cache with the source ID as the key.
87-
88-
If the 'return_response' attribute of the service call is True, the function calls the 'execute_script' function with the necessary parameters and returns the response returned by it. Otherwise, the function returns None.
89-
90-
Note: This function assumes that the necessary variables, such as '_LOGGER', 'hass', and 'cache_code', are already defined.
91-
"""
9255
# Run with SyncWorker
9356
file = call.data.get("file")
9457
srcid = md5(call.data["source"]) if "source" in call.data else None
@@ -122,41 +85,31 @@ def handler(call: ServiceCall) -> ServiceResponse:
12285
else:
12386
_LOGGER.debug("Load code from cache")
12487

125-
if call.return_response:
126-
return execute_script(hass, call.data, _LOGGER, code) or {}
127-
return None
88+
return execute_script(hass, call.data, _LOGGER, code)
12889

12990
hass.services.async_register(
13091
DOMAIN,
13192
"exec",
13293
handler,
133-
PYTHON_SCRIPTS_PRO_SERVICE_SCHEMA,
94+
SERVICE_SCHEMA,
13495
SupportsResponse.OPTIONAL,
13596
)
13697

13798
return True
13899

139100

140-
def execute_script(hass: HomeAssistant, data: dict, logger, code):
101+
def execute_script(hass: HomeAssistant, data: dict, logger, code) -> ServiceResponse:
141102
try:
142103
_LOGGER.debug("Run python script")
143-
loc_vars = {}
144-
exec(code, {}, loc_vars)
145-
146-
if loc_vars.get("return_response") is not None:
147-
service_response: JsonObjectType = {
148-
"stdout": loc_vars["return_response"],
149-
"stderr": "",
150-
"returncode": 0,
151-
}
152-
return service_response
153-
else:
154-
return {}
104+
exec(code, locals())
105+
response = {
106+
k: v
107+
for k, v in locals().items()
108+
if isinstance(v, (dict, list, str, int, float, bool))
109+
and k not in ("__builtins__", "data")
110+
or v is None
111+
}
112+
return response
155113
except Exception as e:
156114
_LOGGER.error(f"Error executing script", exc_info=e)
157-
service_response: JsonObjectType = {
158-
"stderr": f"Error executing script: {e}",
159-
"stdout": "",
160-
"returncode": 13,
161-
}
162-
return service_response if e else {}
115+
return {"error": str(e)}

0 commit comments

Comments
 (0)