Adjust astroid import in pylint plugin (#72841)

* import nodes from astroid

* Update remaining pylint plugins

Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com>
This commit is contained in:
epenet 2022-06-02 07:48:59 +02:00 committed by GitHub
parent f79e5e002b
commit 999b3a4f7b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 39 additions and 35 deletions

View file

@ -1,5 +1,7 @@
"""Plugin for constructor definitions.""" """Plugin for constructor definitions."""
from astroid import Const, FunctionDef from __future__ import annotations
from astroid import nodes
from pylint.checkers import BaseChecker from pylint.checkers import BaseChecker
from pylint.interfaces import IAstroidChecker from pylint.interfaces import IAstroidChecker
from pylint.lint import PyLinter from pylint.lint import PyLinter
@ -22,7 +24,7 @@ class HassConstructorFormatChecker(BaseChecker): # type: ignore[misc]
} }
options = () options = ()
def visit_functiondef(self, node: FunctionDef) -> None: def visit_functiondef(self, node: nodes.FunctionDef) -> None:
"""Called when a FunctionDef node is visited.""" """Called when a FunctionDef node is visited."""
if not node.is_method() or node.name != "__init__": if not node.is_method() or node.name != "__init__":
return return
@ -43,7 +45,7 @@ class HassConstructorFormatChecker(BaseChecker): # type: ignore[misc]
return return
# Check that return type is specified and it is "None". # Check that return type is specified and it is "None".
if not isinstance(node.returns, Const) or node.returns.value is not None: if not isinstance(node.returns, nodes.Const) or node.returns.value is not None:
self.add_message("hass-constructor-return", node=node) self.add_message("hass-constructor-return", node=node)

View file

@ -4,7 +4,7 @@ from __future__ import annotations
from dataclasses import dataclass from dataclasses import dataclass
import re import re
import astroid from astroid import nodes
from pylint.checkers import BaseChecker from pylint.checkers import BaseChecker
from pylint.interfaces import IAstroidChecker from pylint.interfaces import IAstroidChecker
from pylint.lint import PyLinter from pylint.lint import PyLinter
@ -437,7 +437,7 @@ _CLASS_MATCH: dict[str, list[ClassTypeHintMatch]] = {
def _is_valid_type( def _is_valid_type(
expected_type: list[str] | str | None | object, node: astroid.NodeNG expected_type: list[str] | str | None | object, node: nodes.NodeNG
) -> bool: ) -> bool:
"""Check the argument node against the expected type.""" """Check the argument node against the expected type."""
if expected_type is UNDEFINED: if expected_type is UNDEFINED:
@ -451,18 +451,18 @@ def _is_valid_type(
# Const occurs when the type is None # Const occurs when the type is None
if expected_type is None or expected_type == "None": if expected_type is None or expected_type == "None":
return isinstance(node, astroid.Const) and node.value is None return isinstance(node, nodes.Const) and node.value is None
assert isinstance(expected_type, str) assert isinstance(expected_type, str)
# Const occurs when the type is an Ellipsis # Const occurs when the type is an Ellipsis
if expected_type == "...": if expected_type == "...":
return isinstance(node, astroid.Const) and node.value == Ellipsis return isinstance(node, nodes.Const) and node.value == Ellipsis
# Special case for `xxx | yyy` # Special case for `xxx | yyy`
if match := _TYPE_HINT_MATCHERS["a_or_b"].match(expected_type): if match := _TYPE_HINT_MATCHERS["a_or_b"].match(expected_type):
return ( return (
isinstance(node, astroid.BinOp) isinstance(node, nodes.BinOp)
and _is_valid_type(match.group(1), node.left) and _is_valid_type(match.group(1), node.left)
and _is_valid_type(match.group(2), node.right) and _is_valid_type(match.group(2), node.right)
) )
@ -470,11 +470,11 @@ def _is_valid_type(
# Special case for xxx[yyy[zzz, aaa]]` # Special case for xxx[yyy[zzz, aaa]]`
if match := _TYPE_HINT_MATCHERS["x_of_y_of_z_comma_a"].match(expected_type): if match := _TYPE_HINT_MATCHERS["x_of_y_of_z_comma_a"].match(expected_type):
return ( return (
isinstance(node, astroid.Subscript) isinstance(node, nodes.Subscript)
and _is_valid_type(match.group(1), node.value) and _is_valid_type(match.group(1), node.value)
and isinstance(subnode := node.slice, astroid.Subscript) and isinstance(subnode := node.slice, nodes.Subscript)
and _is_valid_type(match.group(2), subnode.value) and _is_valid_type(match.group(2), subnode.value)
and isinstance(subnode.slice, astroid.Tuple) and isinstance(subnode.slice, nodes.Tuple)
and _is_valid_type(match.group(3), subnode.slice.elts[0]) and _is_valid_type(match.group(3), subnode.slice.elts[0])
and _is_valid_type(match.group(4), subnode.slice.elts[1]) and _is_valid_type(match.group(4), subnode.slice.elts[1])
) )
@ -482,9 +482,9 @@ def _is_valid_type(
# Special case for xxx[yyy, zzz]` # Special case for xxx[yyy, zzz]`
if match := _TYPE_HINT_MATCHERS["x_of_y_comma_z"].match(expected_type): if match := _TYPE_HINT_MATCHERS["x_of_y_comma_z"].match(expected_type):
return ( return (
isinstance(node, astroid.Subscript) isinstance(node, nodes.Subscript)
and _is_valid_type(match.group(1), node.value) and _is_valid_type(match.group(1), node.value)
and isinstance(node.slice, astroid.Tuple) and isinstance(node.slice, nodes.Tuple)
and _is_valid_type(match.group(2), node.slice.elts[0]) and _is_valid_type(match.group(2), node.slice.elts[0])
and _is_valid_type(match.group(3), node.slice.elts[1]) and _is_valid_type(match.group(3), node.slice.elts[1])
) )
@ -492,22 +492,22 @@ def _is_valid_type(
# Special case for xxx[yyy]` # Special case for xxx[yyy]`
if match := _TYPE_HINT_MATCHERS["x_of_y"].match(expected_type): if match := _TYPE_HINT_MATCHERS["x_of_y"].match(expected_type):
return ( return (
isinstance(node, astroid.Subscript) isinstance(node, nodes.Subscript)
and _is_valid_type(match.group(1), node.value) and _is_valid_type(match.group(1), node.value)
and _is_valid_type(match.group(2), node.slice) and _is_valid_type(match.group(2), node.slice)
) )
# Name occurs when a namespace is not used, eg. "HomeAssistant" # Name occurs when a namespace is not used, eg. "HomeAssistant"
if isinstance(node, astroid.Name) and node.name == expected_type: if isinstance(node, nodes.Name) and node.name == expected_type:
return True return True
# Attribute occurs when a namespace is used, eg. "core.HomeAssistant" # Attribute occurs when a namespace is used, eg. "core.HomeAssistant"
return isinstance(node, astroid.Attribute) and node.attrname == expected_type return isinstance(node, nodes.Attribute) and node.attrname == expected_type
def _get_all_annotations(node: astroid.FunctionDef) -> list[astroid.NodeNG | None]: def _get_all_annotations(node: nodes.FunctionDef) -> list[nodes.NodeNG | None]:
args = node.args args = node.args
annotations: list[astroid.NodeNG | None] = ( annotations: list[nodes.NodeNG | None] = (
args.posonlyargs_annotations + args.annotations + args.kwonlyargs_annotations args.posonlyargs_annotations + args.annotations + args.kwonlyargs_annotations
) )
if args.vararg is not None: if args.vararg is not None:
@ -518,7 +518,7 @@ def _get_all_annotations(node: astroid.FunctionDef) -> list[astroid.NodeNG | Non
def _has_valid_annotations( def _has_valid_annotations(
annotations: list[astroid.NodeNG | None], annotations: list[nodes.NodeNG | None],
) -> bool: ) -> bool:
for annotation in annotations: for annotation in annotations:
if annotation is not None: if annotation is not None:
@ -563,7 +563,7 @@ class HassTypeHintChecker(BaseChecker): # type: ignore[misc]
self._function_matchers: list[TypeHintMatch] = [] self._function_matchers: list[TypeHintMatch] = []
self._class_matchers: list[ClassTypeHintMatch] = [] self._class_matchers: list[ClassTypeHintMatch] = []
def visit_module(self, node: astroid.Module) -> None: def visit_module(self, node: nodes.Module) -> None:
"""Called when a Module node is visited.""" """Called when a Module node is visited."""
self._function_matchers = [] self._function_matchers = []
self._class_matchers = [] self._class_matchers = []
@ -580,16 +580,16 @@ class HassTypeHintChecker(BaseChecker): # type: ignore[misc]
if class_matches := _CLASS_MATCH.get(module_platform): if class_matches := _CLASS_MATCH.get(module_platform):
self._class_matchers = class_matches self._class_matchers = class_matches
def visit_classdef(self, node: astroid.ClassDef) -> None: def visit_classdef(self, node: nodes.ClassDef) -> None:
"""Called when a ClassDef node is visited.""" """Called when a ClassDef node is visited."""
ancestor: astroid.ClassDef ancestor: nodes.ClassDef
for ancestor in node.ancestors(): for ancestor in node.ancestors():
for class_matches in self._class_matchers: for class_matches in self._class_matchers:
if ancestor.name == class_matches.base_class: if ancestor.name == class_matches.base_class:
self._visit_class_functions(node, class_matches.matches) self._visit_class_functions(node, class_matches.matches)
def _visit_class_functions( def _visit_class_functions(
self, node: astroid.ClassDef, matches: list[TypeHintMatch] self, node: nodes.ClassDef, matches: list[TypeHintMatch]
) -> None: ) -> None:
for match in matches: for match in matches:
for function_node in node.mymethods(): for function_node in node.mymethods():
@ -597,7 +597,7 @@ class HassTypeHintChecker(BaseChecker): # type: ignore[misc]
if match.function_name == function_name: if match.function_name == function_name:
self._check_function(function_node, match) self._check_function(function_node, match)
def visit_functiondef(self, node: astroid.FunctionDef) -> None: def visit_functiondef(self, node: nodes.FunctionDef) -> None:
"""Called when a FunctionDef node is visited.""" """Called when a FunctionDef node is visited."""
for match in self._function_matchers: for match in self._function_matchers:
if node.name != match.function_name or node.is_method(): if node.name != match.function_name or node.is_method():
@ -606,7 +606,7 @@ class HassTypeHintChecker(BaseChecker): # type: ignore[misc]
visit_asyncfunctiondef = visit_functiondef visit_asyncfunctiondef = visit_functiondef
def _check_function(self, node: astroid.FunctionDef, match: TypeHintMatch) -> None: def _check_function(self, node: nodes.FunctionDef, match: TypeHintMatch) -> None:
# Check that at least one argument is annotated. # Check that at least one argument is annotated.
annotations = _get_all_annotations(node) annotations = _get_all_annotations(node)
if node.returns is None and not _has_valid_annotations(annotations): if node.returns is None and not _has_valid_annotations(annotations):

View file

@ -4,7 +4,7 @@ from __future__ import annotations
from dataclasses import dataclass from dataclasses import dataclass
import re import re
from astroid import Import, ImportFrom, Module from astroid import nodes
from pylint.checkers import BaseChecker from pylint.checkers import BaseChecker
from pylint.interfaces import IAstroidChecker from pylint.interfaces import IAstroidChecker
from pylint.lint import PyLinter from pylint.lint import PyLinter
@ -14,7 +14,7 @@ from pylint.lint import PyLinter
class ObsoleteImportMatch: class ObsoleteImportMatch:
"""Class for pattern matching.""" """Class for pattern matching."""
constant: re.Pattern constant: re.Pattern[str]
reason: str reason: str
@ -255,7 +255,7 @@ class HassImportsFormatChecker(BaseChecker): # type: ignore[misc]
super().__init__(linter) super().__init__(linter)
self.current_package: str | None = None self.current_package: str | None = None
def visit_module(self, node: Module) -> None: def visit_module(self, node: nodes.Module) -> None:
"""Called when a Module node is visited.""" """Called when a Module node is visited."""
if node.package: if node.package:
self.current_package = node.name self.current_package = node.name
@ -263,13 +263,13 @@ class HassImportsFormatChecker(BaseChecker): # type: ignore[misc]
# Strip name of the current module # Strip name of the current module
self.current_package = node.name[: node.name.rfind(".")] self.current_package = node.name[: node.name.rfind(".")]
def visit_import(self, node: Import) -> None: def visit_import(self, node: nodes.Import) -> None:
"""Called when a Import node is visited.""" """Called when a Import node is visited."""
for module, _alias in node.names: for module, _alias in node.names:
if module.startswith(f"{self.current_package}."): if module.startswith(f"{self.current_package}."):
self.add_message("hass-relative-import", node=node) self.add_message("hass-relative-import", node=node)
def visit_importfrom(self, node: ImportFrom) -> None: def visit_importfrom(self, node: nodes.ImportFrom) -> None:
"""Called when a ImportFrom node is visited.""" """Called when a ImportFrom node is visited."""
if node.level is not None: if node.level is not None:
return return

View file

@ -1,5 +1,7 @@
"""Plugin for logger invocations.""" """Plugin for logger invocations."""
import astroid from __future__ import annotations
from astroid import nodes
from pylint.checkers import BaseChecker from pylint.checkers import BaseChecker
from pylint.interfaces import IAstroidChecker from pylint.interfaces import IAstroidChecker
from pylint.lint import PyLinter from pylint.lint import PyLinter
@ -29,10 +31,10 @@ class HassLoggerFormatChecker(BaseChecker): # type: ignore[misc]
} }
options = () options = ()
def visit_call(self, node: astroid.Call) -> None: def visit_call(self, node: nodes.Call) -> None:
"""Called when a Call node is visited.""" """Called when a Call node is visited."""
if not isinstance(node.func, astroid.Attribute) or not isinstance( if not isinstance(node.func, nodes.Attribute) or not isinstance(
node.func.expr, astroid.Name node.func.expr, nodes.Name
): ):
return return
@ -44,7 +46,7 @@ class HassLoggerFormatChecker(BaseChecker): # type: ignore[misc]
first_arg = node.args[0] first_arg = node.args[0]
if not isinstance(first_arg, astroid.Const) or not first_arg.value: if not isinstance(first_arg, nodes.Const) or not first_arg.value:
return return
log_message = first_arg.value log_message = first_arg.value