diff -r 23b2fe1cd863 -r 7efebdfa5dc2 eric7/Plugins/CheckerPlugins/CodeStyleChecker/Miscellaneous/MiscellaneousChecker.py --- a/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Miscellaneous/MiscellaneousChecker.py Tue Nov 02 18:02:00 2021 +0100 +++ b/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Miscellaneous/MiscellaneousChecker.py Wed Nov 03 19:34:56 2021 +0100 @@ -55,10 +55,9 @@ "M131", "M132", ## Comprehensions - "M181", "M182", "M183", "M184", - "M185", "M186", "M187", - "M191", "M192", "M193", - "M195", "M196", "M197", "M198", + "M181", "M182", "M183", "M184", "M185", "M186", "M187", "M188", + "M189", + "M191", "M192", "M193", "M195", "M196", "M197", "M198", ## Dictionaries with sorted keys "M201", @@ -173,7 +172,8 @@ (self.__checkCopyright, ("M111", "M112")), (self.__checkBuiltins, ("M131", "M132")), (self.__checkComprehensions, ("M181", "M182", "M183", "M184", - "M185", "M186", "M187", + "M185", "M186", "M187", "M188", + "M189", "M191", "M192", "M193", "M195", "M196", "M197", "M198")), (self.__checkDictWithSortedKeys, ("M201",)), @@ -682,6 +682,7 @@ for node in ast.walk(self.__tree): if isinstance(node, ast.Call) and isinstance(node.func, ast.Name): nArgs = len(node.args) + nKwArgs = len(node.keywords) if ( nArgs == 1 and @@ -696,21 +697,25 @@ elif ( nArgs == 1 and - isinstance(node.args[0], ast.GeneratorExp) and + isinstance(node.args[0], + (ast.GeneratorExp, ast.ListComp)) and isinstance(node.args[0].elt, ast.Tuple) and len(node.args[0].elt.elts) == 2 and node.func.id == "dict" ): - self.__error(node.lineno - 1, node.col_offset, "M183") + if isinstance(node.args[0], ast.GeneratorExp): + errorCode = "M183" + else: + errorCode = "M185" + self.__error(node.lineno - 1, node.col_offset, errorCode) elif ( nArgs == 1 and isinstance(node.args[0], ast.ListComp) and - node.func.id in ('list', 'set', 'dict') + node.func.id in ('list', 'set') ): errorCode = { 'list': 'M195', - 'dict': 'M185', 'set': 'M184', }[node.func.id] self.__error(node.lineno - 1, node.col_offset, errorCode) @@ -743,32 +748,109 @@ self.__error(node.lineno - 1, node.col_offset, errorCode, type(node.args[0]).__name__.lower(), node.func.id) - - elif ( - nArgs == 1 and - isinstance(node.args[0], ast.ListComp) and - node.func.id in ('all', 'any', 'enumerate', 'frozenset', - 'max', 'min', 'sorted', 'sum', 'tuple',) - ): - self.__error(node.lineno - 1, node.col_offset, "M187", - node.func.id) elif ( nArgs == 0 and not any(isinstance(a, ast.Starred) for a in node.args) and not any(k.arg is None for k in node.keywords) and - node.func.id in ("tuple", "list", "dict") + node.func.id == "dict" + ) or ( + nArgs == 0 and + nKwArgs == 0 and + node.func.id in ("tuple", "list") ): self.__error(node.lineno - 1, node.col_offset, "M186", node.func.id) - elif isinstance(node, ast.Compare) and ( - len(node.ops) == 1 and - isinstance(node.ops[0], ast.In) and - len(node.comparators) == 1 and - isinstance(node.comparators[0], ast.ListComp) + elif ( + node.func.id in {"list", "reversed"} and + nArgs > 0 and + isinstance(node.args[0], ast.Call) and + isinstance(node.args[0].func, ast.Name) and + node.args[0].func.id == "sorted" ): - self.__error(node.lineno - 1, node.col_offset, "M196") + if node.func.id == "reversed": + reverseFlagValue = False + 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 + + if reverseFlagValue is None: + self.__error(node.lineno - 1, node.col_offset, + "M187a", node.func.id, + node.args[0].func.id) + else: + self.__error(node.lineno - 1, node.col_offset, + "M187b", node.func.id, + node.args[0].func.id, + not reverseFlagValue) + else: + self.__error(node.lineno - 1, node.col_offset, + "M187c", node.func.id, + node.args[0].func.id) + + elif ( + nArgs > 0 and + isinstance(node.args[0], ast.Call) and + isinstance(node.args[0].func, ast.Name) and + ( + ( + node.func.id in {"set", "sorted"} and + node.args[0].func.id in { + "list", "reversed", "sorted", "tuple"} + ) or ( + node.func.id in {"list", "tuple"} and + node.args[0].func.id in {"list", "tuple"} + ) or ( + node.func.id == "set" and + node.args[0].func.id == "set" + ) + ) + ): + self.__error(node.lineno - 1, node.col_offset, "M188", + node.args[0].func.id, node.func.id) + + elif ( + node.func.id in {"reversed", "set", "sorted"} and + nArgs > 0 and + isinstance(node.args[0], ast.Subscript) and + isinstance(node.args[0].slice, ast.Slice) and + node.args[0].slice.lower is None 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 + node.args[0].slice.step.operand.n == 1 + ): + self.__error(node.lineno - 1, node.col_offset, + "M189", node.func.id) + + elif ( + isinstance(node, (ast.ListComp, ast.SetComp)) and ( + len(node.generators) == 1 and + not node.generators[0].ifs and + not node.generators[0].is_async and ( + isinstance(node.elt, ast.Name) and + isinstance(node.generators[0].target, ast.Name) and + node.elt.id == node.generators[0].target.id + ) + ) + ): + compType = { + ast.DictComp: "dict", + ast.ListComp: "list", + ast.SetComp: "set", + }[node.__class__] + + self.__error(node.lineno - 1, node.col_offset, + "M196", compType) def __checkMutableDefault(self): """