src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Imports/ImportsChecker.py

branch
eric7
changeset 9275
1a7d545d3ef2
parent 9274
86fab0c74430
child 9453
e5065dde905d
diff -r 86fab0c74430 -r 1a7d545d3ef2 src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Imports/ImportsChecker.py
--- a/src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Imports/ImportsChecker.py	Wed Jul 27 15:52:14 2022 +0200
+++ b/src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Imports/ImportsChecker.py	Wed Jul 27 18:02:43 2022 +0200
@@ -9,6 +9,7 @@
 
 import ast
 import copy
+import re
 import sys
 
 
@@ -505,16 +506,37 @@
     #######################################################################
     ## Tidy imports
     ##
-    ## adapted from: flake8-tidy-imports v4.5.0
+    ## adapted from: flake8-tidy-imports v4.8.0
     #######################################################################
-    # TODO: update to v4.8.0
 
     def __tidyImports(self):
         """
         Private method to check various other import related topics.
         """
-        self.__bannedModules = self.__args.get("BannedModules", [])
         self.__banRelativeImports = self.__args.get("BanRelativeImports", "")
+        self.__bannedModules = []
+        self.__bannedStructuredPatterns = []
+        self.__bannedUnstructuredPatterns = []
+        for module in self.__args.get("BannedModules", []):
+            module = module.strip()
+            if "*" in module[:-1] or module == "*":
+                # unstructured
+                self.__bannedUnstructuredPatterns.append(
+                    self.__compileUnstructuredGlob(module)
+                )
+            elif module.endswith(".*"):
+                # structured
+                self.__bannedStructuredPatterns.append(module)
+                # Also check for exact matches without the wildcard
+                # e.g. "foo.*" matches "foo"
+                prefix = module[:-2]
+                if prefix not in self.__bannedModules:
+                    self.__bannedModules.append(prefix)
+            else:
+                self.__bannedModules.append(module)
+
+        # Sort the structured patterns so we match the specifc ones first.
+        self.__bannedStructuredPatterns.sort(key=lambda x: len(x[0]), reverse=True)
 
         ruleMethods = []
         if not self.__ignoreCode("I901"):
@@ -530,6 +552,26 @@
             for method in ruleMethods:
                 method(node)
 
+    def __compileUnstructuredGlob(self, module):
+        """
+        Private method to convert a pattern to a regex such that ".*" matches zero or
+        more modules.
+
+        @param module module pattern to be converted
+        @type str
+        @return compiled regex
+        @rtype re.regex object
+        """
+        parts = module.split(".")
+        transformedParts = [
+            "(\\..*)?" if p == "*" else "\\." + re.escape(p) for p in parts
+        ]
+        if parts[0] == "*":
+            transformedParts[0] = ".*"
+        else:
+            transformedParts[0] = re.escape(parts[0])
+        return re.compile("".join(transformedParts) + "\\Z")
+
     def __checkUnnecessaryAlias(self, node):
         """
         Private method to check unnecessary import aliases.
@@ -560,6 +602,34 @@
 
                     self.__error(node.lineno - 1, node.col_offset, "I901", rewritten)
 
+    def __isModuleBanned(self, moduleName):
+        """
+        Private method to check, if the given module name banned.
+
+        @param moduleName module name to be checked
+        @type str
+        @return flag indicating a banned module
+        @rtype bool
+        """
+        if moduleName in self.__bannedModules:
+            return True
+
+        # Check unustructed wildcards
+        if any(
+            bannedPattern.match(moduleName)
+            for bannedPattern in self.__bannedUnstructuredPatterns
+        ):
+            return True
+
+        # Check structured wildcards
+        if any(
+            moduleName.startswith(bannedPrefix[:-1])
+            for bannedPrefix in self.__bannedStructuredPatterns
+        ):
+            return True
+
+        return False
+
     def __checkBannedImport(self, node):
         """
         Private method to check import of banned modules.
@@ -586,7 +656,7 @@
         warned = set()
 
         for moduleName in moduleNames:
-            if moduleName in self.__bannedModules:
+            if self.__isModuleBanned(moduleName):
                 if any(mod.startswith(moduleName) for mod in warned):
                     # Do not show an error for this line if we already showed
                     # a more specific error.

eric ide

mercurial