From 2062e49ae16d6aed555763a9fd2031e8bcc7984e Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Fri, 20 Sep 2024 11:10:27 +0200 Subject: [PATCH] Improve readability in hass_imports pylint plugin (#126252) * Improve readability in hass_imports pylint plugin * One more * docstring * docstring --- pylint/plugins/hass_imports.py | 143 ++++++++++++++++++++++++--------- 1 file changed, 104 insertions(+), 39 deletions(-) diff --git a/pylint/plugins/hass_imports.py b/pylint/plugins/hass_imports.py index f7713daabe8..eacabc5b700 100644 --- a/pylint/plugins/hass_imports.py +++ b/pylint/plugins/hass_imports.py @@ -548,6 +548,85 @@ class HassImportsFormatChecker(BaseChecker): if len(split_package) < node.level + 2: self.add_message("hass-absolute-import", node=node) + def _check_for_constant_alias( + self, + node: nodes.ImportFrom, + current_component: str | None, + imported_component: str, + ) -> bool: + """Check for hass-import-constant-alias.""" + if current_component == imported_component: + return True + + # Check for `from homeassistant.components.other import DOMAIN` + for name, alias in node.names: + if name == "DOMAIN" and (alias is None or alias == "DOMAIN"): + self.add_message( + "hass-import-constant-alias", + node=node, + args=( + "DOMAIN", + "DOMAIN", + f"{imported_component.upper()}_DOMAIN", + ), + ) + return False + + return True + + def _check_for_component_root_import( + self, + node: nodes.ImportFrom, + current_component: str | None, + imported_parts: list[str], + imported_component: str, + ) -> bool: + """Check for hass-component-root-import.""" + if ( + current_component == imported_component + or imported_component in _IGNORE_ROOT_IMPORT + ): + return True + + # Check for `from homeassistant.components.other.module import something` + if len(imported_parts) > 3: + self.add_message("hass-component-root-import", node=node) + return False + + # Check for `from homeassistant.components.other import const` + for name, _ in node.names: + if name == "const": + self.add_message("hass-component-root-import", node=node) + return False + + return True + + def _check_for_relative_import( + self, + current_package: str, + node: nodes.ImportFrom, + current_component: str | None, + ) -> bool: + """Check for hass-relative-import.""" + if node.modname == current_package or node.modname.startswith( + f"{current_package}." + ): + self.add_message("hass-relative-import", node=node) + return False + + for root in ("homeassistant", "tests"): + if current_package.startswith(f"{root}.components."): + if node.modname == f"{root}.components": + for name in node.names: + if name[0] == current_component: + self.add_message("hass-relative-import", node=node) + return False + elif node.modname.startswith(f"{root}.components.{current_component}."): + self.add_message("hass-relative-import", node=node) + return False + + return True + def visit_importfrom(self, node: nodes.ImportFrom) -> None: """Check for improper 'from _ import _' invocations.""" if not self.current_package: @@ -555,52 +634,36 @@ class HassImportsFormatChecker(BaseChecker): if node.level is not None: self._visit_importfrom_relative(self.current_package, node) return - if node.modname == self.current_package or node.modname.startswith( - f"{self.current_package}." - ): - self.add_message("hass-relative-import", node=node) - return + + # Cache current component + current_component: str | None = None for root in ("homeassistant", "tests"): if self.current_package.startswith(f"{root}.components."): current_component = self.current_package.split(".")[2] - if node.modname == f"{root}.components": - for name in node.names: - if name[0] == current_component: - self.add_message("hass-relative-import", node=node) - return - if node.modname.startswith(f"{root}.components.{current_component}."): - self.add_message("hass-relative-import", node=node) - return - if ( - node.modname.startswith("homeassistant.components.") - and (module_parts := node.modname.split(".")) - and (module_integration := module_parts[2]) - and module_integration not in _IGNORE_ROOT_IMPORT - and not ( - self.current_package.startswith("tests.components.") - and self.current_package.split(".")[2] == module_integration - ) + # Checks for hass-relative-import + if not self._check_for_relative_import( + self.current_package, node, current_component ): - if len(module_parts) > 3: - self.add_message("hass-component-root-import", node=node) + return + + if node.modname.startswith("homeassistant.components."): + imported_parts = node.modname.split(".") + imported_component = imported_parts[2] + + # Checks for hass-component-root-import + if not self._check_for_component_root_import( + node, current_component, imported_parts, imported_component + ): + return + + # Checks for hass-import-constant-alias + if not self._check_for_constant_alias( + node, current_component, imported_component + ): return - for name, alias in node.names: - if name == "const": - self.add_message("hass-component-root-import", node=node) - return - if name == "DOMAIN" and (alias is None or alias == "DOMAIN"): - self.add_message( - "hass-import-constant-alias", - node=node, - args=( - "DOMAIN", - "DOMAIN", - f"{node.modname.split(".")[2].upper()}_DOMAIN", - ), - ) - return + # Checks for hass-deprecated-import if obsolete_imports := _OBSOLETE_IMPORT.get(node.modname): for name_tuple in node.names: for obsolete_import in obsolete_imports: @@ -610,6 +673,8 @@ class HassImportsFormatChecker(BaseChecker): node=node, args=(import_match.string, obsolete_import.reason), ) + + # Checks for hass-helper-namespace-import if namespace_alias := _FORCE_NAMESPACE_IMPORT.get(node.modname): for name in node.names: if name[0] in namespace_alias.names: -- GitLab