mirror of
https://github.com/home-assistant/core.git
synced 2025-07-31 19:25:12 +02:00
Create issue if exception is not raised
This commit is contained in:
@@ -27,6 +27,7 @@ from homeassistant.core import (
|
|||||||
SupportsResponse,
|
SupportsResponse,
|
||||||
)
|
)
|
||||||
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
||||||
|
from homeassistant.helpers import issue_registry as ir
|
||||||
from homeassistant.helpers.service import async_set_service_schema
|
from homeassistant.helpers.service import async_set_service_schema
|
||||||
from homeassistant.helpers.typing import ConfigType
|
from homeassistant.helpers.typing import ConfigType
|
||||||
from homeassistant.loader import bind_hass
|
from homeassistant.loader import bind_hass
|
||||||
@@ -249,6 +250,16 @@ def execute(hass, filename, source, data=None, return_response=False):
|
|||||||
if return_response:
|
if return_response:
|
||||||
raise ServiceValidationError(f"Error executing script: {err}") from err
|
raise ServiceValidationError(f"Error executing script: {err}") from err
|
||||||
logger.error("Error executing script: %s", err)
|
logger.error("Error executing script: %s", err)
|
||||||
|
ir.create_issue(
|
||||||
|
hass,
|
||||||
|
DOMAIN,
|
||||||
|
filename,
|
||||||
|
breaks_in_ha_version="2024.4.0",
|
||||||
|
is_fixable=False,
|
||||||
|
severity=ir.IssueSeverity.ERROR,
|
||||||
|
translation_key="script_continue_on_error",
|
||||||
|
translation_placeholders={"script_name": filename.replace(".py", "")},
|
||||||
|
)
|
||||||
return None
|
return None
|
||||||
except Exception as err: # pylint: disable=broad-except
|
except Exception as err: # pylint: disable=broad-except
|
||||||
if return_response:
|
if return_response:
|
||||||
@@ -256,6 +267,16 @@ def execute(hass, filename, source, data=None, return_response=False):
|
|||||||
f"Error executing script ({type(err).__name__}): {err}"
|
f"Error executing script ({type(err).__name__}): {err}"
|
||||||
) from err
|
) from err
|
||||||
logger.exception("Error executing script: %s", err)
|
logger.exception("Error executing script: %s", err)
|
||||||
|
ir.create_issue(
|
||||||
|
hass,
|
||||||
|
DOMAIN,
|
||||||
|
filename,
|
||||||
|
breaks_in_ha_version="2024.4.0",
|
||||||
|
is_fixable=False,
|
||||||
|
severity=ir.IssueSeverity.ERROR,
|
||||||
|
translation_key="script_continue_on_error",
|
||||||
|
translation_placeholders={"script_name": filename.replace(".py", "")},
|
||||||
|
)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return restricted_globals["output"]
|
return restricted_globals["output"]
|
||||||
|
@@ -4,5 +4,11 @@
|
|||||||
"name": "[%key:common::action::reload%]",
|
"name": "[%key:common::action::reload%]",
|
||||||
"description": "Reloads all available Python scripts."
|
"description": "Reloads all available Python scripts."
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"issues": {
|
||||||
|
"script_continue_on_error": {
|
||||||
|
"title": "'python_script.{script_name}' logs errors and continues",
|
||||||
|
"description": "The `python_script` integration will change to raise script errors instead of logging them.\n\nThis will **stop** automations/scripts if `continue_on_error` is not set ([docs](https://www.home-assistant.io/docs/scripts/#continuing-on-error)).\n\nTo enable the new behavior, add a `response_variable` ([docs](https://www.home-assistant.io/docs/scripts/service-calls/#use-templates-to-handle-response-data)) to your service call."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -7,6 +7,7 @@ import pytest
|
|||||||
from homeassistant.components.python_script import DOMAIN, FOLDER, execute
|
from homeassistant.components.python_script import DOMAIN, FOLDER, execute
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
||||||
|
from homeassistant.helpers import issue_registry as ir
|
||||||
from homeassistant.helpers.service import async_get_all_descriptions
|
from homeassistant.helpers.service import async_get_all_descriptions
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
@@ -123,7 +124,9 @@ this is not valid Python
|
|||||||
|
|
||||||
|
|
||||||
async def test_execute_runtime_error(
|
async def test_execute_runtime_error(
|
||||||
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
|
hass: HomeAssistant,
|
||||||
|
caplog: pytest.LogCaptureFixture,
|
||||||
|
issue_registry: ir.IssueRegistry,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test compile error logs error."""
|
"""Test compile error logs error."""
|
||||||
caplog.set_level(logging.ERROR)
|
caplog.set_level(logging.ERROR)
|
||||||
@@ -135,9 +138,12 @@ raise Exception('boom')
|
|||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert "Error executing script: boom" in caplog.text
|
assert "Error executing script: boom" in caplog.text
|
||||||
|
assert len(issue_registry.issues) == 1
|
||||||
|
|
||||||
|
|
||||||
async def test_execute_runtime_error_with_response(hass: HomeAssistant) -> None:
|
async def test_execute_runtime_error_with_response(
|
||||||
|
hass: HomeAssistant, issue_registry: ir.IssueRegistry
|
||||||
|
) -> None:
|
||||||
"""Test compile error logs error."""
|
"""Test compile error logs error."""
|
||||||
source = """
|
source = """
|
||||||
raise Exception('boom')
|
raise Exception('boom')
|
||||||
@@ -148,10 +154,13 @@ raise Exception('boom')
|
|||||||
|
|
||||||
assert type(task.exception()) == HomeAssistantError
|
assert type(task.exception()) == HomeAssistantError
|
||||||
assert "Error executing script (Exception): boom" in str(task.exception())
|
assert "Error executing script (Exception): boom" in str(task.exception())
|
||||||
|
assert len(issue_registry.issues) == 0
|
||||||
|
|
||||||
|
|
||||||
async def test_accessing_async_methods(
|
async def test_accessing_async_methods(
|
||||||
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
|
hass: HomeAssistant,
|
||||||
|
caplog: pytest.LogCaptureFixture,
|
||||||
|
issue_registry: ir.IssueRegistry,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test compile error logs error."""
|
"""Test compile error logs error."""
|
||||||
caplog.set_level(logging.ERROR)
|
caplog.set_level(logging.ERROR)
|
||||||
@@ -163,9 +172,12 @@ hass.async_stop()
|
|||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert "Not allowed to access async methods" in caplog.text
|
assert "Not allowed to access async methods" in caplog.text
|
||||||
|
assert len(issue_registry.issues) == 1
|
||||||
|
|
||||||
|
|
||||||
async def test_accessing_async_methods_with_response(hass: HomeAssistant) -> None:
|
async def test_accessing_async_methods_with_response(
|
||||||
|
hass: HomeAssistant, issue_registry: ir.IssueRegistry
|
||||||
|
) -> None:
|
||||||
"""Test compile error logs error."""
|
"""Test compile error logs error."""
|
||||||
source = """
|
source = """
|
||||||
hass.async_stop()
|
hass.async_stop()
|
||||||
@@ -176,6 +188,7 @@ hass.async_stop()
|
|||||||
|
|
||||||
assert type(task.exception()) == ServiceValidationError
|
assert type(task.exception()) == ServiceValidationError
|
||||||
assert "Not allowed to access async methods" in str(task.exception())
|
assert "Not allowed to access async methods" in str(task.exception())
|
||||||
|
assert len(issue_registry.issues) == 0
|
||||||
|
|
||||||
|
|
||||||
async def test_using_complex_structures(
|
async def test_using_complex_structures(
|
||||||
@@ -196,7 +209,9 @@ logger.info('Logging from inside script: %s %s' % (mydict["a"], mylist[2]))
|
|||||||
|
|
||||||
|
|
||||||
async def test_accessing_forbidden_methods(
|
async def test_accessing_forbidden_methods(
|
||||||
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
|
hass: HomeAssistant,
|
||||||
|
caplog: pytest.LogCaptureFixture,
|
||||||
|
issue_registry: ir.IssueRegistry,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test compile error logs error."""
|
"""Test compile error logs error."""
|
||||||
caplog.set_level(logging.ERROR)
|
caplog.set_level(logging.ERROR)
|
||||||
@@ -208,12 +223,16 @@ async def test_accessing_forbidden_methods(
|
|||||||
"time.tzset()": "TimeWrapper.tzset",
|
"time.tzset()": "TimeWrapper.tzset",
|
||||||
}.items():
|
}.items():
|
||||||
caplog.records.clear()
|
caplog.records.clear()
|
||||||
|
issue_registry.async_delete("python_script", "test.py")
|
||||||
hass.async_add_executor_job(execute, hass, "test.py", source, {})
|
hass.async_add_executor_job(execute, hass, "test.py", source, {})
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert f"Not allowed to access {name}" in caplog.text
|
assert f"Not allowed to access {name}" in caplog.text
|
||||||
|
assert len(issue_registry.issues) == 1
|
||||||
|
|
||||||
|
|
||||||
async def test_accessing_forbidden_methods_with_response(hass: HomeAssistant) -> None:
|
async def test_accessing_forbidden_methods_with_response(
|
||||||
|
hass: HomeAssistant, issue_registry: ir.IssueRegistry
|
||||||
|
) -> None:
|
||||||
"""Test compile error logs error."""
|
"""Test compile error logs error."""
|
||||||
for source, name in {
|
for source, name in {
|
||||||
"hass.stop()": "HomeAssistant.stop",
|
"hass.stop()": "HomeAssistant.stop",
|
||||||
@@ -226,6 +245,7 @@ async def test_accessing_forbidden_methods_with_response(hass: HomeAssistant) ->
|
|||||||
|
|
||||||
assert type(task.exception()) == ServiceValidationError
|
assert type(task.exception()) == ServiceValidationError
|
||||||
assert f"Not allowed to access {name}" in str(task.exception())
|
assert f"Not allowed to access {name}" in str(task.exception())
|
||||||
|
assert len(issue_registry.issues) == 0
|
||||||
|
|
||||||
|
|
||||||
async def test_iterating(hass: HomeAssistant) -> None:
|
async def test_iterating(hass: HomeAssistant) -> None:
|
||||||
|
Reference in New Issue
Block a user