mirror of
https://github.com/home-assistant/core.git
synced 2025-07-17 10:17:09 +00:00
Cache AST module parsing in hassfest (#132244)
This commit is contained in:
parent
e54d929573
commit
9771998415
@ -1 +1,14 @@
|
|||||||
"""Manifest validator."""
|
"""Manifest validator."""
|
||||||
|
|
||||||
|
import ast
|
||||||
|
from functools import lru_cache
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache
|
||||||
|
def ast_parse_module(file_path: Path) -> ast.Module:
|
||||||
|
"""Parse a module.
|
||||||
|
|
||||||
|
Cached to avoid parsing the same file for each plugin.
|
||||||
|
"""
|
||||||
|
return ast.parse(file_path.read_text())
|
||||||
|
@ -6,6 +6,7 @@ import ast
|
|||||||
|
|
||||||
from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN
|
from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN
|
||||||
|
|
||||||
|
from . import ast_parse_module
|
||||||
from .model import Config, Integration
|
from .model import Config, Integration
|
||||||
|
|
||||||
CONFIG_SCHEMA_IGNORE = {
|
CONFIG_SCHEMA_IGNORE = {
|
||||||
@ -60,7 +61,7 @@ def _validate_integration(config: Config, integration: Integration) -> None:
|
|||||||
# Virtual integrations don't have any implementation
|
# Virtual integrations don't have any implementation
|
||||||
return
|
return
|
||||||
|
|
||||||
init = ast.parse(init_file.read_text())
|
init = ast_parse_module(init_file)
|
||||||
|
|
||||||
# No YAML Support
|
# No YAML Support
|
||||||
if not _has_function(
|
if not _has_function(
|
||||||
@ -81,7 +82,7 @@ def _validate_integration(config: Config, integration: Integration) -> None:
|
|||||||
|
|
||||||
config_file = integration.path / "config.py"
|
config_file = integration.path / "config.py"
|
||||||
if config_file.is_file():
|
if config_file.is_file():
|
||||||
config_module = ast.parse(config_file.read_text())
|
config_module = ast_parse_module(config_file)
|
||||||
if _has_function(config_module, ast.AsyncFunctionDef, "async_validate_config"):
|
if _has_function(config_module, ast.AsyncFunctionDef, "async_validate_config"):
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ from pathlib import Path
|
|||||||
from homeassistant.const import Platform
|
from homeassistant.const import Platform
|
||||||
from homeassistant.requirements import DISCOVERY_INTEGRATIONS
|
from homeassistant.requirements import DISCOVERY_INTEGRATIONS
|
||||||
|
|
||||||
|
from . import ast_parse_module
|
||||||
from .model import Config, Integration
|
from .model import Config, Integration
|
||||||
|
|
||||||
|
|
||||||
@ -33,7 +34,7 @@ class ImportCollector(ast.NodeVisitor):
|
|||||||
self._cur_fil_dir = fil.relative_to(self.integration.path)
|
self._cur_fil_dir = fil.relative_to(self.integration.path)
|
||||||
self.referenced[self._cur_fil_dir] = set()
|
self.referenced[self._cur_fil_dir] = set()
|
||||||
try:
|
try:
|
||||||
self.visit(ast.parse(fil.read_text()))
|
self.visit(ast_parse_module(fil))
|
||||||
except SyntaxError as e:
|
except SyntaxError as e:
|
||||||
e.add_note(f"File: {fil}")
|
e.add_note(f"File: {fil}")
|
||||||
raise
|
raise
|
||||||
|
@ -5,6 +5,7 @@ https://developers.home-assistant.io/docs/core/integration-quality-scale/rules/c
|
|||||||
|
|
||||||
import ast
|
import ast
|
||||||
|
|
||||||
|
from script.hassfest import ast_parse_module
|
||||||
from script.hassfest.model import Integration
|
from script.hassfest.model import Integration
|
||||||
|
|
||||||
|
|
||||||
@ -20,7 +21,7 @@ def validate(integration: Integration) -> list[str] | None:
|
|||||||
"""Validate that the integration has a config flow."""
|
"""Validate that the integration has a config flow."""
|
||||||
|
|
||||||
init_file = integration.path / "__init__.py"
|
init_file = integration.path / "__init__.py"
|
||||||
init = ast.parse(init_file.read_text())
|
init = ast_parse_module(init_file)
|
||||||
|
|
||||||
if not _has_unload_entry_function(init):
|
if not _has_unload_entry_function(init):
|
||||||
return [
|
return [
|
||||||
|
@ -5,6 +5,7 @@ https://developers.home-assistant.io/docs/core/integration-quality-scale/rules/d
|
|||||||
|
|
||||||
import ast
|
import ast
|
||||||
|
|
||||||
|
from script.hassfest import ast_parse_module
|
||||||
from script.hassfest.model import Integration
|
from script.hassfest.model import Integration
|
||||||
|
|
||||||
DIAGNOSTICS_FUNCTIONS = {
|
DIAGNOSTICS_FUNCTIONS = {
|
||||||
@ -31,7 +32,7 @@ def validate(integration: Integration) -> list[str] | None:
|
|||||||
"(is missing diagnostics.py)",
|
"(is missing diagnostics.py)",
|
||||||
]
|
]
|
||||||
|
|
||||||
diagnostics = ast.parse(diagnostics_file.read_text())
|
diagnostics = ast_parse_module(diagnostics_file)
|
||||||
|
|
||||||
if not _has_diagnostics_function(diagnostics):
|
if not _has_diagnostics_function(diagnostics):
|
||||||
return [
|
return [
|
||||||
|
@ -5,6 +5,7 @@ https://developers.home-assistant.io/docs/core/integration-quality-scale/rules/d
|
|||||||
|
|
||||||
import ast
|
import ast
|
||||||
|
|
||||||
|
from script.hassfest import ast_parse_module
|
||||||
from script.hassfest.model import Integration
|
from script.hassfest.model import Integration
|
||||||
|
|
||||||
MANIFEST_KEYS = [
|
MANIFEST_KEYS = [
|
||||||
@ -49,7 +50,7 @@ def validate(integration: Integration) -> list[str] | None:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
# Fallback => check config_flow step
|
# Fallback => check config_flow step
|
||||||
config_flow = ast.parse(config_flow_file.read_text())
|
config_flow = ast_parse_module(config_flow_file)
|
||||||
if not (_has_discovery_function(config_flow)):
|
if not (_has_discovery_function(config_flow)):
|
||||||
return [
|
return [
|
||||||
f"Integration is missing one of {CONFIG_FLOW_STEPS} "
|
f"Integration is missing one of {CONFIG_FLOW_STEPS} "
|
||||||
|
@ -5,6 +5,7 @@ https://developers.home-assistant.io/docs/core/integration-quality-scale/rules/r
|
|||||||
|
|
||||||
import ast
|
import ast
|
||||||
|
|
||||||
|
from script.hassfest import ast_parse_module
|
||||||
from script.hassfest.model import Integration
|
from script.hassfest.model import Integration
|
||||||
|
|
||||||
|
|
||||||
@ -20,7 +21,7 @@ def validate(integration: Integration) -> list[str] | None:
|
|||||||
"""Validate that the integration has a reauthentication flow."""
|
"""Validate that the integration has a reauthentication flow."""
|
||||||
|
|
||||||
config_flow_file = integration.path / "config_flow.py"
|
config_flow_file = integration.path / "config_flow.py"
|
||||||
config_flow = ast.parse(config_flow_file.read_text())
|
config_flow = ast_parse_module(config_flow_file)
|
||||||
|
|
||||||
if not _has_step_reauth_function(config_flow):
|
if not _has_step_reauth_function(config_flow):
|
||||||
return [
|
return [
|
||||||
|
@ -5,6 +5,7 @@ https://developers.home-assistant.io/docs/core/integration-quality-scale/rules/r
|
|||||||
|
|
||||||
import ast
|
import ast
|
||||||
|
|
||||||
|
from script.hassfest import ast_parse_module
|
||||||
from script.hassfest.model import Integration
|
from script.hassfest.model import Integration
|
||||||
|
|
||||||
|
|
||||||
@ -20,7 +21,7 @@ def validate(integration: Integration) -> list[str] | None:
|
|||||||
"""Validate that the integration has a reconfiguration flow."""
|
"""Validate that the integration has a reconfiguration flow."""
|
||||||
|
|
||||||
config_flow_file = integration.path / "config_flow.py"
|
config_flow_file = integration.path / "config_flow.py"
|
||||||
config_flow = ast.parse(config_flow_file.read_text())
|
config_flow = ast_parse_module(config_flow_file)
|
||||||
|
|
||||||
if not _has_step_reconfigure_function(config_flow):
|
if not _has_step_reconfigure_function(config_flow):
|
||||||
return [
|
return [
|
||||||
|
@ -5,6 +5,7 @@ https://developers.home-assistant.io/docs/core/integration-quality-scale/rules/r
|
|||||||
|
|
||||||
import ast
|
import ast
|
||||||
|
|
||||||
|
from script.hassfest import ast_parse_module
|
||||||
from script.hassfest.model import Integration
|
from script.hassfest.model import Integration
|
||||||
|
|
||||||
|
|
||||||
@ -35,7 +36,7 @@ def _get_setup_entry_function(module: ast.Module) -> ast.AsyncFunctionDef | None
|
|||||||
def validate(integration: Integration) -> list[str] | None:
|
def validate(integration: Integration) -> list[str] | None:
|
||||||
"""Validate correct use of ConfigEntry.runtime_data."""
|
"""Validate correct use of ConfigEntry.runtime_data."""
|
||||||
init_file = integration.path / "__init__.py"
|
init_file = integration.path / "__init__.py"
|
||||||
init = ast.parse(init_file.read_text())
|
init = ast_parse_module(init_file)
|
||||||
|
|
||||||
# Should not happen, but better to be safe
|
# Should not happen, but better to be safe
|
||||||
if not (async_setup_entry := _get_setup_entry_function(init)):
|
if not (async_setup_entry := _get_setup_entry_function(init)):
|
||||||
|
@ -5,6 +5,7 @@ https://developers.home-assistant.io/docs/core/integration-quality-scale/rules/u
|
|||||||
|
|
||||||
import ast
|
import ast
|
||||||
|
|
||||||
|
from script.hassfest import ast_parse_module
|
||||||
from script.hassfest.model import Integration
|
from script.hassfest.model import Integration
|
||||||
|
|
||||||
|
|
||||||
@ -36,7 +37,7 @@ def validate(integration: Integration) -> list[str] | None:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
config_flow_file = integration.path / "config_flow.py"
|
config_flow_file = integration.path / "config_flow.py"
|
||||||
config_flow = ast.parse(config_flow_file.read_text())
|
config_flow = ast_parse_module(config_flow_file)
|
||||||
|
|
||||||
if not (
|
if not (
|
||||||
_has_abort_entries_match(config_flow)
|
_has_abort_entries_match(config_flow)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user