"""Validate dependencies.""" import pathlib import re from typing import Set, Dict from .model import Integration def grep_dir(path: pathlib.Path, glob_pattern: str, search_pattern: str) -> Set[str]: """Recursively go through a dir and it's children and find the regex.""" pattern = re.compile(search_pattern) found = set() for fil in path.glob(glob_pattern): if not fil.is_file(): continue for match in pattern.finditer(fil.read_text()): found.add(match.groups()[0]) return found ALLOWED_USED_COMPONENTS = { # This component will always be set up "persistent_notification", # These allow to register things without being set up "conversation", "frontend", "hassio", "system_health", "websocket_api", } def validate_dependencies(integration: Integration): """Validate all dependencies.""" # Find usage of hass.components referenced = grep_dir(integration.path, "**/*.py", r"hass\.components\.(\w+)") referenced -= ALLOWED_USED_COMPONENTS referenced -= set(integration.manifest["dependencies"]) referenced -= set(integration.manifest.get("after_dependencies", [])) if referenced: for domain in sorted(referenced): print( "Warning: {} references integration {} but it's not a " "dependency".format(integration.domain, domain) ) # Not enforced yet. # integration.add_error( # 'dependencies', # "Using component {} but it's not a dependency".format(domain) # ) def validate(integrations: Dict[str, Integration], config): """Handle dependencies for integrations.""" # check for non-existing dependencies for integration in integrations.values(): if not integration.manifest: continue validate_dependencies(integration) # check that all referenced dependencies exist for dep in integration.manifest["dependencies"]: if dep not in integrations: integration.add_error( "dependencies", "Dependency {} does not exist".format(dep) )