Tue, 29 Aug 2023 16:55:18 +0200
Made some modification in preparation for Python 3.12.
--- a/src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Annotations/AnnotationsChecker.py Tue Aug 29 16:55:01 2023 +0200 +++ b/src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Annotations/AnnotationsChecker.py Tue Aug 29 16:55:18 2023 +0200 @@ -570,7 +570,7 @@ """ if AstUtilities.isString(annotationNode): try: - annotationNode = ast.parse(annotationNode.s).body[0].value + annotationNode = ast.parse(annotationNode.value).body[0].value except (IndexError, SyntaxError): return defaultComplexity @@ -606,7 +606,7 @@ annotationLength = 0 if AstUtilities.isString(annotationNode): try: - annotationNode = ast.parse(annotationNode.s).body[0].value + annotationNode = ast.parse(annotationNode.value).body[0].value except (IndexError, SyntaxError): return annotationLength
--- a/src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Annotations/AnnotationsFunctionVisitor.py Tue Aug 29 16:55:01 2023 +0200 +++ b/src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Annotations/AnnotationsFunctionVisitor.py Tue Aug 29 16:55:18 2023 +0200 @@ -571,11 +571,10 @@ """ if node.value is not None: # In the event of an explicit `None` return (`return None`), the - # node body will be an instance of either `ast.Constant` (3.8+) or - # `ast.NameConstant`, which we need to check to see if it's - # actually `None` + # node body will be an instance `ast.Constant` (3.8+), which we + # need to check to see if it's actually `None` if ( - isinstance(node.value, (ast.Constant, ast.NameConstant)) + isinstance(node.value, ast.Constant) and node.value.value is None ): return
--- a/src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Miscellaneous/MiscellaneousChecker.py Tue Aug 29 16:55:01 2023 +0200 +++ b/src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Miscellaneous/MiscellaneousChecker.py Tue Aug 29 16:55:18 2023 +0200 @@ -662,7 +662,7 @@ visitor = TextVisitor() visitor.visit(self.__tree) for node in visitor.nodes: - text = node.s + text = node.value if isinstance(text, bytes): try: text = text.decode(coding) @@ -943,13 +943,11 @@ for kw in node.args[0].keywords: if kw.arg != "reverse": continue - if isinstance(kw.value, ast.NameConstant): - reverseFlagValue = kw.value.value - elif isinstance(kw.value, ast.Num): - reverseFlagValue = bool(kw.value.n) - else: - # Complex value - reverseFlagValue = None + reverseFlagValue = ( + bool(kw.value.value) + if isinstance(kw.value, ast.Constant) + else None + ) if reverseFlagValue is None: self.__error( @@ -1011,7 +1009,7 @@ and node.args[0].slice.upper is None and isinstance(node.args[0].slice.step, ast.UnaryOp) and isinstance(node.args[0].slice.step.op, ast.USub) - and isinstance(node.args[0].slice.step.operand, ast.Num) + and isinstance(node.args[0].slice.step.operand, ast.Constant) and node.args[0].slice.step.operand.n == 1 ): self.__error(node.lineno - 1, node.col_offset, "M189", node.func.id) @@ -1135,9 +1133,13 @@ for node in ast.walk(self.__tree): if isinstance(node, ast.Dict) and self.__dictShouldBeChecked(node): for key1, key2 in zip(node.keys, node.keys[1:]): - if key2.s < key1.s: + if key2.value < key1.value: self.__error( - key2.lineno - 1, key2.col_offset, "M201", key2.s, key1.s + key2.lineno - 1, + key2.col_offset, + "M201", + key2.value, + key1.value, ) def __checkLogging(self): @@ -1328,24 +1330,6 @@ node.is_docstring = False self.nodes.append(node) - def visit_Str(self, node): - """ - Public method to record a string node. - - @param node reference to the string node - @type ast.Str - """ - self.__addNode(node) - - def visit_Bytes(self, node): - """ - Public method to record a bytes node. - - @param node reference to the bytes node - @type ast.Bytes - """ - self.__addNode(node) - def visit_Constant(self, node): """ Public method to handle constant nodes. @@ -2017,7 +2001,7 @@ # bad getattr and setattr if ( node.func.id in ("getattr", "hasattr") - and node.args[1].s == "__call__" + and node.args[1].value == "__call__" ): self.violations.append((node, "M504")) if ( @@ -2636,8 +2620,7 @@ def emptyBody(body): def isStrOrEllipsis(node): - # ast.Ellipsis and ast.Str used in python<3.8 - return isinstance(node, (ast.Ellipsis, ast.Str)) or ( + return ( isinstance(node, ast.Constant) and (node.value is Ellipsis or isinstance(node.value, str)) )
--- a/src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/NameOrder/NameOrderChecker.py Tue Aug 29 16:55:01 2023 +0200 +++ b/src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/NameOrder/NameOrderChecker.py Tue Aug 29 16:55:18 2023 +0200 @@ -279,8 +279,6 @@ for el in node.elts: if isinstance(el, ast.Constant): actualList.append(el.value) - elif isinstance(el, ast.Str): - actualList.append(el.s) else: # Can't handle anything that isn't a string literal return None
--- a/src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/awsHardcodedPassword.py Tue Aug 29 16:55:01 2023 +0200 +++ b/src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/awsHardcodedPassword.py Tue Aug 29 16:55:18 2023 +0200 @@ -84,8 +84,8 @@ @type dict """ node = context.node - if AWS_ACCESS_KEY_ID_REGEX.fullmatch(node.s): - entropy = shannonEntropy(node.s, AWS_ACCESS_KEY_ID_SYMBOLS) + if AWS_ACCESS_KEY_ID_REGEX.fullmatch(node.value): + entropy = shannonEntropy(node.value, AWS_ACCESS_KEY_ID_SYMBOLS) if entropy > AWS_ACCESS_KEY_ID_MAX_ENTROPY: reportError( context.node.lineno - 1, @@ -93,11 +93,11 @@ "S801", "L", "M", - node.s, + node.value, ) - elif AWS_SECRET_ACCESS_KEY_REGEX.fullmatch(node.s): - entropy = shannonEntropy(node.s, AWS_SECRET_ACCESS_KEY_SYMBOLS) + elif AWS_SECRET_ACCESS_KEY_REGEX.fullmatch(node.value): + entropy = shannonEntropy(node.value, AWS_SECRET_ACCESS_KEY_SYMBOLS) if entropy > AWS_SECRET_ACCESS_KEY_MAX_ENTROPY: reportError( context.node.lineno - 1, @@ -105,5 +105,5 @@ "S802", "M", "M", - node.s, + node.value, )
--- a/src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/generalHardcodedPassword.py Tue Aug 29 16:55:01 2023 +0200 +++ b/src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/generalHardcodedPassword.py Tue Aug 29 16:55:18 2023 +0200 @@ -67,10 +67,12 @@ "S105", "L", "M", - node.s, + node.value, ) - elif isinstance(node._securityParent, ast.Index) and RE_CANDIDATES.search(node.s): + elif ( + isinstance(node._securityParent, ast.Index) and RE_CANDIDATES.search(node.value) + ): # looks for "dict[candidate]='some_string'" # assign -> subscript -> index -> string assign = node._securityParent._securityParent._securityParent @@ -81,7 +83,7 @@ "S105", "L", "M", - assign.value.s, + assign.value.value, ) elif isinstance(node._securityParent, ast.Compare): @@ -122,7 +124,7 @@ "S106", "L", "M", - kw.value.s, + kw.value.value, ) @@ -156,5 +158,5 @@ "S107", "L", "M", - val.s, + val.value, )
--- a/src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/injectionShell.py Tue Aug 29 16:55:01 2023 +0200 +++ b/src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/injectionShell.py Tue Aug 29 16:55:18 2023 +0200 @@ -80,7 +80,7 @@ if key.arg == "shell": val = key.value if AstUtilities.isNumber(val): - result = bool(val.n) + result = bool(val.value) elif isinstance(val, ast.List): result = bool(val.elts) elif isinstance(val, ast.Dict): @@ -289,7 +289,7 @@ node = node.elts[0] # make sure the param is a string literal and not a var name - if AstUtilities.isString(node) and not fullPathMatchRe.match(node.s): + if AstUtilities.isString(node) and not fullPathMatchRe.match(node.value): reportError( context.node.lineno - 1, context.node.col_offset,
--- a/src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/injectionSql.py Tue Aug 29 16:55:01 2023 +0200 +++ b/src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/injectionSql.py Tue Aug 29 16:55:18 2023 +0200 @@ -62,7 +62,7 @@ Function to analyze the given ast node. @param node ast node to be analyzed - @type ast.Str + @type ast.Constant @return tuple containing a flag indicating an execute call and the resulting statement @rtype tuple of (bool, str) @@ -78,11 +78,11 @@ isinstance(node._securityParent, ast.Attribute) and node._securityParent.attr == "format" ): - statement = node.s + statement = node.value # Hierarchy for "".format() is Wrapper -> Call -> Attribute -> Str wrapper = node._securityParent._securityParent._securityParent elif hasattr(ast, "JoinedStr") and isinstance(node._securityParent, ast.JoinedStr): - statement = node.s + statement = node.value wrapper = node._securityParent._securityParent if isinstance(wrapper, ast.Call): # wrapped in "execute" call?
--- a/src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Security/SecurityContext.py Tue Aug 29 16:55:01 2023 +0200 +++ b/src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Security/SecurityContext.py Tue Aug 29 16:55:18 2023 +0200 @@ -17,7 +17,6 @@ import ast import copy -import sys import AstUtilities @@ -220,11 +219,12 @@ @return converted Python object @rtype Any """ - if AstUtilities.isNumber(literal): - literalValue = literal.n - - elif AstUtilities.isString(literal) or AstUtilities.isBytes(literal): - literalValue = literal.s + if ( + AstUtilities.isNumber(literal) + or AstUtilities.isString(literal) + or AstUtilities.isBytes(literal) + ): + literalValue = literal.value elif isinstance(literal, ast.List): returnList = [] @@ -247,7 +247,7 @@ elif isinstance(literal, ast.Dict): literalValue = dict(zip(literal.keys, literal.values)) - elif sys.version_info <= (3, 8, 0) and isinstance(literal, ast.Ellipsis): + elif AstUtilities.isEllipsis(literal): # what do we want to do with this? literalValue = None
--- a/src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Security/SecurityNodeVisitor.py Tue Aug 29 16:55:01 2023 +0200 +++ b/src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Security/SecurityNodeVisitor.py Tue Aug 29 16:55:18 2023 +0200 @@ -183,43 +183,19 @@ @type ast.Constant """ if isinstance(node.value, str): - self.visit_Str(node) + self.__context["str"] = node.value + if not isinstance(node._securityParent, ast.Expr): # docstring + self.__context["linerange"] = SecurityUtils.linerange_fix( + node._securityParent + ) + self.__runChecks("Str") elif isinstance(node.value, bytes): - self.visit_Bytes(node) - - def visit_Str(self, node): - """ - Public method defining a visitor for String nodes. - - This adds relevant information about node to - the context for use in tests which inspect strings. - - @param node reference to the node being inspected - @type ast.Str - """ - self.__context["str"] = node.s - if not isinstance(node._securityParent, ast.Expr): # docstring - self.__context["linerange"] = SecurityUtils.linerange_fix( - node._securityParent - ) - self.__runChecks("Str") - - def visit_Bytes(self, node): - """ - Public method defining a visitor for Bytes nodes. - - This adds relevant information about node to - the context for use in tests which inspect strings. - - @param node reference to the node being inspected - @type ast.Bytes - """ - self.__context["bytes"] = node.s - if not isinstance(node._securityParent, ast.Expr): # docstring - self.__context["linerange"] = SecurityUtils.linerange_fix( - node._securityParent - ) - self.__runChecks("Bytes") + self.__context["bytes"] = node.value + if not isinstance(node._securityParent, ast.Expr): # docstring + self.__context["linerange"] = SecurityUtils.linerange_fix( + node._securityParent + ) + self.__runChecks("Bytes") def __preVisit(self, node): """
--- a/src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Security/SecurityUtils.py Tue Aug 29 16:55:01 2023 +0200 +++ b/src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Security/SecurityUtils.py Tue Aug 29 16:55:18 2023 +0200 @@ -259,14 +259,14 @@ """ Function to build a string from an ast.BinOp chain. - This will build a string from a series of ast.Str/ast.Constant nodes + This will build a string from a series of ast.Constant nodes wrapped in ast.BinOp nodes. Something like "a" + "b" + "c" or "a %s" % val etc. The provided node can be any participant in the BinOp chain. @param node node to be processed - @type ast.BinOp or ast.Str/ast.Constant + @type ast.BinOp or ast.Constant @param stop base node to stop at - @type ast.BinOp or ast.Str/ast.Constant + @type ast.BinOp or ast.Constant @return tuple containing the root node of the expression and the string value @rtype tuple of (ast.AST, str) @@ -291,7 +291,7 @@ if isinstance(node, ast.BinOp): _get(node, bits, stop) - return (node, " ".join([x.s for x in bits if AstUtilities.isString(x)])) + return (node, " ".join([x.value for x in bits if AstUtilities.isString(x)])) def getCalledName(node):
--- a/src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Simplify/SimplifyNodeVisitor.py Tue Aug 29 16:55:01 2023 +0200 +++ b/src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Simplify/SimplifyNodeVisitor.py Tue Aug 29 16:55:18 2023 +0200 @@ -19,6 +19,8 @@ # Python < 3.9 from ast_unparse import unparse +import AstUtilities + ############################################################################### ## The following code is derived from the flake8-simplify package (v0.20.0). ## @@ -47,10 +49,6 @@ ## IN THE SOFTWARE. ############################################################################### -BOOL_CONST_TYPES = (ast.Constant, ast.NameConstant) -AST_CONST_TYPES = (ast.Constant, ast.NameConstant, ast.Str, ast.Num) -STR_TYPES = (ast.Constant, ast.Str) - class SimplifyNodeVisitor(ast.NodeVisitor): """ @@ -295,7 +293,6 @@ """ return isinstance(expr.op, ast.Add) and ( (isinstance(expr.value, ast.Constant) and expr.value.value == 1) - or (isinstance(expr.value, ast.Num) and expr.value.n == 1) ) def __getIfBodyPairs(self, node): @@ -526,13 +523,13 @@ if not ( len(node.body) != 1 or not isinstance(node.body[0], ast.Return) - or not isinstance(node.body[0].value, BOOL_CONST_TYPES) + or not isinstance(node.body[0].value, ast.Constant) or not ( node.body[0].value.value is True or node.body[0].value.value is False ) or len(node.orelse) != 1 or not isinstance(node.orelse[0], ast.Return) - or not isinstance(node.orelse[0].value, BOOL_CONST_TYPES) + or not isinstance(node.orelse[0].value, ast.Constant) or not ( node.orelse[0].value.value is True or node.orelse[0].value.value is False @@ -780,7 +777,7 @@ and isinstance(node.body[0], ast.If) and len(node.body[0].body) == 1 and isinstance(node.body[0].body[0], ast.Return) - and isinstance(node.body[0].body[0].value, BOOL_CONST_TYPES) + and isinstance(node.body[0].body[0].value, ast.Constant) and hasattr(node.body[0].body[0].value, "value") and isinstance(node.next_sibling, ast.Return) ): @@ -824,7 +821,7 @@ and ( ( isinstance(node.value.slice, ast.Index) - and isinstance(node.value.slice.value, STR_TYPES) + and isinstance(node.value.slice.value, ast.Constant) ) or isinstance(node.value.slice, ast.Constant) ) @@ -835,10 +832,7 @@ if isinstance(slice_, ast.Index): # Python < 3.9 stringPart = slice_.value # type: ignore - if isinstance(stringPart, ast.Str): - envName = stringPart.s # Python 3.6 / 3.7 fallback - else: - envName = stringPart.value + envName = stringPart.value elif isinstance(slice_, ast.Constant): # Python 3.9 envName = slice_.value @@ -855,15 +849,12 @@ and node.value.func.value.attr == "environ" and node.value.func.attr == "get" and len(node.value.args) in [1, 2] - and isinstance(node.value.args[0], STR_TYPES) + and isinstance(node.value.args[0], ast.Constant) ) if isGetCall: call = node.value stringPart = call.args[0] - if isinstance(stringPart, ast.Str): - envName = stringPart.s # Python 3.6 / 3.7 fallback - else: - envName = stringPart.value + envName = stringPart.value # Check if this has a change hasChange = envName != envName.upper() if not (isIndexCall or isGetCall) or not hasChange: @@ -1006,7 +997,7 @@ and len(node.test.ops) == 1 and isinstance(node.test.ops[0], ast.Eq) and len(node.test.comparators) == 1 - and isinstance(node.test.comparators[0], AST_CONST_TYPES) + and isinstance(node.test.comparators[0], ast.Constant) and len(node.body) == 1 and isinstance(node.body[0], ast.Return) and len(node.orelse) == 1 @@ -1019,15 +1010,13 @@ bodyValueStr = unparse(node.body[0].value).strip("'") else: bodyValueStr = "None" - if isinstance(node.test.comparators[0], ast.Str): + if AstUtilities.isString(node.test.comparators[0]): value = ( bodyValueStr if bodyValueStr[0] == '"' and bodyValueStr[-1] == '"' else bodyValueStr[1:-1] ) keyValuePairs = {node.test.comparators[0].s: value} - elif isinstance(node.test.comparators[0], ast.Num): - keyValuePairs = {node.test.comparators[0].n: bodyValueStr} else: keyValuePairs = {node.test.comparators[0].value: bodyValueStr} while child: @@ -1038,7 +1027,7 @@ and len(child.test.ops) == 1 and isinstance(child.test.ops[0], ast.Eq) and len(child.test.comparators) == 1 - and isinstance(child.test.comparators[0], AST_CONST_TYPES) + and isinstance(child.test.comparators[0], ast.Constant) and len(child.body) == 1 and isinstance(child.body[0], ast.Return) and len(child.orelse) <= 1 @@ -1049,12 +1038,7 @@ if isinstance(returnCall.value, ast.Call): return - if isinstance(child.test.comparators[0], ast.Str): - key = child.test.comparators[0].s - elif isinstance(child.test.comparators[0], ast.Num): - key = child.test.comparators[0].n - else: - key = child.test.comparators[0].value + key = child.test.comparators[0].value value = unparse(child.body[0].value) if value[0] == '"' and value[-1] == '"': @@ -1537,9 +1521,9 @@ """ # True if a else False if ( - isinstance(node.body, BOOL_CONST_TYPES) + isinstance(node.body, ast.Constant) and node.body.value is True - and isinstance(node.orelse, BOOL_CONST_TYPES) + and isinstance(node.orelse, ast.Constant) and node.orelse.value is False ): cond = unparse(node.test) @@ -1558,9 +1542,9 @@ """ # False if a else True if ( - isinstance(node.body, BOOL_CONST_TYPES) + isinstance(node.body, ast.Constant) and node.body.value is False - and isinstance(node.orelse, BOOL_CONST_TYPES) + and isinstance(node.orelse, ast.Constant) and node.orelse.value is True ): cond = unparse(node.test) @@ -1648,7 +1632,7 @@ # a or True if isinstance(node.op, ast.Or): for exp in node.values: - if isinstance(exp, BOOL_CONST_TYPES) and exp.value is True: + if isinstance(exp, ast.Constant) and exp.value is True: self.__error(node.lineno - 1, node.col_offset, "Y223") def __check224(self, node): @@ -1661,7 +1645,7 @@ # a and False if isinstance(node.op, ast.And): for exp in node.values: - if isinstance(exp, BOOL_CONST_TYPES) and exp.value is False: + if isinstance(exp, ast.Constant) and exp.value is False: self.__error(node.lineno - 1, node.col_offset, "Y224") def __check301(self, node): @@ -1673,16 +1657,15 @@ """ # 42 == age if ( - isinstance(node.left, AST_CONST_TYPES) + isinstance(node.left, ast.Constant) and len(node.ops) == 1 and isinstance(node.ops[0], ast.Eq) ): left = unparse(node.left) - isPy37Str = isinstance(node.left, ast.Str) - isPy38Str = isinstance(node.left, ast.Constant) and isinstance( + isStr = isinstance(node.left, ast.Constant) and isinstance( node.left.value, str ) - if isPy37Str or isPy38Str: + if isStr: left = f"'{left}'" right = unparse(node.comparators[0]) self.__error(node.lineno - 1, node.col_offset, "Y301", left, right) @@ -1777,12 +1760,9 @@ if ( isinstance(node.func, ast.Attribute) and node.func.attr == "split" - and isinstance(node.func.value, (ast.Str, ast.Constant)) + and isinstance(node.func.value, ast.Constant) ): - if isinstance(node.func.value, ast.Constant): - value = node.func.value.value - else: - value = node.func.value.s + value = node.func.value.value expected = json.dumps(value.split()) actual = unparse(node.func.value) + ".split()" @@ -1811,8 +1791,8 @@ names += getOsPathJoinArgs(arg) elif isinstance(arg, ast.Name): names.append(arg.id) - elif isinstance(arg, ast.Str): - names.append(f"'{arg.s}'") + elif AstUtilities.isString(arg): + names.append(f"'{arg.value}'") return names if ( @@ -1864,7 +1844,7 @@ hasNone = False others = [] for elt in tupleVar.elts: - if isinstance(elt, BOOL_CONST_TYPES) and elt.value is None: + if isinstance(elt, ast.Constant) and elt.value is None: hasNone = True else: others.append(elt) @@ -1909,7 +1889,7 @@ # check the argument value if not ( len(node.args) == 2 - and isinstance(node.args[1], BOOL_CONST_TYPES) + and isinstance(node.args[1], ast.Constant) and node.args[1].value is None ): return