diff options
Diffstat (limited to 'pylint/checkers/utils.py')
-rw-r--r-- | pylint/checkers/utils.py | 45 |
1 files changed, 44 insertions, 1 deletions
diff --git a/pylint/checkers/utils.py b/pylint/checkers/utils.py index f5b4f42a5..cff791364 100644 --- a/pylint/checkers/utils.py +++ b/pylint/checkers/utils.py @@ -822,7 +822,9 @@ def _is_property_decorator(decorator: nodes.Name) -> bool: def decorated_with( - func: Union[nodes.FunctionDef, astroid.BoundMethod, astroid.UnboundMethod], + func: Union[ + nodes.ClassDef, nodes.FunctionDef, astroid.BoundMethod, astroid.UnboundMethod + ], qnames: Iterable[str], ) -> bool: """Determine if the `func` node has a decorator with the qualified name `qname`.""" @@ -843,6 +845,47 @@ def decorated_with( return False +def uninferable_final_decorators( + node: nodes.Decorators, +) -> List[Optional[Union[nodes.Attribute, nodes.Name]]]: + """Return a list of uninferable `typing.final` decorators in `node`. + + This function is used to determine if the `typing.final` decorator is used + with an unsupported Python version; the decorator cannot be inferred when + using a Python version lower than 3.8. + """ + decorators = [] + for decorator in getattr(node, "nodes", []): + if isinstance(decorator, nodes.Attribute): + try: + import_node = decorator.expr.lookup(decorator.expr.name)[1][0] + except AttributeError: + continue + elif isinstance(decorator, nodes.Name): + import_node = decorator.lookup(decorator.name)[1][0] + else: + continue + + if not isinstance(import_node, (astroid.Import, astroid.ImportFrom)): + continue + + import_names = dict(import_node.names) + + # from typing import final + is_from_import = ("final" in import_names) and import_node.modname == "typing" + # import typing + is_import = ("typing" in import_names) and getattr( + decorator, "attrname", None + ) == "final" + + if (is_from_import or is_import) and safe_infer(decorator) in [ + astroid.Uninferable, + None, + ]: + decorators.append(decorator) + return decorators + + @lru_cache(maxsize=1024) def unimplemented_abstract_methods( node: nodes.ClassDef, is_abstract_cb: nodes.FunctionDef = None |