diff -r c8854a6300d1 -r 65b7354b0d4c src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Annotations/AnnotationsDeprecationsVisitor.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Annotations/AnnotationsDeprecationsVisitor.py Thu Jun 01 11:44:06 2023 +0200 @@ -0,0 +1,203 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2023 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a node visitor for checking the use of deprecated 'typing' symbols. +""" + +# +# The visitors are adapted and extended variants of the ones found in +# flake8-pep585 v0.1.7 +# + +import ast + + +class AnnotationsDeprecationsVisitor(ast.NodeVisitor): + """ + Class implementing a node visitor for checking the use of deprecated 'typing' + symbols. + """ + + NameReplacements = { + "Tuple": "tuple", + "List": "list", + "Dict": "dict", + "Set": "set", + "FrozenSet": "frozenset", + "Type": "type", + "Deque": "collections.deque", + "DefaultDict": "collections.defaultdict", + "OrderedDict": "collections.OrderedDict", + "Counter": "collections.Counter", + "ChainMap": "collections.ChainMap", + "Awaitable": "collections.abc.Awaitable", + "Coroutine": "collections.abc.Coroutine", + "AsyncIterable": "collections.abc.AsyncIterable", + "AsyncIterator": "collections.abc.AsyncIterator", + "AsyncGenerator": "collections.abc.AsyncGenerator", + "Iterable": "collections.abc.Iterable", + "Iterator": "collections.abc.Iterator", + "Generator": "collections.abc.Generator", + "Reversible": "collections.abc.Reversible", + "Container": "collections.abc.Container", + "Collection": "collections.abc.Collection", + "Callable": "collections.abc.Callable", + "AbstractSet": "collections.abc.Set", + "MutableSet": "collections.abc.MutableSet", + "Mapping": "collections.abc.Mapping", + "MutableMapping": "collections.abc.MutableMapping", + "Sequence": "collections.abc.Sequence", + "MutableSequence": "collections.abc.MutableSequence", + "ByteString": "collections.abc.ByteString", + "MappingView": "collections.abc.MappingView", + "KeysView": "collections.abc.KeysView", + "ItemsView": "collections.abc.ItemsView", + "ValuesView": "collections.abc.ValuesView", + "ContextManager": "contextlib.AbstractContextManager", + "AsyncContextManager": "contextlib.AbstractAsyncContextManager", + "Pattern": "re.Pattern", + "Match": "re.Match", + } + + def __init__(self, exemptedList): + """ + Constructor + + @param exemptedList list of typing symbols exempted from checking + @type list of str + """ + self.__exemptedList = exemptedList[:] + self.__typingAliases = set() + + self.__issues = [] + + def getIssues(self): + """ + Public method to get the list of detected issues. + + @return list of detected issues consisting of a tuple of a reference to the node + and a tuple containing the used name and the suggested replacement + @rtype list of tuples of (ast.AST, (str, str)) + """ + return self.__issues + + def __checkDeprecation(self, node, name): + """ + Private method to check, if the given name is deprecated. + + @param node reference to the node + @type ast.ImportFrom, ast.Attribute + @param name name to be checked + @type str + """ + if name not in self.__exemptedList: + replacement = self.NameReplacements.get(name) + if replacement is not None: + self.__issues.append((node, (name, replacement))) + + def visit_ImportFrom(self, node): + """ + Public method to handle an ast.ImportFrom node. + + @param node reference to the node to be handled + @type ast.ImportFrom + """ + if node.module == "typing": + for alias in node.names: + self.__checkDeprecation(node, alias.name) + + def visit_Import(self, node): + """ + Public method to handle an ast.Import node. + + @param node reference to the node to be handled + @type ast.Import + """ + for alias in node.names: + if alias.name == "typing": + self.__typingAliases.add(alias.asname or "typing") + + def visit_Attribute(self, node): + """ + Public method to handle an ast.Attribute node. + + @param node reference to the node to be handled + @type ast.Attribute + """ + if ( + isinstance(node.value, ast.Name) + and node.value.id in self.__typingAliases + and node.attr not in self.__exemptedList + ): + self.__checkDeprecation(node, node.attr) + + def visit_AnnAssign(self, node): + """ + Public method to handle an ast.AnnAssign node. + + @param node reference to the node to be handled + @type ast.AnnAssign + """ + if isinstance(node.annotation, ast.Name): + self.__checkDeprecation(node, node.annotation.id) + elif isinstance(node.annotation, ast.Subscript) and isinstance( + node.annotation.value, ast.Name + ): + self.__checkDeprecation(node, node.annotation.value.id) + + def visit_FunctionDef(self, node): + """ + Public method to handle an ast.FunctionDef or ast.AsyncFunctionDef node. + + @param node reference to the node to be handled + @type ast.FunctionDef or ast.AsyncFunctionDef + """ + for arg in node.args.args + node.args.posonlyargs + node.args.kwonlyargs: + if isinstance(arg.annotation, ast.Name): + self.__checkDeprecation(arg, arg.annotation.id) + elif isinstance(arg.annotation, ast.Subscript) and isinstance( + arg.annotation.value, ast.Name + ): + self.__checkDeprecation(arg, arg.annotation.value.id) + + visit_AsyncFunctionDef = visit_FunctionDef + + +class AnnotationsFutureImportVisitor(ast.NodeVisitor): + """ + Class implementing a node visitor to dtermine, if the annotations __future__ + import is present. + + This class is used to determine usage of annotations for Python 3.8. + """ + + def __init__(self): + """ + Constructor + """ + self.__futureImport = False + + def futureImportPresent(self): + """ + Public method to check, if a 'from __future__ import annotations' statement + exists. + + @return flag indicating the existence of the import statement + @rtype bool + """ + return self.__futureImport + + def visit_ImportFrom(self, node): + """ + Public method to handle an ast.ImportFrom node. + + @param node reference to the node to be handled + @type ast.ImportFrom + """ + if node.module == "__future__" and "annotations" in { + alias.name for alias in node.names + }: + self.__futureImport = True