Made the built-ins checker configurable.

Fri, 17 Mar 2017 19:09:39 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Fri, 17 Mar 2017 19:09:39 +0100
changeset 5619
ab999dc48132
parent 5618
b50da40b6bc9
child 5620
6bca68319bb4

Made the built-ins checker configurable.

Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleAddBuiltinIgnoreDialog.py file | annotate | diff | comparison | revisions
Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleAddBuiltinIgnoreDialog.ui file | annotate | diff | comparison | revisions
Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleChecker.py file | annotate | diff | comparison | revisions
Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCheckerDialog.py file | annotate | diff | comparison | revisions
Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCheckerDialog.ui file | annotate | diff | comparison | revisions
Plugins/CheckerPlugins/CodeStyleChecker/MiscellaneousChecker.py file | annotate | diff | comparison | revisions
eric6.e4p file | annotate | diff | comparison | revisions
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleAddBuiltinIgnoreDialog.py	Fri Mar 17 19:09:39 2017 +0100
@@ -0,0 +1,74 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2017 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a dialog to enter the data for a built-in assignment to
+be ignored.
+"""
+
+from PyQt5.QtCore import pyqtSlot
+from PyQt5.QtWidgets import QDialog, QDialogButtonBox
+
+from .Ui_CodeStyleAddBuiltinIgnoreDialog import \
+    Ui_CodeStyleAddBuiltinIgnoreDialog
+
+
+class CodeStyleAddBuiltinIgnoreDialog(QDialog, 
+                                      Ui_CodeStyleAddBuiltinIgnoreDialog):
+    """
+    Class implementing a dialog to enter the data for a built-in assignment to
+    be ignored.
+    """
+    def __init__(self, parent=None):
+        """
+        Constructor
+        
+        @param parent reference to the parent widget
+        @type QWidget
+        """
+        super(CodeStyleAddBuiltinIgnoreDialog, self).__init__(parent)
+        self.setupUi(self)
+        
+        self.__updateOkButton
+        
+        msh = self.minimumSizeHint()
+        self.resize(max(self.width(), msh.width()), msh.height())
+    
+    def __updateOkButton(self):
+        """
+        Private slot to set the state of the OK button.
+        """
+        self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(
+            bool(self.leftEdit.text()) and
+            bool(self.rightEdit.text()))
+    
+    @pyqtSlot(str)
+    def on_leftEdit_textChanged(self, txt):
+        """
+        Private slot to handle a change of the text of the left side edit.
+        
+        @param txt text of the line edit
+        @type str
+        """
+        self.__updateOkButton()
+    
+    @pyqtSlot(str)
+    def on_rightEdit_textChanged(self, txt):
+        """
+        Private slot to handle a change of the text of the right side edit.
+        
+        @param txt text of the line edit
+        @type str
+        """
+        self.__updateOkButton()
+    
+    def getData(self):
+        """
+        Public method to get the entered data.
+        
+        @return tuple containing the left and right hand side of the assignment
+        @rtype tuple of two str
+        """
+        return self.leftEdit.text(), self.rightEdit.text()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleAddBuiltinIgnoreDialog.ui	Fri Mar 17 19:09:39 2017 +0100
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>CodeStyleAddBuiltinIgnoreDialog</class>
+ <widget class="QDialog" name="CodeStyleAddBuiltinIgnoreDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>112</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Add Built-in Assignment</string>
+  </property>
+  <property name="sizeGripEnabled">
+   <bool>true</bool>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="0" column="0" colspan="2">
+    <widget class="QLabel" name="label">
+     <property name="text">
+      <string>Enter the data for a built-in assignment to be ignored:</string>
+     </property>
+     <property name="wordWrap">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="0">
+    <widget class="QLabel" name="label_2">
+     <property name="text">
+      <string>Left Side:</string>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="1">
+    <widget class="E5ClearableLineEdit" name="leftEdit">
+     <property name="placeholderText">
+      <string>Enter left hand side of assignment</string>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="0">
+    <widget class="QLabel" name="label_3">
+     <property name="text">
+      <string>Right Side:</string>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="1">
+    <widget class="E5ClearableLineEdit" name="rightEdit">
+     <property name="placeholderText">
+      <string>Enter right hand side of assignment</string>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="0" colspan="2">
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>E5ClearableLineEdit</class>
+   <extends>QLineEdit</extends>
+   <header>E5Gui/E5LineEdit.h</header>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>CodeStyleAddBuiltinIgnoreDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>CodeStyleAddBuiltinIgnoreDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
--- a/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleChecker.py	Thu Mar 16 20:00:31 2017 +0100
+++ b/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleChecker.py	Fri Mar 17 19:09:39 2017 +0100
@@ -188,11 +188,13 @@
     @param args arguments used by the codeStyleCheck function (list of
         excludeMessages (str), includeMessages (str), repeatMessages
         (bool), fixCodes (str), noFixCodes (str), fixIssues (bool),
-        maxLineLength (int), hangClosing (bool), docType (str), errors
-        (list of str), eol (str), encoding (str), backup (bool))
-    @return tuple of stats (dict) and results (tuple for each found violation
-        of style (tuple of lineno (int), position (int), text (str), ignored
-            (bool), fixed (bool), autofixing (bool), fixedMsg (str)))
+        maxLineLength (int), hangClosing (bool), docType (str), maximum
+        allowed code complexity (int), dictionary with arguments for the
+        miscellaneous checker (dict), errors (list of str), eol (str),
+        encoding (str), backup (bool))
+    @return tuple of statistics (dict) and results (tuple for each found
+        violation of style (tuple of lineno (int), position (int), text (str),
+        ignored (bool), fixed (bool), autofixing (bool), fixedMsg (str)))
     """
     (excludeMessages, includeMessages, repeatMessages, fixCodes, noFixCodes,
      fixIssues, maxLineLength, hangClosing, docType, maxComplexity,
--- a/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCheckerDialog.py	Thu Mar 16 20:00:31 2017 +0100
+++ b/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCheckerDialog.py	Fri Mar 17 19:09:39 2017 +0100
@@ -95,6 +95,9 @@
         self.resultList.headerItem().setText(self.resultList.columnCount(), "")
         self.resultList.header().setSortIndicator(0, Qt.AscendingOrder)
         
+        self.addBuiltinButton.setIcon(UI.PixmapCache.getIcon("plus.png"))
+        self.deleteBuiltinButton.setIcon(UI.PixmapCache.getIcon("minus.png"))
+        
         self.checkProgress.setVisible(False)
         self.checkProgressLabel.setVisible(False)
         self.checkProgressLabel.setMaximumWidth(600)
@@ -325,6 +328,11 @@
             self.__data["CopyrightAuthor"] = ""
         if "FutureChecker" not in self.__data:
             self.__data["FutureChecker"] = ""
+        if "BuiltinsChecker" not in self.__data:
+            self.__data["BuiltinsChecker"] = {
+                "str": ["unicode", ],
+                "chr": ["unichr", ],
+            }
         
         self.excludeFilesEdit.setText(self.__data["ExcludeFiles"])
         self.excludeMessagesEdit.setText(self.__data["ExcludeMessages"])
@@ -344,6 +352,7 @@
             self.__data["CopyrightMinFileSize"])
         self.copyrightAuthorEdit.setText(self.__data["CopyrightAuthor"])
         self.__initFuturesList(self.__data["FutureChecker"])
+        self.__initBuiltinsIgnoreList(self.__data["BuiltinsChecker"])
     
     def start(self, fn, save=False, repeat=None):
         """
@@ -430,6 +439,7 @@
                     "Author": self.copyrightAuthorEdit.text(),
                 },
                 "FutureChecker": self.__getSelectedFutureImports(),
+                "BuiltinsChecker": self.__getBuiltinsIgnoreList(),
             }
             
             self.__options = [excludeMessages, includeMessages, repeatMessages,
@@ -755,6 +765,7 @@
                 "CopyrightMinFileSize": self.copyrightFileSizeSpinBox.value(),
                 "CopyrightAuthor": self.copyrightAuthorEdit.text(),
                 "FutureChecker": self.__getSelectedFutureImports(),
+                "BuiltinsChecker": self.__getBuiltinsIgnoreList(),
             }
             if data != self.__data:
                 self.__data = data
@@ -936,6 +947,11 @@
             Preferences.Prefs.settings.value("PEP8/CopyrightAuthor", ""))
         self.__initFuturesList(
             Preferences.Prefs.settings.value("PEP8/FutureChecker", ""))
+        self.__initBuiltinsIgnoreList(Preferences.toDict(
+            Preferences.Prefs.settings.value("PEP8/BuiltinsChecker", {
+                "str": ["unicode", ],
+                "chr": ["unichr", ],
+            })))
     
     @pyqtSlot()
     def on_storeDefaultButton_clicked(self):
@@ -976,6 +992,8 @@
             "PEP8/CopyrightAuthor", self.copyrightAuthorEdit.text())
         Preferences.Prefs.settings.setValue(
             "PEP8/FutureChecker", self.__getSelectedFutureImports())
+        Preferences.Prefs.settings.setValue(
+            "PEP8/BuiltinsChecker", self.__getBuiltinsIgnoreList())
     
     @pyqtSlot()
     def on_resetDefaultButton_clicked(self):
@@ -1001,6 +1019,10 @@
         Preferences.Prefs.settings.setValue("PEP8/CopyrightMinFileSize", 0)
         Preferences.Prefs.settings.setValue("PEP8/CopyrightAuthor", "")
         Preferences.Prefs.settings.setValue("PEP8/FutureChecker", "")
+        Preferences.Prefs.settings.setValue("PEP8/BuiltinsChecker", {
+            "str": ["unicode", ],
+            "chr": ["unichr", ],
+        })
     
     @pyqtSlot(QAbstractButton)
     def on_buttonBox_clicked(self, button):
@@ -1117,6 +1139,7 @@
         for row in range(self.futuresList.count()):
             itm = self.futuresList.item(row)
             itm.setSelected(itm.text() in expectedImports)
+        # TODO: change this to checkable items
     
     def __getSelectedFutureImports(self):
         """
@@ -1127,3 +1150,66 @@
         """
         selectedFutures = [i.text() for i in self.futuresList.selectedItems()]
         return ", ".join(selectedFutures)
+    
+    def __initBuiltinsIgnoreList(self, builtinsIgnoreDict):
+        """
+        Private method to populate the list of shadowed builtins to be ignored.
+        
+        @param builtinsIgnoreDict dictionary containing the builtins
+            assignments to be ignored
+        @type dict of list of str
+        """
+        self.builtinsAssignmentList.clear()
+        for left, rightList in builtinsIgnoreDict.items():
+            for right in rightList:
+                QTreeWidgetItem(self.builtinsAssignmentList, [left, right])
+        
+        self.on_builtinsAssignmentList_itemSelectionChanged()
+    
+    def __getBuiltinsIgnoreList(self):
+        """
+        Private method to get a dictionary containing the builtins assignments
+        to be ignored.
+        
+        @return dictionary containing the builtins assignments to be ignored
+        @rtype dict of list of str
+        """
+        builtinsIgnoreDict = {}
+        for row in range(self.builtinsAssignmentList.topLevelItemCount()):
+            itm = self.builtinsAssignmentList.topLevelItem(row)
+            left, right = itm.text(0), itm.text(1)
+            if left not in builtinsIgnoreDict:
+                builtinsIgnoreDict[left] = []
+            builtinsIgnoreDict[left].append(right)
+        
+        return builtinsIgnoreDict
+    
+    @pyqtSlot()
+    def on_builtinsAssignmentList_itemSelectionChanged(self):
+        """
+        Private slot to react upon changes of the selected builtin assignments.
+        """
+        self.deleteBuiltinButton.setEnabled(
+            len(self.builtinsAssignmentList.selectedItems()) > 0)
+    
+    @pyqtSlot()
+    def on_addBuiltinButton_clicked(self):
+        """
+        Slot documentation goes here.
+        """
+        from .CodeStyleAddBuiltinIgnoreDialog import \
+            CodeStyleAddBuiltinIgnoreDialog
+        dlg = CodeStyleAddBuiltinIgnoreDialog(self)
+        if dlg.exec_() == QDialog.Accepted:
+            left,  right = dlg.getData()
+            QTreeWidgetItem(self.builtinsAssignmentList, [left, right])
+    
+    @pyqtSlot()
+    def on_deleteBuiltinButton_clicked(self):
+        """
+        Private slot to delete the selected items from the list.
+        """
+        for itm in self.builtinsAssignmentList.selectedItems():
+            index = self.builtinsAssignmentList.indexOfTopLevelItem(itm)
+            self.builtinsAssignmentList.takeTopLevelItem(index)
+            del itm
--- a/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCheckerDialog.ui	Thu Mar 16 20:00:31 2017 +0100
+++ b/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCheckerDialog.ui	Fri Mar 17 19:09:39 2017 +0100
@@ -21,8 +21,8 @@
   <property name="sizeGripEnabled">
    <bool>true</bool>
   </property>
-  <layout class="QVBoxLayout" name="verticalLayout_5">
-   <item>
+  <layout class="QGridLayout" name="gridLayout_3">
+   <item row="0" column="0">
     <widget class="QFrame" name="filterFrame">
      <property name="sizePolicy">
       <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
@@ -258,8 +258,8 @@
               <rect>
                <x>0</x>
                <y>0</y>
-               <width>206</width>
-               <height>470</height>
+               <width>561</width>
+               <height>580</height>
               </rect>
              </property>
              <layout class="QVBoxLayout" name="verticalLayout_2">
@@ -473,6 +473,75 @@
                </widget>
               </item>
               <item>
+               <widget class="QGroupBox" name="groupBox_7">
+                <property name="title">
+                 <string>Ignore Built-ins Assignment</string>
+                </property>
+                <layout class="QHBoxLayout" name="horizontalLayout_8">
+                 <item>
+                  <widget class="QTreeWidget" name="builtinsAssignmentList">
+                   <property name="alternatingRowColors">
+                    <bool>true</bool>
+                   </property>
+                   <property name="rootIsDecorated">
+                    <bool>false</bool>
+                   </property>
+                   <property name="sortingEnabled">
+                    <bool>true</bool>
+                   </property>
+                   <column>
+                    <property name="text">
+                     <string>Left</string>
+                    </property>
+                   </column>
+                   <column>
+                    <property name="text">
+                     <string>Right</string>
+                    </property>
+                   </column>
+                  </widget>
+                 </item>
+                 <item>
+                  <layout class="QVBoxLayout" name="verticalLayout_5">
+                   <item>
+                    <widget class="QToolButton" name="addBuiltinButton">
+                     <property name="toolTip">
+                      <string>Press to add a built-in assignment to be ignored</string>
+                     </property>
+                     <property name="text">
+                      <string notr="true">+</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item>
+                    <widget class="QToolButton" name="deleteBuiltinButton">
+                     <property name="toolTip">
+                      <string>Press to delete the selected entries</string>
+                     </property>
+                     <property name="text">
+                      <string notr="true">-</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item>
+                    <spacer name="verticalSpacer_3">
+                     <property name="orientation">
+                      <enum>Qt::Vertical</enum>
+                     </property>
+                     <property name="sizeHint" stdset="0">
+                      <size>
+                       <width>20</width>
+                       <height>40</height>
+                      </size>
+                     </property>
+                    </spacer>
+                   </item>
+                  </layout>
+                 </item>
+                </layout>
+               </widget>
+              </item>
+              <item>
                <widget class="QGroupBox" name="groupBox_3">
                 <property name="title">
                  <string>McCabe Complexity</string>
@@ -608,7 +677,7 @@
      </layout>
     </widget>
    </item>
-   <item>
+   <item row="1" column="0">
     <widget class="QTreeWidget" name="resultList">
      <property name="sizePolicy">
       <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
@@ -648,7 +717,7 @@
      </column>
     </widget>
    </item>
-   <item>
+   <item row="2" column="0">
     <widget class="E5SqueezeLabelPath" name="checkProgressLabel">
      <property name="sizePolicy">
       <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
@@ -661,7 +730,7 @@
      </property>
     </widget>
    </item>
-   <item>
+   <item row="3" column="0">
     <widget class="QProgressBar" name="checkProgress">
      <property name="toolTip">
       <string>Shows the progress of the code style check</string>
@@ -677,7 +746,7 @@
      </property>
     </widget>
    </item>
-   <item>
+   <item row="4" column="0">
     <widget class="QDialogButtonBox" name="buttonBox">
      <property name="orientation">
       <enum>Qt::Horizontal</enum>
@@ -724,6 +793,9 @@
   <tabstop>copyrightFileSizeSpinBox</tabstop>
   <tabstop>copyrightAuthorEdit</tabstop>
   <tabstop>futuresList</tabstop>
+  <tabstop>builtinsAssignmentList</tabstop>
+  <tabstop>addBuiltinButton</tabstop>
+  <tabstop>deleteBuiltinButton</tabstop>
   <tabstop>complexitySpinBox</tabstop>
   <tabstop>startButton</tabstop>
   <tabstop>fixButton</tabstop>
--- a/Plugins/CheckerPlugins/CodeStyleChecker/MiscellaneousChecker.py	Thu Mar 16 20:00:31 2017 +0100
+++ b/Plugins/CheckerPlugins/CodeStyleChecker/MiscellaneousChecker.py	Fri Mar 17 19:09:39 2017 +0100
@@ -115,6 +115,10 @@
                 "MinFilesize": 0,
                 "Author": "",
             },
+            "BuiltinsChecker": {
+                "str": ["unicode", ],
+                "chr": ["unichr", ],
+            }
         }
         
         self.__checkers = []
@@ -491,6 +495,9 @@
         """
         Private method to check, if built-ins are shadowed.
         """
+        ignoreBuiltinAssignments = self.__args.get(
+            "BuiltinsChecker", self.__defaultArgs["BuiltinsChecker"])
+        
         for node in ast.walk(self.__tree):
             if isinstance(node, ast.Assign):
                 # assign statement
@@ -499,9 +506,9 @@
                        element.id in self.__builtins:
                         value = node.value
                         if isinstance(value, ast.Name) and \
-                           value.id in ["unicode", "unichr"]:
+                           element.id in ignoreBuiltinAssignments and \
+                           value.id in ignoreBuiltinAssignments[element.id]:
                             # ignore compatibility assignments
-                            # TODO: make this configurable
                             continue
                         self.__error(element.lineno - 1, element.col_offset,
                                      "M131", element.id)
--- a/eric6.e4p	Thu Mar 16 20:00:31 2017 +0100
+++ b/eric6.e4p	Fri Mar 17 19:09:39 2017 +0100
@@ -465,6 +465,7 @@
     <Source>PluginManager/__init__.py</Source>
     <Source>Plugins/AboutPlugin/AboutDialog.py</Source>
     <Source>Plugins/AboutPlugin/__init__.py</Source>
+    <Source>Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleAddBuiltinIgnoreDialog.py</Source>
     <Source>Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleChecker.py</Source>
     <Source>Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCheckerDialog.py</Source>
     <Source>Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCodeSelectionDialog.py</Source>
@@ -1605,6 +1606,7 @@
     <Form>PluginManager/PluginInstallDialog.ui</Form>
     <Form>PluginManager/PluginRepositoryDialog.ui</Form>
     <Form>PluginManager/PluginUninstallDialog.ui</Form>
+    <Form>Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleAddBuiltinIgnoreDialog.ui</Form>
     <Form>Plugins/AboutPlugin/AboutDialog.ui</Form>
     <Form>Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCheckerDialog.ui</Form>
     <Form>Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCodeSelectionDialog.ui</Form>
@@ -1954,14 +1956,14 @@
   <Interfaces/>
   <Others>
     <Other>.hgignore</Other>
-    <Other>APIs/Python/zope-2.10.7.api</Other>
-    <Other>APIs/Python/zope-2.11.2.api</Other>
-    <Other>APIs/Python/zope-3.3.1.api</Other>
     <Other>APIs/Python3/PyQt4.bas</Other>
     <Other>APIs/Python3/PyQt5.bas</Other>
     <Other>APIs/Python3/QScintilla2.bas</Other>
     <Other>APIs/Python3/eric6.api</Other>
     <Other>APIs/Python3/eric6.bas</Other>
+    <Other>APIs/Python/zope-2.10.7.api</Other>
+    <Other>APIs/Python/zope-2.11.2.api</Other>
+    <Other>APIs/Python/zope-3.3.1.api</Other>
     <Other>APIs/QSS/qss.api</Other>
     <Other>APIs/Ruby/Ruby-1.8.7.api</Other>
     <Other>APIs/Ruby/Ruby-1.8.7.bas</Other>

eric ide

mercurial