eric6/Plugins/CheckerPlugins/CodeStyleChecker/Miscellaneous/MiscellaneousChecker.py

branch
maintenance
changeset 8273
698ae46f40a4
parent 8176
31965986ecd1
parent 8243
cc717c2ae956
--- a/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Miscellaneous/MiscellaneousChecker.py	Fri Apr 02 11:59:41 2021 +0200
+++ b/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Miscellaneous/MiscellaneousChecker.py	Sat May 01 14:27:20 2021 +0200
@@ -14,6 +14,8 @@
 from string import Formatter
 from collections import defaultdict
 import tokenize
+import copy
+import contextlib
 
 import AstUtilities
 
@@ -32,14 +34,13 @@
     @ytype str
     """
     if isinstance(node, ast.Attribute):
-        for v in composeCallPath(node.value):
-            yield v
+        yield from composeCallPath(node.value)
         yield node.attr
     elif isinstance(node, ast.Name):
         yield node.id
 
 
-class MiscellaneousChecker(object):
+class MiscellaneousChecker:
     """
     Class implementing a checker for miscellaneous checks.
     """
@@ -110,9 +111,6 @@
         
         ## commented code
         "M891",
-        
-        ## syntax error
-        "M901",
     ]
     
     Formatter = Formatter()
@@ -124,8 +122,8 @@
         "credits",
     ]
 
-    def __init__(self, source, filename, select, ignore, expected, repeat,
-                 args):
+    def __init__(self, source, filename, tree, select, ignore, expected,
+                 repeat, args):
         """
         Constructor
         
@@ -133,6 +131,8 @@
         @type list of str
         @param filename name of the source file
         @type str
+        @param tree AST tree of the source code
+        @type ast.Module
         @param select list of selected codes
         @type list of str
         @param ignore list of codes to be ignored
@@ -150,6 +150,7 @@
         self.__repeat = repeat
         self.__filename = filename
         self.__source = source[:]
+        self.__tree = copy.deepcopy(tree)
         self.__args = args
         
         self.__pep3101FormatRegex = re.compile(
@@ -267,29 +268,6 @@
                 }
             )
     
-    def __reportInvalidSyntax(self):
-        """
-        Private method to report a syntax error.
-        """
-        exc_type, exc = sys.exc_info()[:2]
-        if len(exc.args) > 1:
-            offset = exc.args[1]
-            if len(offset) > 2:
-                offset = offset[1:3]
-        else:
-            offset = (1, 0)
-        self.__error(offset[0] - 1, offset[1] or 0,
-                     'M901', exc_type.__name__, exc.args[0])
-    
-    def __generateTree(self):
-        """
-        Private method to generate an AST for our source.
-        
-        @return generated AST
-        @rtype ast.AST
-        """
-        return ast.parse("".join(self.__source), self.__filename)
-    
     def run(self):
         """
         Public method to check the given source against miscellaneous
@@ -303,12 +281,6 @@
             # don't do anything, if no codes were selected
             return
         
-        try:
-            self.__tree = self.__generateTree()
-        except (SyntaxError, TypeError):
-            self.__reportInvalidSyntax()
-            return
-        
         for check in self.__checkers:
             check()
     
@@ -480,7 +452,7 @@
         if isinstance(node, ast.Module) or not hasCode:
             return
 
-        if not (imports >= expectedImports):
+        if imports < expectedImports:
             if imports:
                 self.__error(node.lineno - 1, node.col_offset, "M701",
                              ", ".join(expectedImports), ", ".join(imports))
@@ -572,14 +544,12 @@
                 
                 # if starargs or kwargs is not None, it can't count the
                 # parameters but at least check if the args are used
-                if hasKwArgs:
-                    if not names:
-                        # No names but kwargs
-                        self.__error(call.lineno - 1, call.col_offset, "M623")
-                if hasStarArgs:
-                    if not numbers:
-                        # No numbers but args
-                        self.__error(call.lineno - 1, call.col_offset, "M624")
+                if hasKwArgs and not names:
+                    # No names but kwargs
+                    self.__error(call.lineno - 1, call.col_offset, "M623")
+                if hasStarArgs and not numbers:
+                    # No numbers but args
+                    self.__error(call.lineno - 1, call.col_offset, "M624")
                 
                 if not hasKwArgs and not hasStarArgs:
                     # can actually verify numbers and names
@@ -642,10 +612,8 @@
         Private method to check, if built-ins are shadowed.
         """
         functionDefs = [ast.FunctionDef]
-        try:
+        with contextlib.suppress(AttributeError):
             functionDefs.append(ast.AsyncFunctionDef)
-        except AttributeError:
-            pass
         
         ignoreBuiltinAssignments = self.__args.get(
             "BuiltinsChecker",
@@ -830,19 +798,15 @@
             "frozenset",
         )
         functionDefs = [ast.FunctionDef]
-        try:
+        with contextlib.suppress(AttributeError):
             functionDefs.append(ast.AsyncFunctionDef)
-        except AttributeError:
-            pass
         
         for node in ast.walk(self.__tree):
             if any(isinstance(node, functionDef)
                    for functionDef in functionDefs):
                 defaults = node.args.defaults[:]
-                try:
+                with contextlib.suppress(AttributeError):
                     defaults += node.args.kw_defaults[:]
-                except AttributeError:
-                    pass
                 for default in defaults:
                     if any(isinstance(default, mutableType)
                            for mutableType in mutableTypes):
@@ -943,7 +907,7 @@
         """
         # step 1: generate an augmented node tree containing parent info
         #         for each child node
-        tree = self.__generateTree()
+        tree = copy.deepcopy(self.__tree)
         for node in ast.walk(tree):
             for childNode in ast.iter_child_nodes(node):
                 childNode._dtCheckerParent = node
@@ -981,7 +945,7 @@
         """
         Constructor
         """
-        super(TextVisitor, self).__init__()
+        super().__init__()
         self.nodes = []
         self.calls = {}
 
@@ -1025,9 +989,9 @@
             if AstUtilities.isBaseString(node):
                 self.__addNode(node)
             else:
-                super(TextVisitor, self).generic_visit(node)
+                super().generic_visit(node)
         else:
-            super(TextVisitor, self).generic_visit(node)
+            super().generic_visit(node)
 
     def __visitDefinition(self, node):
         """
@@ -1123,7 +1087,7 @@
                 AstUtilities.isBaseString(node.args[0])
             ):
                 self.calls[node.args[0]] = (node, True)
-        super(TextVisitor, self).generic_visit(node)
+        super().generic_visit(node)
 
 
 class LoggingVisitor(ast.NodeVisitor):
@@ -1143,7 +1107,7 @@
         """
         Constructor
         """
-        super(LoggingVisitor, self).__init__()
+        super().__init__()
         
         self.__currentLoggingCall = None
         self.__currentLoggingArgument = None
@@ -1192,14 +1156,12 @@
         @return logging level
         @rtype str or None
         """
-        try:
+        with contextlib.suppress(AttributeError):
             if node.func.value.id == "warnings":
                 return None
             
             if node.func.attr in LoggingVisitor.LoggingLevels:
                 return node.func.attr
-        except AttributeError:
-            pass
         
         return None
 
@@ -1228,11 +1190,14 @@
         @type ast.Call
         """
         # we are in a logging statement
-        if self.__withinLoggingStatement():
-            if self.__withinLoggingArgument() and self.__isFormatCall(node):
-                self.violations.append((node, "M651"))
-                super(LoggingVisitor, self).generic_visit(node)
-                return
+        if (
+            self.__withinLoggingStatement() and
+            self.__withinLoggingArgument() and
+            self.__isFormatCall(node)
+        ):
+            self.violations.append((node, "M651"))
+            super().generic_visit(node)
+            return
         
         loggingLevel = self.__detectLoggingLevel(node)
         
@@ -1241,7 +1206,7 @@
         
         # we are in some other statement
         if loggingLevel is None:
-            super(LoggingVisitor, self).generic_visit(node)
+            super().generic_visit(node)
             return
         
         # we are entering a new logging statement
@@ -1260,7 +1225,7 @@
             ):
                 self.__currentExtraKeyword = child
             
-            super(LoggingVisitor, self).visit(child)
+            super().visit(child)
             
             self.__currentLoggingArgument = None
             self.__currentExtraKeyword = None
@@ -1285,7 +1250,7 @@
             if isinstance(node.op, ast.Add):
                 self.violations.append((node, "M653"))
         
-        super(LoggingVisitor, self).generic_visit(node)
+        super().generic_visit(node)
     
     def visit_JoinedStr(self, node):
         """
@@ -1294,12 +1259,14 @@
         @param node reference to the node to be processed
         @type ast.JoinedStr
         """
-        if self.__withinLoggingStatement():
-            if any(isinstance(i, ast.FormattedValue) for i in node.values):
-                if self.__withinLoggingArgument():
-                    self.violations.append((node, "M654"))
-                    
-                    super(LoggingVisitor, self).generic_visit(node)
+        if (
+            self.__withinLoggingStatement() and
+            any(isinstance(i, ast.FormattedValue) for i in node.values) and
+            self.__withinLoggingArgument()
+        ):
+            self.violations.append((node, "M654"))
+            
+            super().generic_visit(node)
 
 
 class BugBearVisitor(ast.NodeVisitor):
@@ -1317,7 +1284,7 @@
         """
         Constructor
         """
-        super(BugBearVisitor, self).__init__()
+        super().__init__()
         
         self.__nodeStack = []
         self.__nodeWindow = []
@@ -1334,7 +1301,7 @@
         self.__nodeWindow.append(node)
         self.__nodeWindow = self.__nodeWindow[-BugBearVisitor.NodeWindowSize:]
         
-        super(BugBearVisitor, self).visit(node)
+        super().visit(node)
         
         self.__nodeStack.pop()
     
@@ -1376,7 +1343,7 @@
             else:
                 self.__checkForM502(node)
         else:
-            try:
+            with contextlib.suppress(AttributeError, IndexError):
                 # bad super() call
                 if isinstance(node.func, ast.Name) and node.func.id == "super":
                     args = node.args
@@ -1407,8 +1374,6 @@
                     AstUtilities.isString(node.args[1])
                 ):
                     self.violations.append((node, "M513"))
-            except (AttributeError, IndexError):
-                pass
 
             self.generic_visit(node)
     
@@ -1452,10 +1417,10 @@
             target = node.targets[0]
             if (
                 isinstance(target, ast.Attribute) and
-                isinstance(target.value, ast.Name)
+                isinstance(target.value, ast.Name) and
+                (target.value.id, target.attr) == ('os', 'environ')
             ):
-                if (target.value.id, target.attr) == ('os', 'environ'):
-                    self.violations.append((node, "M506"))
+                self.violations.append((node, "M506"))
         
         self.generic_visit(node)
     
@@ -1559,7 +1524,7 @@
         """
         Constructor
         """
-        super(NameFinder, self).__init__()
+        super().__init__()
         
         self.__names = {}
 
@@ -1581,9 +1546,9 @@
         """
         if isinstance(node, list):
             for elem in node:
-                super(NameFinder, self).visit(elem)
+                super().visit(elem)
         else:
-            super(NameFinder, self).visit(node)
+            super().visit(node)
     
     def getNames(self):
         """
@@ -1607,7 +1572,7 @@
         """
         Constructor
         """
-        super(ReturnVisitor, self).__init__()
+        super().__init__()
         
         self.__stack = []
         self.violations = []
@@ -1968,7 +1933,7 @@
         """
         Constructor
         """
-        super(DateTimeVisitor, self).__init__()
+        super().__init__()
         
         self.violations = []
     
@@ -2126,10 +2091,11 @@
                 # datetime.strptime(...).replace(tzinfo=UTC)
                 parent = getattr(node, '_dtCheckerParent', None)
                 pparent = getattr(parent, '_dtCheckerParent', None)
-                if not (isinstance(parent, ast.Attribute) and
-                        parent.attr == 'replace'):
-                    isCase1 = False
-                elif not isinstance(pparent, ast.Call):
+                if (
+                    not (isinstance(parent, ast.Attribute) and
+                         parent.attr == 'replace') or
+                    not isinstance(pparent, ast.Call)
+                ):
                     isCase1 = False
                 else:
                     tzinfoKeyword = self.__getFromKeywords(pparent.keywords,
@@ -2188,7 +2154,7 @@
         """
         Constructor
         """
-        super(SysVersionVisitor, self).__init__()
+        super().__init__()
         
         self.violations = []
         self.__fromImports = {}
@@ -2219,16 +2185,13 @@
         """
         match = False
         if (
-            isinstance(node, ast.Attribute) and
-            isinstance(node.value, ast.Name) and
-            node.value.id == "sys" and
-            node.attr == attr
-        ):
-            match = True
-        elif (
-            isinstance(node, ast.Name) and
-            node.id == attr and
-            self.__fromImports.get(node.id) == "sys"
+            (isinstance(node, ast.Attribute) and
+             isinstance(node.value, ast.Name) and
+             node.value.id == "sys" and
+             node.attr == attr) or
+            (isinstance(node, ast.Name) and
+             node.id == attr and
+             self.__fromImports.get(node.id) == "sys")
         ):
             match = True
         

eric ide

mercurial