mirror of
https://github.com/home-assistant/core.git
synced 2025-04-23 08:47:57 +00:00
Add runtime_data rule to quality_scale hassfest validation (#131857)
* Add quality scale check for runtime_data * Linter fixes * Add developer documentation link * Update script/hassfest/quality_scale_validation/runtime_data.py Co-authored-by: epenet <6771947+epenet@users.noreply.github.com> * Update validation to check explicitly for ConfigEntry.runtime_data * Update script/hassfest/quality_scale_validation/runtime_data.py Co-authored-by: epenet <6771947+epenet@users.noreply.github.com> * Refine check for setting attributes * Patch with changes from epenet --------- Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
This commit is contained in:
parent
0fc365a114
commit
920c958ec7
@ -20,6 +20,7 @@ from .quality_scale_validation import (
|
||||
discovery,
|
||||
reauthentication_flow,
|
||||
reconfiguration_flow,
|
||||
runtime_data,
|
||||
strict_typing,
|
||||
unique_config_entry,
|
||||
)
|
||||
@ -52,7 +53,7 @@ ALL_RULES = [
|
||||
Rule("entity-event-setup", ScaledQualityScaleTiers.BRONZE),
|
||||
Rule("entity-unique-id", ScaledQualityScaleTiers.BRONZE),
|
||||
Rule("has-entity-name", ScaledQualityScaleTiers.BRONZE),
|
||||
Rule("runtime-data", ScaledQualityScaleTiers.BRONZE),
|
||||
Rule("runtime-data", ScaledQualityScaleTiers.BRONZE, runtime_data),
|
||||
Rule("test-before-configure", ScaledQualityScaleTiers.BRONZE),
|
||||
Rule("test-before-setup", ScaledQualityScaleTiers.BRONZE),
|
||||
Rule("unique-config-entry", ScaledQualityScaleTiers.BRONZE, unique_config_entry),
|
||||
|
53
script/hassfest/quality_scale_validation/runtime_data.py
Normal file
53
script/hassfest/quality_scale_validation/runtime_data.py
Normal file
@ -0,0 +1,53 @@
|
||||
"""Enforce that the integration uses ConfigEntry.runtime_data to store runtime data.
|
||||
|
||||
https://developers.home-assistant.io/docs/core/integration-quality-scale/rules/runtime-data
|
||||
"""
|
||||
|
||||
import ast
|
||||
|
||||
from script.hassfest.model import Integration
|
||||
|
||||
|
||||
def _sets_runtime_data(
|
||||
async_setup_entry_function: ast.AsyncFunctionDef, config_entry_argument: ast.arg
|
||||
) -> bool:
|
||||
"""Check that `entry.runtime` gets set within `async_setup_entry`."""
|
||||
for node in ast.walk(async_setup_entry_function):
|
||||
if (
|
||||
isinstance(node, ast.Attribute)
|
||||
and isinstance(node.value, ast.Name)
|
||||
and node.value.id == config_entry_argument.arg
|
||||
and node.attr == "runtime_data"
|
||||
and isinstance(node.ctx, ast.Store)
|
||||
):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _get_setup_entry_function(module: ast.Module) -> ast.AsyncFunctionDef | None:
|
||||
"""Get async_setup_entry function."""
|
||||
for item in module.body:
|
||||
if isinstance(item, ast.AsyncFunctionDef) and item.name == "async_setup_entry":
|
||||
return item
|
||||
return None
|
||||
|
||||
|
||||
def validate(integration: Integration) -> list[str] | None:
|
||||
"""Validate correct use of ConfigEntry.runtime_data."""
|
||||
init_file = integration.path / "__init__.py"
|
||||
init = ast.parse(init_file.read_text())
|
||||
|
||||
# Should not happen, but better to be safe
|
||||
if not (async_setup_entry := _get_setup_entry_function(init)):
|
||||
return [f"Could not find `async_setup_entry` in {init_file}"]
|
||||
if len(async_setup_entry.args.args) != 2:
|
||||
return [f"async_setup_entry has incorrect signature in {init_file}"]
|
||||
config_entry_argument = async_setup_entry.args.args[1]
|
||||
|
||||
if not _sets_runtime_data(async_setup_entry, config_entry_argument):
|
||||
return [
|
||||
"Integration does not set entry.runtime_data in async_setup_entry"
|
||||
f"({init_file})"
|
||||
]
|
||||
|
||||
return None
|
Loading…
x
Reference in New Issue
Block a user