Finished implementing a checker for import statements (unnecessary alias, banned relative and banned modules). eric7

Sat, 04 Dec 2021 18:06:17 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sat, 04 Dec 2021 18:06:17 +0100
branch
eric7
changeset 8808
033fa34447d0
parent 8807
f4486646a233
child 8809
29471a3867ac

Finished implementing a checker for import statements (unnecessary alias, banned relative and banned modules).

eric7/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCheckerDialog.py file | annotate | diff | comparison | revisions
eric7/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCheckerDialog.ui file | annotate | diff | comparison | revisions
eric7/Plugins/CheckerPlugins/CodeStyleChecker/Imports/ImportNode.py file | annotate | diff | comparison | revisions
eric7/Plugins/CheckerPlugins/CodeStyleChecker/Imports/ImportsChecker.py file | annotate | diff | comparison | revisions
eric7/Plugins/CheckerPlugins/CodeStyleChecker/Imports/translations.py file | annotate | diff | comparison | revisions
--- a/eric7/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCheckerDialog.py	Sat Dec 04 17:41:18 2021 +0100
+++ b/eric7/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCheckerDialog.py	Sat Dec 04 18:06:17 2021 +0100
@@ -405,6 +405,35 @@
         self.__statistics["_IssuesFixed"] = 0
         self.__statistics["_SecurityOK"] = 0
     
+    def __getBanRelativeImportsValue(self):
+        """
+        Private method to get the value corresponding the selected button.
+        
+        @return value for the BanRelativeImports argument
+        @rtype str
+        """
+        if self.banParentsButton.isChecked():
+            return "parents"
+        elif self.banAllButton.isChecked():
+            return "true"
+        else:
+            return ""
+    
+    def __setBanRelativeImports(self, value):
+        """
+        Private method to set the button according to the ban relative imports
+        setting.
+        
+        @param value value of the ban relative imports setting
+        @type str
+        """
+        if value == "parents":
+            self.banParentsButton.setChecked(True)
+        elif value == "true":
+            self.banAllButton.setChecked(True)
+        else:
+            self.allowAllButton.setChecked(True)
+    
     def prepare(self, fileList, project):
         """
         Public method to prepare the dialog with a list of filenames.
@@ -549,6 +578,8 @@
         if "ImportsChecker" not in self.__data:
             self.__data["ImportsChecker"] = {
                 "ApplicationPackageNames": [],
+                "BannedModules": [],
+                "BanRelativeImports": "",
             }
         
         self.__initCategoriesList(self.__data["EnabledCheckerCategories"])
@@ -815,6 +846,9 @@
             importsArgs = {
                 "ApplicationPackageNames":
                     sorted(self.appPackagesEdit.toPlainText().split()),
+                "BannedModules":
+                    sorted(self.bannedModulesEdit.toPlainText().split()),
+                "BanRelativeImports": self.__getBanRelativeImportsValue(),
             }
             
             self.__options = [excludeMessages, includeMessages, repeatMessages,
@@ -1251,7 +1285,10 @@
                 },
                 "ImportsChecker": {
                     "ApplicationPackageNames":
-                        sorted(self.appPackagesEdit.toPlainText().split())
+                        sorted(self.appPackagesEdit.toPlainText().split()),
+                    "BannedModules":
+                        sorted(self.bannedModulesEdit.toPlainText().split()),
+                    "BanRelativeImports": self.__getBanRelativeImportsValue(),
                 },
             }
             if (
@@ -1599,6 +1636,12 @@
         self.appPackagesEdit.setPlainText(" ".join(
             sorted(Preferences.toList(Preferences.getSettings().value(
                 "PEP8/ApplicationPackageNames", [])))))
+        self.bannedModulesEdit.setPlainText(" ".join(
+            sorted(Preferences.toList(Preferences.getSettings().value(
+                "PEP8/BannedModules", [])))))
+        self.__setBanRelativeImports(
+            Preferences.getSettings().value(
+                "PEP8/BanRelativeImports", ""))
         
         self.__cleanupData()
     
@@ -1740,6 +1783,12 @@
         Preferences.getSettings().setValue(
             "PEP8/ApplicationPackageNames",
             sorted(self.appPackagesEdit.toPlainText().split()))
+        Preferences.getSettings().setValue(
+            "PEP8/BannedModules",
+            sorted(self.bannedModulesEdit.toPlainText().split()))
+        Preferences.getSettings().setValue(
+            "PEP8/BanRelativeImports",
+            self.__getBanRelativeImportsValue())
     
     @pyqtSlot()
     def on_resetDefaultButton_clicked(self):
@@ -1868,6 +1917,10 @@
         # Imports Checker
         Preferences.getSettings().setValue(
             "PEP8/ApplicationPackageNames", [])
+        Preferences.getSettings().setValue(
+            "PEP8/BannedModules", [])
+        Preferences.getSettings().setValue(
+            "PEP8/BanRelativeImports", "")
         
         # Update UI with default values
         self.on_loadDefaultButton_clicked()
--- a/eric7/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCheckerDialog.ui	Sat Dec 04 17:41:18 2021 +0100
+++ b/eric7/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCheckerDialog.ui	Sat Dec 04 18:06:17 2021 +0100
@@ -39,7 +39,7 @@
          </property>
          <widget class="QWidget" name="globalOptionsTab">
           <attribute name="title">
-           <string>Global Options</string>
+           <string>Globals</string>
           </attribute>
           <layout class="QGridLayout" name="gridLayout_2">
            <item row="0" column="0">
@@ -245,7 +245,7 @@
          </widget>
          <widget class="QWidget" name="specificOptionsTab">
           <attribute name="title">
-           <string>Specific Options</string>
+           <string>Specifics</string>
           </attribute>
           <layout class="QVBoxLayout" name="verticalLayout_9">
            <item>
@@ -267,8 +267,8 @@
                <rect>
                 <x>0</x>
                 <y>0</y>
-                <width>365</width>
-                <height>1152</height>
+                <width>611</width>
+                <height>923</height>
                </rect>
               </property>
               <layout class="QVBoxLayout" name="verticalLayout_4">
@@ -725,292 +725,332 @@
                  </layout>
                 </widget>
                </item>
-               <item>
-                <widget class="QGroupBox" name="groupBox_3">
-                 <property name="title">
-                  <string>Code Complexity</string>
-                 </property>
-                 <layout class="QGridLayout" name="gridLayout_4">
-                  <item row="0" column="2" rowspan="2">
-                   <spacer name="horizontalSpacer_5">
-                    <property name="orientation">
-                     <enum>Qt::Horizontal</enum>
-                    </property>
-                    <property name="sizeHint" stdset="0">
-                     <size>
-                      <width>313</width>
-                      <height>20</height>
-                     </size>
-                    </property>
-                   </spacer>
-                  </item>
-                  <item row="0" column="0">
-                   <widget class="QLabel" name="label_8">
-                    <property name="text">
-                     <string>Max. McCabe Complexity:</string>
-                    </property>
-                   </widget>
-                  </item>
-                  <item row="0" column="1">
-                   <widget class="QSpinBox" name="complexitySpinBox">
-                    <property name="toolTip">
-                     <string>Enter the maximum allowed code complexity (McCabe: 10)</string>
-                    </property>
-                    <property name="alignment">
-                     <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
-                    </property>
-                    <property name="maximum">
-                     <number>100</number>
-                    </property>
-                    <property name="value">
-                     <number>10</number>
-                    </property>
-                   </widget>
-                  </item>
-                  <item row="1" column="0">
-                   <widget class="QLabel" name="label_13">
-                    <property name="text">
-                     <string>Max. Line Complexity:</string>
-                    </property>
-                   </widget>
-                  </item>
-                  <item row="1" column="1">
-                   <widget class="QSpinBox" name="lineComplexitySpinBox">
-                    <property name="toolTip">
-                     <string>Enter the maximum complexity (number of nodes) for a line of code</string>
-                    </property>
-                    <property name="alignment">
-                     <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
-                    </property>
-                    <property name="maximum">
-                     <number>100</number>
-                    </property>
-                    <property name="value">
-                     <number>15</number>
-                    </property>
-                   </widget>
-                  </item>
-                  <item row="2" column="0">
-                   <widget class="QLabel" name="label_14">
-                    <property name="text">
-                     <string>Max. Line Complexity Score:</string>
-                    </property>
-                   </widget>
-                  </item>
-                  <item row="2" column="1">
-                   <widget class="QSpinBox" name="lineComplexityScoreSpinBox">
-                    <property name="toolTip">
-                     <string>Enter the maximum allowed median for line complexity</string>
-                    </property>
-                    <property name="alignment">
-                     <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
-                    </property>
-                    <property name="maximum">
-                     <number>100</number>
-                    </property>
-                    <property name="value">
-                     <number>10</number>
-                    </property>
-                   </widget>
-                  </item>
-                 </layout>
-                </widget>
-               </item>
-               <item>
-                <widget class="QGroupBox" name="groupBox_10">
-                 <property name="title">
-                  <string>Type Annotations</string>
-                 </property>
-                 <layout class="QVBoxLayout" name="verticalLayout_3">
-                  <item>
-                   <layout class="QGridLayout" name="gridLayout_6">
-                    <item row="0" column="0">
-                     <widget class="QLabel" name="label_18">
-                      <property name="text">
-                       <string>Min. Coverage:</string>
-                      </property>
-                     </widget>
-                    </item>
-                    <item row="0" column="1">
-                     <widget class="QSpinBox" name="minAnnotationsCoverageSpinBox">
-                      <property name="toolTip">
-                       <string>Enter the minimum percentage of type annotations</string>
-                      </property>
-                      <property name="alignment">
-                       <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
-                      </property>
-                      <property name="specialValueText">
-                       <string>off</string>
-                      </property>
-                      <property name="suffix">
-                       <string>%</string>
-                      </property>
-                      <property name="maximum">
-                       <number>100</number>
-                      </property>
-                     </widget>
-                    </item>
-                    <item row="0" column="2">
-                     <spacer name="horizontalSpacer_7">
-                      <property name="orientation">
-                       <enum>Qt::Horizontal</enum>
-                      </property>
-                      <property name="sizeHint" stdset="0">
-                       <size>
-                        <width>352</width>
-                        <height>20</height>
-                       </size>
-                      </property>
-                     </spacer>
-                    </item>
-                    <item row="1" column="0">
-                     <widget class="QLabel" name="label_19">
-                      <property name="text">
-                       <string>Max. Complexity:</string>
-                      </property>
-                     </widget>
-                    </item>
-                    <item row="1" column="1">
-                     <widget class="QSpinBox" name="maxAnnotationsComplexitySpinBox">
-                      <property name="toolTip">
-                       <string>Enter the maximum type annotation complexity</string>
-                      </property>
-                      <property name="alignment">
-                       <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
-                      </property>
-                      <property name="minimum">
-                       <number>1</number>
-                      </property>
-                      <property name="maximum">
-                       <number>9</number>
-                      </property>
-                     </widget>
-                    </item>
-                    <item row="2" column="0">
-                     <widget class="QLabel" name="label_32">
-                      <property name="text">
-                       <string>Max. Length:</string>
-                      </property>
-                     </widget>
-                    </item>
-                    <item row="2" column="1">
-                     <widget class="QSpinBox" name="maxAnnotationsLengthSpinBox">
-                      <property name="toolTip">
-                       <string>Enter the maximum type annotation length</string>
-                      </property>
-                      <property name="alignment">
-                       <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
-                      </property>
-                      <property name="minimum">
-                       <number>1</number>
-                      </property>
-                      <property name="maximum">
-                       <number>15</number>
-                      </property>
-                     </widget>
-                    </item>
-                   </layout>
-                  </item>
-                  <item>
-                   <layout class="QGridLayout" name="gridLayout_9">
-                    <item row="0" column="0">
-                     <widget class="QCheckBox" name="suppressNoneReturningCheckBox">
-                      <property name="toolTip">
-                       <string>Select to not report functions without returns or with only bare returns</string>
-                      </property>
-                      <property name="text">
-                       <string>Suppress 'None' return</string>
-                      </property>
-                     </widget>
-                    </item>
-                    <item row="0" column="1">
-                     <widget class="QCheckBox" name="suppressDummyArgsCheckBox">
-                      <property name="toolTip">
-                       <string>Select to not report dummy (i.e. '_') arguments</string>
-                      </property>
-                      <property name="text">
-                       <string>Suppress Dummy Arguments</string>
-                      </property>
-                     </widget>
-                    </item>
-                    <item row="1" column="0">
-                     <widget class="QCheckBox" name="allowUntypedDefsCheckBox">
-                      <property name="toolTip">
-                       <string>Select to not report dynamically typed functions</string>
-                      </property>
-                      <property name="text">
-                       <string>Allow Untyped Functions</string>
-                      </property>
-                     </widget>
-                    </item>
-                    <item row="1" column="1">
-                     <widget class="QCheckBox" name="allowUntypedNestedCheckBox">
-                      <property name="toolTip">
-                       <string>Select to not report dynamically typed nested functions</string>
-                      </property>
-                      <property name="text">
-                       <string>Allow Untyped Nested Functions</string>
-                      </property>
-                     </widget>
-                    </item>
-                    <item row="2" column="0" colspan="2">
-                     <widget class="QCheckBox" name="mypyInitReturnCheckBox">
-                      <property name="toolTip">
-                       <string>Select to not report unhinted '__init__' return</string>
-                      </property>
-                      <property name="text">
-                       <string>Allow Untyped '__init__' function</string>
-                      </property>
-                     </widget>
-                    </item>
-                   </layout>
-                  </item>
-                  <item>
-                   <widget class="QLabel" name="label_33">
-                    <property name="text">
-                     <string>Dispatch Decorators:</string>
-                    </property>
-                   </widget>
-                  </item>
-                  <item>
-                   <widget class="QLineEdit" name="dispatchDecoratorEdit">
-                    <property name="toolTip">
-                     <string>Enter the list of dispatch decorators separated by comma</string>
-                    </property>
-                    <property name="clearButtonEnabled">
-                     <bool>true</bool>
-                    </property>
-                   </widget>
-                  </item>
-                  <item>
-                   <widget class="QLabel" name="label_34">
-                    <property name="text">
-                     <string>Overload Decorators:</string>
-                    </property>
-                   </widget>
-                  </item>
-                  <item>
-                   <widget class="QLineEdit" name="overloadDecoratorEdit">
-                    <property name="toolTip">
-                     <string>Enter the list of typing.overload decorators separated by comma</string>
-                    </property>
-                    <property name="clearButtonEnabled">
-                     <bool>true</bool>
-                    </property>
-                   </widget>
-                  </item>
-                 </layout>
-                </widget>
-               </item>
               </layout>
              </widget>
             </widget>
            </item>
           </layout>
          </widget>
+         <widget class="QWidget" name="codeComplexityTab">
+          <attribute name="title">
+           <string>Complexity</string>
+          </attribute>
+          <layout class="QVBoxLayout" name="verticalLayout_17">
+           <item>
+            <widget class="QGroupBox" name="groupBox_3">
+             <property name="title">
+              <string>Code Complexity</string>
+             </property>
+             <layout class="QGridLayout" name="gridLayout_4">
+              <item row="0" column="2" rowspan="2">
+               <spacer name="horizontalSpacer_5">
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>313</width>
+                  <height>20</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+              <item row="0" column="0">
+               <widget class="QLabel" name="label_8">
+                <property name="text">
+                 <string>Max. McCabe Complexity:</string>
+                </property>
+               </widget>
+              </item>
+              <item row="0" column="1">
+               <widget class="QSpinBox" name="complexitySpinBox">
+                <property name="toolTip">
+                 <string>Enter the maximum allowed code complexity (McCabe: 10)</string>
+                </property>
+                <property name="alignment">
+                 <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+                </property>
+                <property name="maximum">
+                 <number>100</number>
+                </property>
+                <property name="value">
+                 <number>10</number>
+                </property>
+               </widget>
+              </item>
+              <item row="1" column="0">
+               <widget class="QLabel" name="label_13">
+                <property name="text">
+                 <string>Max. Line Complexity:</string>
+                </property>
+               </widget>
+              </item>
+              <item row="1" column="1">
+               <widget class="QSpinBox" name="lineComplexitySpinBox">
+                <property name="toolTip">
+                 <string>Enter the maximum complexity (number of nodes) for a line of code</string>
+                </property>
+                <property name="alignment">
+                 <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+                </property>
+                <property name="maximum">
+                 <number>100</number>
+                </property>
+                <property name="value">
+                 <number>15</number>
+                </property>
+               </widget>
+              </item>
+              <item row="2" column="0">
+               <widget class="QLabel" name="label_14">
+                <property name="text">
+                 <string>Max. Line Complexity Score:</string>
+                </property>
+               </widget>
+              </item>
+              <item row="2" column="1">
+               <widget class="QSpinBox" name="lineComplexityScoreSpinBox">
+                <property name="toolTip">
+                 <string>Enter the maximum allowed median for line complexity</string>
+                </property>
+                <property name="alignment">
+                 <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+                </property>
+                <property name="maximum">
+                 <number>100</number>
+                </property>
+                <property name="value">
+                 <number>10</number>
+                </property>
+               </widget>
+              </item>
+             </layout>
+            </widget>
+           </item>
+           <item>
+            <spacer name="verticalSpacer_8">
+             <property name="orientation">
+              <enum>Qt::Vertical</enum>
+             </property>
+             <property name="sizeHint" stdset="0">
+              <size>
+               <width>20</width>
+               <height>802</height>
+              </size>
+             </property>
+            </spacer>
+           </item>
+          </layout>
+         </widget>
+         <widget class="QWidget" name="typeAnnotationsTab">
+          <attribute name="title">
+           <string>Annotations</string>
+          </attribute>
+          <layout class="QVBoxLayout" name="verticalLayout_18">
+           <item>
+            <widget class="QGroupBox" name="groupBox_10">
+             <property name="title">
+              <string>Type Annotations</string>
+             </property>
+             <layout class="QVBoxLayout" name="verticalLayout_3">
+              <item>
+               <layout class="QGridLayout" name="gridLayout_6">
+                <item row="0" column="0">
+                 <widget class="QLabel" name="label_18">
+                  <property name="text">
+                   <string>Min. Coverage:</string>
+                  </property>
+                 </widget>
+                </item>
+                <item row="0" column="1">
+                 <widget class="QSpinBox" name="minAnnotationsCoverageSpinBox">
+                  <property name="toolTip">
+                   <string>Enter the minimum percentage of type annotations</string>
+                  </property>
+                  <property name="alignment">
+                   <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+                  </property>
+                  <property name="specialValueText">
+                   <string>off</string>
+                  </property>
+                  <property name="suffix">
+                   <string>%</string>
+                  </property>
+                  <property name="maximum">
+                   <number>100</number>
+                  </property>
+                 </widget>
+                </item>
+                <item row="0" column="2">
+                 <spacer name="horizontalSpacer_7">
+                  <property name="orientation">
+                   <enum>Qt::Horizontal</enum>
+                  </property>
+                  <property name="sizeHint" stdset="0">
+                   <size>
+                    <width>352</width>
+                    <height>20</height>
+                   </size>
+                  </property>
+                 </spacer>
+                </item>
+                <item row="1" column="0">
+                 <widget class="QLabel" name="label_19">
+                  <property name="text">
+                   <string>Max. Complexity:</string>
+                  </property>
+                 </widget>
+                </item>
+                <item row="1" column="1">
+                 <widget class="QSpinBox" name="maxAnnotationsComplexitySpinBox">
+                  <property name="toolTip">
+                   <string>Enter the maximum type annotation complexity</string>
+                  </property>
+                  <property name="alignment">
+                   <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+                  </property>
+                  <property name="minimum">
+                   <number>1</number>
+                  </property>
+                  <property name="maximum">
+                   <number>9</number>
+                  </property>
+                 </widget>
+                </item>
+                <item row="2" column="0">
+                 <widget class="QLabel" name="label_32">
+                  <property name="text">
+                   <string>Max. Length:</string>
+                  </property>
+                 </widget>
+                </item>
+                <item row="2" column="1">
+                 <widget class="QSpinBox" name="maxAnnotationsLengthSpinBox">
+                  <property name="toolTip">
+                   <string>Enter the maximum type annotation length</string>
+                  </property>
+                  <property name="alignment">
+                   <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+                  </property>
+                  <property name="minimum">
+                   <number>1</number>
+                  </property>
+                  <property name="maximum">
+                   <number>15</number>
+                  </property>
+                 </widget>
+                </item>
+               </layout>
+              </item>
+              <item>
+               <layout class="QGridLayout" name="gridLayout_9">
+                <item row="0" column="0">
+                 <widget class="QCheckBox" name="suppressNoneReturningCheckBox">
+                  <property name="toolTip">
+                   <string>Select to not report functions without returns or with only bare returns</string>
+                  </property>
+                  <property name="text">
+                   <string>Suppress 'None' return</string>
+                  </property>
+                 </widget>
+                </item>
+                <item row="0" column="1">
+                 <widget class="QCheckBox" name="suppressDummyArgsCheckBox">
+                  <property name="toolTip">
+                   <string>Select to not report dummy (i.e. '_') arguments</string>
+                  </property>
+                  <property name="text">
+                   <string>Suppress Dummy Arguments</string>
+                  </property>
+                 </widget>
+                </item>
+                <item row="1" column="0">
+                 <widget class="QCheckBox" name="allowUntypedDefsCheckBox">
+                  <property name="toolTip">
+                   <string>Select to not report dynamically typed functions</string>
+                  </property>
+                  <property name="text">
+                   <string>Allow Untyped Functions</string>
+                  </property>
+                 </widget>
+                </item>
+                <item row="1" column="1">
+                 <widget class="QCheckBox" name="allowUntypedNestedCheckBox">
+                  <property name="toolTip">
+                   <string>Select to not report dynamically typed nested functions</string>
+                  </property>
+                  <property name="text">
+                   <string>Allow Untyped Nested Functions</string>
+                  </property>
+                 </widget>
+                </item>
+                <item row="2" column="0" colspan="2">
+                 <widget class="QCheckBox" name="mypyInitReturnCheckBox">
+                  <property name="toolTip">
+                   <string>Select to not report unhinted '__init__' return</string>
+                  </property>
+                  <property name="text">
+                   <string>Allow Untyped '__init__' function</string>
+                  </property>
+                 </widget>
+                </item>
+               </layout>
+              </item>
+              <item>
+               <widget class="QLabel" name="label_33">
+                <property name="text">
+                 <string>Dispatch Decorators:</string>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <widget class="QLineEdit" name="dispatchDecoratorEdit">
+                <property name="toolTip">
+                 <string>Enter the list of dispatch decorators separated by comma</string>
+                </property>
+                <property name="clearButtonEnabled">
+                 <bool>true</bool>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <widget class="QLabel" name="label_34">
+                <property name="text">
+                 <string>Overload Decorators:</string>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <widget class="QLineEdit" name="overloadDecoratorEdit">
+                <property name="toolTip">
+                 <string>Enter the list of typing.overload decorators separated by comma</string>
+                </property>
+                <property name="clearButtonEnabled">
+                 <bool>true</bool>
+                </property>
+               </widget>
+              </item>
+             </layout>
+            </widget>
+           </item>
+           <item>
+            <spacer name="verticalSpacer_9">
+             <property name="orientation">
+              <enum>Qt::Vertical</enum>
+             </property>
+             <property name="sizeHint" stdset="0">
+              <size>
+               <width>20</width>
+               <height>596</height>
+              </size>
+             </property>
+            </spacer>
+           </item>
+          </layout>
+         </widget>
          <widget class="QWidget" name="securityOptionsTab">
           <attribute name="title">
-           <string>Security Options</string>
+           <string>Security</string>
           </attribute>
           <layout class="QGridLayout" name="gridLayout_7">
            <item row="0" column="0">
@@ -1257,7 +1297,7 @@
           <attribute name="title">
            <string>Imports</string>
           </attribute>
-          <layout class="QVBoxLayout" name="verticalLayout_15">
+          <layout class="QVBoxLayout" name="verticalLayout_16">
            <item>
             <widget class="QGroupBox" name="groupBox_15">
              <property name="title">
@@ -1275,7 +1315,79 @@
                </widget>
               </item>
               <item>
-               <widget class="QPlainTextEdit" name="appPackagesEdit"/>
+               <widget class="QPlainTextEdit" name="appPackagesEdit">
+                <property name="tabChangesFocus">
+                 <bool>true</bool>
+                </property>
+               </widget>
+              </item>
+             </layout>
+            </widget>
+           </item>
+           <item>
+            <widget class="QGroupBox" name="groupBox_16">
+             <property name="title">
+              <string>Banned Modules</string>
+             </property>
+             <layout class="QVBoxLayout" name="verticalLayout_15">
+              <item>
+               <widget class="QLabel" name="label_36">
+                <property name="text">
+                 <string>Enter the name of modules to be banned separated by a space character:</string>
+                </property>
+                <property name="wordWrap">
+                 <bool>true</bool>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <widget class="QPlainTextEdit" name="bannedModulesEdit">
+                <property name="tabChangesFocus">
+                 <bool>true</bool>
+                </property>
+               </widget>
+              </item>
+             </layout>
+            </widget>
+           </item>
+           <item>
+            <widget class="QGroupBox" name="groupBox_17">
+             <property name="title">
+              <string>Ban Relative Imports</string>
+             </property>
+             <layout class="QHBoxLayout" name="horizontalLayout_12">
+              <item>
+               <widget class="QRadioButton" name="allowAllButton">
+                <property name="toolTip">
+                 <string>Select to allow relative imports</string>
+                </property>
+                <property name="text">
+                 <string>Allow</string>
+                </property>
+                <property name="checked">
+                 <bool>true</bool>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <widget class="QRadioButton" name="banParentsButton">
+                <property name="toolTip">
+                 <string>Select to ban relative imports of parents</string>
+                </property>
+                <property name="text">
+                 <string>Ban Parents Import</string>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <widget class="QRadioButton" name="banAllButton">
+                <property name="toolTip">
+                 <string>Select to ban all relative imports</string>
+                </property>
+                <property name="text">
+                 <string>Ban All</string>
+                </property>
+               </widget>
               </item>
              </layout>
             </widget>
@@ -1691,10 +1803,10 @@
   <tabstop>maxAnnotationsComplexitySpinBox</tabstop>
   <tabstop>maxAnnotationsLengthSpinBox</tabstop>
   <tabstop>suppressNoneReturningCheckBox</tabstop>
+  <tabstop>allowUntypedDefsCheckBox</tabstop>
+  <tabstop>mypyInitReturnCheckBox</tabstop>
   <tabstop>suppressDummyArgsCheckBox</tabstop>
-  <tabstop>allowUntypedDefsCheckBox</tabstop>
   <tabstop>allowUntypedNestedCheckBox</tabstop>
-  <tabstop>mypyInitReturnCheckBox</tabstop>
   <tabstop>dispatchDecoratorEdit</tabstop>
   <tabstop>overloadDecoratorEdit</tabstop>
   <tabstop>tmpDirectoriesEdit</tabstop>
@@ -1708,6 +1820,10 @@
   <tabstop>ecMediumRiskCombo</tabstop>
   <tabstop>typedExceptionsCheckBox</tabstop>
   <tabstop>appPackagesEdit</tabstop>
+  <tabstop>bannedModulesEdit</tabstop>
+  <tabstop>allowAllButton</tabstop>
+  <tabstop>banParentsButton</tabstop>
+  <tabstop>banAllButton</tabstop>
   <tabstop>startButton</tabstop>
   <tabstop>loadDefaultButton</tabstop>
   <tabstop>storeDefaultButton</tabstop>
--- a/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Imports/ImportNode.py	Sat Dec 04 17:41:18 2021 +0100
+++ b/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Imports/ImportNode.py	Sat Dec 04 18:06:17 2021 +0100
@@ -42,10 +42,7 @@
         @exception ImportNodeException raised to indicate an invalid node was
             given to this class
         """
-        if (
-            self.nodeType not in (NodeTypeEnum.IMPORT,
-                                  NodeTypeEnum.IMPORT_FROM)
-        ):
+        if not isinstance(astNode, (ast.Import, ast.ImportFrom)):
             raise ImportNodeException(
                 "Node type {0} not recognized".format(type(astNode))
             )
--- a/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Imports/ImportsChecker.py	Sat Dec 04 17:41:18 2021 +0100
+++ b/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Imports/ImportsChecker.py	Sat Dec 04 18:06:17 2021 +0100
@@ -22,6 +22,9 @@
         
         ## Imports order
         "I201", "I202", "I203", "I204",
+        
+        ## Various other import related
+        "I901", "I902", "I903", "I904",
     ]
 
     def __init__(self, source, filename, tree, select, ignore, expected,
@@ -63,7 +66,8 @@
         
         checkersWithCodes = [
             (self.__checkLocalImports, ("I101", "I102", "I103")),
-            (self.__checkImportOrder, ("I201", "I202", "I203", "I204"))
+            (self.__checkImportOrder, ("I201", "I202", "I203", "I204")),
+            (self.__tidyImports, ("I901", "I902", "I903", "I904")),
         ]
         
         self.__checkers = []
@@ -321,3 +325,130 @@
                 return (node, "I204", ", ".join(expectedList))
         
         return None
+    
+    #######################################################################
+    ## Tidy imports
+    ##
+    ## adapted from: flake8-tidy-imports v4.5.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", "")
+        
+        ruleMethods = []
+        if not self.__ignoreCode("I901"):
+            ruleMethods.append(self.__checkUnnecessaryAlias)
+        if (
+            not self.__ignoreCode("I902")
+            and bool(self.__bannedModules)
+        ):
+            ruleMethods.append(self.__checkBannedImport)
+        if (
+            (not self.__ignoreCode("I903") and
+             self.__banRelativeImports == "parents") or
+            (not self.__ignoreCode("I904") and
+             self.__banRelativeImports == "true")
+        ):
+            ruleMethods.append(self.__checkBannedRelativeImports)
+        
+        for node in ast.walk(self.__tree):
+            for method in ruleMethods:
+                method(node)
+    
+    def __checkUnnecessaryAlias(self, node):
+        """
+        Private method to check unnecessary import aliases.
+        
+        @param node reference to the node to be checked
+        @type ast.AST
+        """
+        if isinstance(node, ast.Import):
+            for alias in node.names:
+                if "." not in alias.name:
+                    fromName = None
+                    importedName = alias.name
+                else:
+                    fromName, importedName = alias.name.rsplit(".", 1)
+                
+                if importedName == alias.asname:
+                    if fromName:
+                        rewritten = "from {0} import {1}".format(
+                            fromName, importedName)
+                    else:
+                        rewritten = "import {0}".format(importedName)
+                    
+                    self.__error(node.lineno - 1, node.col_offset, "I901",
+                                 rewritten)
+        
+        elif isinstance(node, ast.ImportFrom):
+            for alias in node.names:
+                if alias.name == alias.asname:
+                    rewritten = "from {0} import {1}".format(
+                        node.module, alias.name)
+                    
+                    self.__error(node.lineno - 1, node.col_offset, "I901",
+                                 rewritten)
+    
+    def __checkBannedImport(self, node):
+        """
+        Private method to check import of banned modules.
+        
+        @param node reference to the node to be checked
+        @type ast.AST
+        """
+        if not bool(self.__bannedModules):
+            return
+        
+        if isinstance(node, ast.Import):
+            moduleNames = [alias.name for alias in node.names]
+        elif isinstance(node, ast.ImportFrom):
+            nodeModule = node.module or ""
+            moduleNames = [nodeModule]
+            for alias in node.names:
+                moduleNames.append("{0}.{1}".format(nodeModule, alias.name))
+        else:
+            return
+        
+        # Sort from most to least specific paths.
+        moduleNames.sort(key=len, reverse=True)
+        
+        warned = set()
+        
+        for moduleName in moduleNames:
+            if moduleName in self.__bannedModules:
+                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.
+                    continue
+                else:
+                    warned.add(moduleName)
+                self.__error(node.lineno - 1, node.col_offset, "I902",
+                             moduleName)
+    
+    def __checkBannedRelativeImports(self, node):
+        """
+        Private method to check if relative imports are banned.
+        
+        @param node reference to the node to be checked
+        @type ast.AST
+        """
+        if not self.__banRelativeImports:
+            return
+        
+        elif self.__banRelativeImports == "parents":
+            minNodeLevel = 1
+            msgCode = "I903"
+        else:
+            minNodeLevel = 0
+            msgCode = "I904"
+        
+        if (
+            self.__banRelativeImports and
+            isinstance(node, ast.ImportFrom) and
+            node.level > minNodeLevel
+        ):
+            self.__error(node.lineno - 1, node.col_offset, msgCode)
--- a/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Imports/translations.py	Sat Dec 04 17:41:18 2021 +0100
+++ b/eric7/Plugins/CheckerPlugins/CodeStyleChecker/Imports/translations.py	Sat Dec 04 18:06:17 2021 +0100
@@ -28,7 +28,7 @@
     "I202": QCoreApplication.translate(
         "ImportsChecker",
         "Imported names are in the wrong order. "
-        "Should be {0}"),
+        "Should be '{0}'"),
     "I203": QCoreApplication.translate(
         "ImportsChecker",
         "Import statements should be combined. "
@@ -36,12 +36,27 @@
     "I204": QCoreApplication.translate(
         "ImportsChecker",
         "The names in __all__ are in the wrong order. "
-        "The order should be {0}"),
+        "The order should be '{0}'"),
+    
+    "I901": QCoreApplication.translate(
+        "ImportsChecker",
+        "unnecessary import alias - rewrite as '{0}'"),
+    "I902": QCoreApplication.translate(
+        "ImportsChecker",
+        "banned import '{0}' used"),
+    "I903": QCoreApplication.translate(
+        "ImportsChecker",
+        "relative imports from parent modules are banned"),
+    "I904": QCoreApplication.translate(
+        "ImportsChecker",
+        "relative imports are banned"),
 }
 
 _importsMessagesSampleArgs = {
-    "I201": ["import os", "import sys"],
-    "I202": ["copy, os, sys"],
+    "I201": ["import bar", "import foo"],
+    "I202": ["bar, baz, foo"],
     "I203": ["from foo import bar", "from foo import baz"],
     "I204": ["bar, baz, foo"],
+    "I901": ["from foo import bar"],
+    "I902": ["foo"],
 }

eric ide

mercurial