summaryrefslogtreecommitdiff
path: root/pylint/checkers/utils.py
diff options
context:
space:
mode:
Diffstat (limited to 'pylint/checkers/utils.py')
-rw-r--r--pylint/checkers/utils.py45
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