eric6/Plugins/CheckerPlugins/CodeStyleChecker/Simplify/SimplifyNodeVisitor.py

changeset 8192
e1157bd8b4c2
parent 8191
9125da0c227e
child 8194
b925628bf91f
diff -r 9125da0c227e -r e1157bd8b4c2 eric6/Plugins/CheckerPlugins/CodeStyleChecker/Simplify/SimplifyNodeVisitor.py
--- a/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Simplify/SimplifyNodeVisitor.py	Fri Apr 02 15:35:44 2021 +0200
+++ b/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Simplify/SimplifyNodeVisitor.py	Fri Apr 02 18:13:12 2021 +0200
@@ -115,6 +115,7 @@
         self.__check104(node)
         self.__check110_111(node)
         self.__check113(node)
+        self.__check118b(node)
         
         self.generic_visit(node)
     
@@ -141,6 +142,39 @@
         
         self.generic_visit(node)
     
+    def visit_With(self, node):
+        """
+        Public method to process a With node.
+        
+        @param node reference to the With node
+        @type ast.With
+        """
+        self.__check117(node)
+        
+        self.generic_visit(node)
+    
+    def visit_Compare(self, node):
+        """
+        Public method to process a Compare node.
+        
+        @param node reference to the Compare node
+        @type ast.Compare
+        """
+        self.__check118a(node)
+        
+        self.generic_visit(node)
+    
+    def visit_ClassDef(self, node):
+        """
+        Public method to process a ClassDef node.
+        
+        @param node reference to the ClassDef node
+        @type ast.ClassDef
+        """
+        self.__check119(node)
+        
+        self.generic_visit(node)
+    
     #############################################################
     ## Helper methods for the various checkers below
     #############################################################
@@ -468,8 +502,13 @@
             body = unparse(node.body[0].value)
             cond = unparse(node.test)
             orelse = unparse(node.orelse[0].value)
-            self.__error(node.lineno - 1, node.col_offset, "Y108",
-                         assign, body, cond, orelse)
+            if len(
+                "{0} = {1} if {2} else {3}".format(assign, body, cond, orelse)
+            ) > 79:
+                self.__error(node.lineno - 1, node.col_offset, "Y108a")
+            else:
+                self.__error(node.lineno - 1, node.col_offset, "Y108b",
+                             assign, body, cond, orelse)
     
     def __check109(self, node):
         """
@@ -730,20 +769,21 @@
             variable = node.test.left
             child = node.orelse[0]
             elseValue = None
+            if node.body[0].value is not None:
+                bodyValueStr = unparse(node.body[0].value).strip("'")
+            else:
+                bodyValueStr = "None"
             if isinstance(node.test.comparators[0], ast.Str):
                 keyValuePairs = {
-                    node.test.comparators[0].s:
-                        unparse(node.body[0].value).strip("'")
+                    node.test.comparators[0].s: bodyValueStr
                 }
             elif isinstance(node.test.comparators[0], ast.Num):
                 keyValuePairs = {
-                    node.test.comparators[0].n:
-                        unparse(node.body[0].value).strip("'")
+                    node.test.comparators[0].n: bodyValueStr,
                 }
             else:
                 keyValuePairs = {
-                    node.test.comparators[0].value:
-                        unparse(node.body[0].value).strip("'")
+                    node.test.comparators[0].value: bodyValueStr
                 }
             while child:
                 if not (
@@ -787,6 +827,113 @@
                 ret = f"{keyValuePairs}.get({variable.id})"
             
             self.__error(node.lineno - 1, node.col_offset, "Y116", ret)
+    
+    def __check117(self, node):
+        """
+        Private method to check for multiple with-statements with same scope.
+        
+        @param node reference to the AST node to be checked
+        @type ast.With
+        """
+        # with A() as a:
+        #     with B() as b:
+        #         print("hello")
+        if (
+            len(node.body) == 1 and
+            isinstance(node.body[0], ast.With)
+        ):
+            withItems = []
+            for withitem in node.items + node.body[0].items:
+                withItems.append(f"{unparse(withitem)}")
+            mergedWith = f"with {', '.join(withItems)}:"
+            self.__error(node.lineno - 1, node.col_offset, "Y117", mergedWith)
+    
+    def __check118a(self, node):
+        """
+        Private method to check for usages of "key in dict.keys()".
+        
+        @param node reference to the AST node to be checked
+        @type ast.Compare
+        """
+        # key in dict.keys()
+        if (
+            len(node.ops) == 1 and
+            isinstance(node.ops[0], ast.In) and
+            len(node.comparators) == 1
+        ):
+            callNode = node.comparators[0]
+            if not isinstance(callNode, ast.Call):
+                return
+            
+            attrNode = callNode.func
+            if (
+                isinstance(callNode.func, ast.Attribute) and
+                callNode.func.attr == "keys" and
+                isinstance(callNode.func.ctx, ast.Load)
+            ):
+                keyStr = unparse(node.left)
+                dictStr = unparse(attrNode.value)
+                self.__error(node.lineno - 1, node.col_offset, "Y118",
+                             keyStr, dictStr)
+    
+    def __check118b(self, node):
+        """
+        Private method to check for usages of "key in dict.keys()".
+        
+        @param node reference to the AST node to be checked
+        @type ast.For
+        """
+        # for key in dict.keys():
+        #     # do something
+        callNode = node.iter
+        if not isinstance(callNode, ast.Call):
+            return
+        
+        attrNode = callNode.func
+        if (
+            isinstance(callNode.func, ast.Attribute) and
+            callNode.func.attr == "keys" and
+            isinstance(callNode.func.ctx, ast.Load)
+        ):
+            keyStr = unparse(node.target)
+            dictStr = unparse(attrNode.value)
+            self.__error(node.lineno - 1, node.col_offset, "Y118",
+                         keyStr, dictStr)
+    
+    def __check119(self, node):
+        """
+        Public method to check for classes that should be "dataclasses".
+        
+        @param node reference to the AST node to be checked
+        @type ast.ClassDef
+        """
+        if (
+            len(node.decorator_list) == 0 and
+            len(node.bases) == 0
+        ):
+            dataclassFunctions = [
+                "__init__",
+                "__eq__",
+                "__hash__",
+                "__repr__",
+                "__str__",
+            ]
+            hasOnlyConstructorMethod = True
+            for bodyElement in node.body:
+                if (
+                    isinstance(bodyElement, ast.FunctionDef) and
+                    bodyElement.name not in dataclassFunctions
+                ):
+                    hasOnlyConstructorMethod = False
+                    break
+
+            if (
+                hasOnlyConstructorMethod and
+                sum(1 for el in node.body
+                    if isinstance(el, ast.FunctionDef)) > 0
+            ):
+                self.__error(node.lineno - 1, node.col_offset, "Y119",
+                             node.name)
 
 #
 # eflag: noqa = M891

eric ide

mercurial