eric6/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleChecker.py

branch
maintenance
changeset 8273
698ae46f40a4
parent 8176
31965986ecd1
parent 8259
2bbec88047dd
diff -r fb0ef164f536 -r 698ae46f40a4 eric6/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleChecker.py
--- a/eric6/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleChecker.py	Fri Apr 02 11:59:41 2021 +0200
+++ b/eric6/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleChecker.py	Sat May 01 14:27:20 2021 +0200
@@ -11,6 +11,7 @@
 import ast
 import sys
 import multiprocessing
+import contextlib
 
 import pycodestyle
 from Naming.NamingStyleChecker import NamingStyleChecker
@@ -23,6 +24,7 @@
 from Complexity.ComplexityChecker import ComplexityChecker
 from Security.SecurityChecker import SecurityChecker
 from PathLib.PathlibChecker import PathlibChecker
+from Simplify.SimplifyChecker import SimplifyChecker
 
 
 def initService():
@@ -53,7 +55,7 @@
         
         @param options options for the report (optparse.Values)
         """
-        super(CodeStyleCheckerReport, self).__init__(options)
+        super().__init__(options)
         
         self.__repeat = options.repeat
         self.errors = []
@@ -69,7 +71,7 @@
         @param args arguments for the message (list)
         @return error code (string)
         """
-        code = super(CodeStyleCheckerReport, self).error_args(
+        code = super().error_args(
             line_number, offset, code, check, *args)
         if code and (self.counters[code] == 1 or self.__repeat):
             self.errors.append(
@@ -278,15 +280,21 @@
     @type str
     @param source string containing the code to check
     @type str
-    @return tuple containing the error dictionary with syntax error details
-        and a statistics dictionary or a tuple containing two None
-    @rtype tuple of (dict, dict) or tuple of (None, None)
+    @return tuple containing the error dictionary with syntax error details,
+        a statistics dictionary and None or a tuple containing two None and
+        the generated AST tree
+    @rtype tuple of (dict, dict, None) or tuple of (None, None, ast.Module)
     """
     src = "".join(source)
     
     try:
-        ast.parse(src, filename, 'exec')
-        return None, None
+        tree = (
+            ast.parse(src, filename, 'exec', type_comments=True)
+            # need the 'type_comments' parameter to include type annotations
+            if sys.version_info >= (3, 8) else
+            ast.parse(src, filename, 'exec')
+        )
+        return None, None, tree
     except (SyntaxError, TypeError):
         exc_type, exc = sys.exc_info()[:2]
         if len(exc.args) > 1:
@@ -295,15 +303,18 @@
                 offset = offset[1:3]
         else:
             offset = (1, 0)
-        return ({
-            "file": filename,
-            "line": offset[0],
-            "offset": offset[1],
-            "code": "E901",
-            "args": [exc_type.__name__, exc.args[0]],
-        }, {
-            "E901": 1,
-        })
+        return (
+            {
+                "file": filename,
+                "line": offset[0],
+                "offset": offset[1],
+                "code": "E901",
+                "args": [exc_type.__name__, exc.args[0]],
+            }, {
+                "E901": 1,
+            },
+            None
+        )
 
 
 def __checkCodeStyle(filename, source, args):
@@ -366,13 +377,10 @@
         else:
             ignore = []
         
-        syntaxError, syntaxStats = __checkSyntax(filename, source)
-        if syntaxError:
-            errors = [syntaxError]
-            stats.update(syntaxStats)
+        syntaxError, syntaxStats, tree = __checkSyntax(filename, source)
         
-        # perform the checks only, if syntax is ok
-        else:
+        # perform the checks only, if syntax is ok and AST tree was generated
+        if tree:
             # check coding style
             pycodestyle.BLANK_LINES_CONFIG = {
                 # Top level class and function.
@@ -403,7 +411,7 @@
             
             # miscellaneous additional checks
             miscellaneousChecker = MiscellaneousChecker(
-                source, filename, select, ignore, [], repeatMessages,
+                source, filename, tree, select, ignore, [], repeatMessages,
                 miscellaneousArgs)
             miscellaneousChecker.run()
             stats.update(miscellaneousChecker.counters)
@@ -411,34 +419,48 @@
             
             # check code complexity
             complexityChecker = ComplexityChecker(
-                source, filename, select, ignore, codeComplexityArgs)
+                source, filename, tree, select, ignore, codeComplexityArgs)
             complexityChecker.run()
             stats.update(complexityChecker.counters)
             errors += complexityChecker.errors
             
             # check function annotations
-            if sys.version_info >= (3, 5, 0):
-                # annotations are supported from Python 3.5 on
+            if sys.version_info >= (3, 8, 0):
+                # annotations with type comments are supported from
+                # Python 3.8 on
                 from Annotations.AnnotationsChecker import AnnotationsChecker
                 annotationsChecker = AnnotationsChecker(
-                    source, filename, select, ignore, [], repeatMessages,
+                    source, filename, tree, select, ignore, [], repeatMessages,
                     annotationArgs)
                 annotationsChecker.run()
                 stats.update(annotationsChecker.counters)
                 errors += annotationsChecker.errors
             
+            # check for security issues
             securityChecker = SecurityChecker(
-                source, filename, select, ignore, [], repeatMessages,
+                source, filename, tree, select, ignore, [], repeatMessages,
                 securityArgs)
             securityChecker.run()
             stats.update(securityChecker.counters)
             errors += securityChecker.errors
             
+            # check for pathlib usage
             pathlibChecker = PathlibChecker(
-                source, filename, select, ignore, [], repeatMessages)
+                source, filename, tree, select, ignore, [], repeatMessages)
             pathlibChecker.run()
             stats.update(pathlibChecker.counters)
             errors += pathlibChecker.errors
+            
+            # check for code simplifications
+            simplifyChecker = SimplifyChecker(
+                source, filename, tree, select, ignore, [], repeatMessages)
+            simplifyChecker.run()
+            stats.update(simplifyChecker.counters)
+            errors += simplifyChecker.errors
+        
+        elif syntaxError:
+            errors = [syntaxError]
+            stats.update(syntaxStats)
     
     errorsDict = {}
     for error in errors:
@@ -464,11 +486,9 @@
             if source:
                 code = error["code"]
                 lineFlags = extractLineFlags(source[lineno - 1].strip())
-                try:
+                with contextlib.suppress(IndexError):
                     lineFlags += extractLineFlags(source[lineno].strip(),
                                                   flagsLine=True)
-                except IndexError:
-                    pass
                 
                 if securityOk(code, lineFlags):
                     error["securityOk"] = True

eric ide

mercurial