Sat, 24 Oct 2015 20:36:26 +0200
Started to add more code style checkers.
--- a/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleChecker.py Fri Oct 23 19:44:22 2015 +0200 +++ b/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleChecker.py Sat Oct 24 20:36:26 2015 +0200 @@ -12,12 +12,13 @@ import pep8 from NamingStyleChecker import NamingStyleChecker -from McCabeChecker import McCabeChecker # register the name checker pep8.register_check(NamingStyleChecker, NamingStyleChecker.Codes) from DocStyleChecker import DocStyleChecker +from MiscellaneousChecker import MiscellaneousChecker +from McCabeChecker import McCabeChecker def initService(): @@ -189,8 +190,8 @@ (bool), fixed (bool), autofixing (bool), fixedMsg (str))) """ (excludeMessages, includeMessages, repeatMessages, fixCodes, noFixCodes, - fixIssues, maxLineLength, hangClosing, docType, maxComplexity, errors, - eol, encoding, backup) = args + fixIssues, maxLineLength, hangClosing, docType, maxComplexity, + miscellaneousArgs, errors, eol, encoding, backup) = args stats = {} @@ -243,6 +244,14 @@ stats.update(docStyleChecker.counters) errors += docStyleChecker.errors + # miscellaneous additional checks + miscellaneousChecker = MiscellaneousChecker( + source, filename, select, ignore, [], repeatMessages, + miscellaneousArgs) + miscellaneousChecker.run() + stats.update(miscellaneousChecker.counters) + errors += miscellaneousChecker.errors + # check code complexity iaw. McCabe mccabeChecker = McCabeChecker( source, filename, select, ignore, maxComplexity)
--- a/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCheckerDialog.py Fri Oct 23 19:44:22 2015 +0200 +++ b/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCheckerDialog.py Sat Oct 24 20:36:26 2015 +0200 @@ -166,7 +166,7 @@ itm = QTreeWidgetItem( self.__lastFileItem, ["{0:6}".format(line), code, message]) - if code.startswith(("W", "-", "C")): + if code.startswith(("W", "-", "C", "M")): itm.setIcon(1, UI.PixmapCache.getIcon("warning.png")) elif code.startswith("N"): itm.setIcon(1, UI.PixmapCache.getIcon("namingError.png")) @@ -301,6 +301,12 @@ self.__data["ShowIgnored"] = False if "MaxCodeComplexity" not in self.__data: self.__data["MaxCodeComplexity"] = 10 + if "ValidEncodings" not in self.__data: + self.__data["ValidEncodings"] = "latin-1, utf-8" + if "CopyrightMinFileSize" not in self.__data or \ + "CopyrightAuthor" not in self.__data: + self.__data["CopyrightMinFileSize"] = 0 + self.__data["CopyrightAuthor"] = "" self.excludeFilesEdit.setText(self.__data["ExcludeFiles"]) self.excludeMessagesEdit.setText(self.__data["ExcludeMessages"]) @@ -315,6 +321,10 @@ self.docTypeComboBox.setCurrentIndex( self.docTypeComboBox.findData(self.__data["DocstringType"])) self.complexitySpinBox.setValue(self.__data["MaxCodeComplexity"]) + self.encodingsEdit.setText(self.__data["ValidEncodings"]) + self.copyrightFileSizeSpinBox.setValue( + self.__data["CopyrightMinFileSize"]) + self.copyrightAuthorEdit.setText(self.__data["CopyrightAuthor"]) def start(self, fn, save=False, repeat=None): """ @@ -394,10 +404,18 @@ docType = self.docTypeComboBox.itemData( self.docTypeComboBox.currentIndex()) maxCodeComplexity = self.complexitySpinBox.value() + miscellaneousArgs = { + "CodingChecker": self.encodingsEdit.text(), + "CopyrightChecker": { + "MinFilesize": self.copyrightFileSizeSpinBox.value(), + "Author": self.copyrightAuthorEdit.text(), + } + } self.__options = [excludeMessages, includeMessages, repeatMessages, fixCodes, noFixCodes, fixIssues, maxLineLength, - hangClosing, docType, maxCodeComplexity] + hangClosing, docType, maxCodeComplexity, + miscellaneousArgs] # now go through all the files self.progress = 0 @@ -436,7 +454,7 @@ self.__lastFileItem = None if codestring: - source = codestring + source = codestring.splitlines(True) encoding = Utilities.get_coding(source) else: try: @@ -677,6 +695,9 @@ "DocstringType": self.docTypeComboBox.itemData( self.docTypeComboBox.currentIndex()), "MaxCodeComplexity": self.complexitySpinBox.value(), + "ValidEncodings": self.encodingsEdit.text(), + "CopyrightMinFileSize": self.copyrightFileSizeSpinBox.value(), + "CopyrightAuthor": self.copyrightAuthorEdit.text(), } if data != self.__data: self.__data = data @@ -850,6 +871,12 @@ Preferences.Prefs.settings.value("PEP8/DocstringType", "pep257"))) self.complexitySpinBox.setValue(int(Preferences.Prefs.settings.value( "PEP8/MaxCodeComplexity", 10))) + self.encodingsEdit.setText(Preferences.Prefs.settings.value( + "PEP8/ValidEncodings", "latin-1, utf-8")) + self.copyrightFileSizeSpinBox.setValue(int( + Preferences.Prefs.settings.value("PEP8/CopyrightMinFileSize", 0))) + self.copyrightAuthorEdit.setText( + Preferences.Prefs.settings.value("PEP8/CopyrightAuthor")) @pyqtSlot() def on_storeDefaultButton_clicked(self): @@ -882,6 +909,12 @@ self.docTypeComboBox.currentIndex())) Preferences.Prefs.settings.setValue( "PEP8/MaxCodeComplexity", self.complexitySpinBox.value()) + Preferences.Prefs.settings.setValue( + "PEP8/ValidEncodings", self.encodingsEdit.text()) + Preferences.Prefs.settings.setValue( + "PEP8/CopyrightMinFileSize", self.copyrightFileSizeSpinBox.value()) + Preferences.Prefs.settings.setValue( + "PEP8/CopyrightAuthor", self.copyrightAuthorEdit.text()) @pyqtSlot() def on_resetDefaultButton_clicked(self): @@ -902,6 +935,10 @@ Preferences.Prefs.settings.setValue("PEP8/HangClosing", False) Preferences.Prefs.settings.setValue("PEP8/DocstringType", "pep257") Preferences.Prefs.settings.setValue("PEP8/MaxCodeComplexity", 10) + Preferences.Prefs.settings.setValue( + "PEP8/ValidEncodings", "latin-1, utf-8") + Preferences.Prefs.settings.setValue("PEP8/CopyrightMinFileSize", 0) + Preferences.Prefs.settings.setValue("PEP8/CopyrightAuthor", "") @pyqtSlot(QAbstractButton) def on_buttonBox_clicked(self, button):
--- a/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCheckerDialog.ui Fri Oct 23 19:44:22 2015 +0200 +++ b/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCheckerDialog.ui Sat Oct 24 20:36:26 2015 +0200 @@ -21,28 +21,464 @@ <property name="sizeGripEnabled"> <bool>true</bool> </property> - <layout class="QVBoxLayout" name="verticalLayout_2"> + <layout class="QVBoxLayout" name="verticalLayout_5"> <item> <widget class="QFrame" name="filterFrame"> <property name="frameShape"> <enum>QFrame::NoFrame</enum> </property> - <layout class="QGridLayout" name="gridLayout"> - <item row="0" column="0"> - <widget class="QLabel" name="label_2"> - <property name="text"> - <string>Exclude Files:</string> + <layout class="QHBoxLayout" name="horizontalLayout_5"> + <item> + <widget class="QTabWidget" name="tabWidget"> + <property name="currentIndex"> + <number>0</number> </property> + <widget class="QWidget" name="tab_1"> + <attribute name="title"> + <string>Global Options</string> + </attribute> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="0" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Exclude Files:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="E5ClearableLineEdit" name="excludeFilesEdit"> + <property name="toolTip"> + <string>Enter filename patterns of files to be excluded separated by a comma</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Exclude Messages:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="E5ClearableLineEdit" name="excludeMessagesEdit"> + <property name="toolTip"> + <string>Enter message codes or categories to be excluded separated by a comma</string> + </property> + </widget> + </item> + <item row="1" column="2"> + <widget class="QToolButton" name="excludeMessagesSelectButton"> + <property name="toolTip"> + <string>Press to select the message codes from a list</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Included Messages:</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="E5ClearableLineEdit" name="includeMessagesEdit"> + <property name="toolTip"> + <string>Enter message codes or categories to be included separated by a comma</string> + </property> + </widget> + </item> + <item row="2" column="2"> + <widget class="QToolButton" name="includeMessagesSelectButton"> + <property name="toolTip"> + <string>Press to select the message codes from a list</string> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string>Fix Issues:</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="E5ClearableLineEdit" name="fixIssuesEdit"> + <property name="toolTip"> + <string>Enter message codes of issues to be fixed automatically (leave empty to fix all)</string> + </property> + </widget> + </item> + <item row="3" column="2"> + <widget class="QToolButton" name="fixIssuesSelectButton"> + <property name="toolTip"> + <string>Press to select the message codes from a list</string> + </property> + </widget> + </item> + <item row="4" column="0"> + <widget class="QLabel" name="label_6"> + <property name="text"> + <string>Don't Fix Issues:</string> + </property> + </widget> + </item> + <item row="4" column="1"> + <widget class="E5ClearableLineEdit" name="noFixIssuesEdit"> + <property name="toolTip"> + <string>Enter message codes of issues not to be fixed automatically</string> + </property> + </widget> + </item> + <item row="4" column="2"> + <widget class="QToolButton" name="noFixIssuesSelectButton"> + <property name="toolTip"> + <string>Press to select the message codes from a list</string> + </property> + </widget> + </item> + <item row="5" column="0" colspan="3"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QCheckBox" name="repeatCheckBox"> + <property name="toolTip"> + <string>Select to repeat each message type</string> + </property> + <property name="text"> + <string>Repeat messages</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="fixIssuesCheckBox"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="toolTip"> + <string>Select to fix some issues</string> + </property> + <property name="text"> + <string>Fix issues automatically</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="ignoredCheckBox"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="toolTip"> + <string>Select to show ignored issues</string> + </property> + <property name="text"> + <string>Show ignored</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item row="6" column="0" colspan="2"> + <spacer name="verticalSpacer_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>68</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <widget class="QWidget" name="tab_2"> + <attribute name="title"> + <string>Specific Options</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <property name="leftMargin"> + <number>1</number> + </property> + <property name="topMargin"> + <number>1</number> + </property> + <property name="rightMargin"> + <number>1</number> + </property> + <property name="bottomMargin"> + <number>1</number> + </property> + <item> + <widget class="QScrollArea" name="scrollArea"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + <property name="verticalScrollBarPolicy"> + <enum>Qt::ScrollBarAlwaysOn</enum> + </property> + <property name="widgetResizable"> + <bool>true</bool> + </property> + <widget class="QWidget" name="scrollAreaWidgetContents"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>529</width> + <height>440</height> + </rect> + </property> + <layout class="QVBoxLayout" name="verticalLayout_4"> + <item> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string>Source Style</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QLabel" name="label_5"> + <property name="text"> + <string>Max. Line Length:</string> + </property> + </widget> + </item> + <item> + <widget class="QSpinBox" name="lineLengthSpinBox"> + <property name="statusTip"> + <string>Enter the maximum allowed line length (PEP-8: 79 characters)</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <property name="minimum"> + <number>60</number> + </property> + <property name="maximum"> + <number>119</number> + </property> + <property name="value"> + <number>79</number> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_3"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <widget class="QCheckBox" name="hangClosingCheckBox"> + <property name="toolTip"> + <string>Select to allow hanging closing brackets</string> + </property> + <property name="text"> + <string>Allow hanging closing brackets</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox_2"> + <property name="title"> + <string>Documentation Style</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <item> + <widget class="QLabel" name="label_7"> + <property name="text"> + <string>Docstring Type:</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="docTypeComboBox"> + <property name="toolTip"> + <string>Select the rule set for docstrings</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_4"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>297</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox_4"> + <property name="title"> + <string>Coding Line</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_6"> + <item> + <widget class="QLabel" name="label_9"> + <property name="text"> + <string>Valid Encodings:</string> + </property> + </widget> + </item> + <item> + <widget class="E5ClearableLineEdit" name="encodingsEdit"> + <property name="toolTip"> + <string>Enter valid encodings separated by a comma (leave empty to use defaults)</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox_5"> + <property name="title"> + <string>Copyright</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="label_10"> + <property name="text"> + <string>Min. File Size:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QSpinBox" name="copyrightFileSizeSpinBox"> + <property name="toolTip"> + <string>Enter the minimum size a file must have to be checked (0 for all files)</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <property name="maximum"> + <number>4096</number> + </property> + </widget> + </item> + <item row="0" column="2"> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>324</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_11"> + <property name="text"> + <string>Author:</string> + </property> + </widget> + </item> + <item row="1" column="1" colspan="2"> + <widget class="E5ClearableLineEdit" name="copyrightAuthorEdit"> + <property name="toolTip"> + <string>Enter a copyright author name to check for (leave empty to omit this check)</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox_3"> + <property name="title"> + <string>McCabe Complexity</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_4"> + <item> + <widget class="QLabel" name="label_8"> + <property name="text"> + <string>Max. Complexity:</string> + </property> + </widget> + </item> + <item> + <widget class="QSpinBox" name="complexitySpinBox"> + <property name="statusTip"> + <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="minimum"> + <number>0</number> + </property> + <property name="maximum"> + <number>100</number> + </property> + <property name="value"> + <number>10</number> + </property> + </widget> + </item> + <item> + <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> + </layout> + </widget> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </widget> </widget> </item> - <item row="0" column="1"> - <widget class="E5ClearableLineEdit" name="excludeFilesEdit"> - <property name="toolTip"> - <string>Enter filename patterns of files to be excluded separated by a comma</string> - </property> - </widget> - </item> - <item row="0" column="3" rowspan="10"> + <item> <widget class="Line" name="line"> <property name="lineWidth"> <number>2</number> @@ -52,7 +488,7 @@ </property> </widget> </item> - <item row="0" column="4" rowspan="10"> + <item> <layout class="QVBoxLayout" name="verticalLayout"> <item> <widget class="QPushButton" name="startButton"> @@ -60,7 +496,7 @@ <string>Press to start the code style check run</string> </property> <property name="text"> - <string>Start</string> + <string>&Start</string> </property> </widget> </item> @@ -70,7 +506,7 @@ <string>Press to fix the selected issues</string> </property> <property name="text"> - <string>Fix Selected</string> + <string>&Fix Selected</string> </property> </widget> </item> @@ -93,7 +529,7 @@ <string>Press to load the default values</string> </property> <property name="text"> - <string>Load Defaults</string> + <string>&Load Defaults</string> </property> </widget> </item> @@ -103,7 +539,7 @@ <string>Press to store the current values as defaults</string> </property> <property name="text"> - <string>Store Defaults</string> + <string>St&ore Defaults</string> </property> </widget> </item> @@ -113,274 +549,10 @@ <string>Press to reset the default values</string> </property> <property name="text"> - <string>Reset Defaults</string> - </property> - </widget> - </item> - </layout> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="label"> - <property name="text"> - <string>Exclude Messages:</string> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="E5ClearableLineEdit" name="excludeMessagesEdit"> - <property name="toolTip"> - <string>Enter message codes or categories to be excluded separated by a comma</string> - </property> - </widget> - </item> - <item row="1" column="2"> - <widget class="QToolButton" name="excludeMessagesSelectButton"> - <property name="toolTip"> - <string>Press to select the message codes from a list</string> - </property> - </widget> - </item> - <item row="2" column="0"> - <widget class="QLabel" name="label_3"> - <property name="text"> - <string>Included Messages:</string> - </property> - </widget> - </item> - <item row="2" column="1"> - <widget class="E5ClearableLineEdit" name="includeMessagesEdit"> - <property name="toolTip"> - <string>Enter message codes or categories to be included separated by a comma</string> - </property> - </widget> - </item> - <item row="2" column="2"> - <widget class="QToolButton" name="includeMessagesSelectButton"> - <property name="toolTip"> - <string>Press to select the message codes from a list</string> - </property> - </widget> - </item> - <item row="3" column="0"> - <widget class="QLabel" name="label_4"> - <property name="text"> - <string>Fix Issues:</string> - </property> - </widget> - </item> - <item row="3" column="1"> - <widget class="E5ClearableLineEdit" name="fixIssuesEdit"> - <property name="toolTip"> - <string>Enter message codes of issues to be fixed automatically (leave empty to fix all)</string> - </property> - </widget> - </item> - <item row="3" column="2"> - <widget class="QToolButton" name="fixIssuesSelectButton"> - <property name="toolTip"> - <string>Press to select the message codes from a list</string> - </property> - </widget> - </item> - <item row="4" column="0"> - <widget class="QLabel" name="label_6"> - <property name="text"> - <string>Don't Fix Issues:</string> - </property> - </widget> - </item> - <item row="4" column="1"> - <widget class="E5ClearableLineEdit" name="noFixIssuesEdit"> - <property name="toolTip"> - <string>Enter message codes of issues not to be fixed automatically</string> - </property> - </widget> - </item> - <item row="4" column="2"> - <widget class="QToolButton" name="noFixIssuesSelectButton"> - <property name="toolTip"> - <string>Press to select the message codes from a list</string> - </property> - </widget> - </item> - <item row="5" column="0"> - <widget class="QLabel" name="label_5"> - <property name="text"> - <string>Max. Line Length:</string> - </property> - </widget> - </item> - <item row="5" column="1" colspan="2"> - <layout class="QHBoxLayout" name="horizontalLayout_3"> - <item> - <widget class="QSpinBox" name="lineLengthSpinBox"> - <property name="statusTip"> - <string>Enter the maximum allowed line length (PEP-8: 79 characters)</string> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - <property name="minimum"> - <number>60</number> - </property> - <property name="maximum"> - <number>119</number> - </property> - <property name="value"> - <number>79</number> + <string>&Reset Defaults</string> </property> </widget> </item> - <item> - <spacer name="horizontalSpacer_3"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - </layout> - </item> - <item row="6" column="0"> - <widget class="QLabel" name="label_7"> - <property name="text"> - <string>Docstring Type:</string> - </property> - </widget> - </item> - <item row="6" column="1" colspan="2"> - <layout class="QHBoxLayout" name="horizontalLayout_4"> - <item> - <widget class="QComboBox" name="docTypeComboBox"> - <property name="toolTip"> - <string>Select the rule set for docstrings</string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_4"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - </layout> - </item> - <item row="7" column="0" colspan="3"> - <widget class="QCheckBox" name="hangClosingCheckBox"> - <property name="toolTip"> - <string>Select to allow hanging closing brackets</string> - </property> - <property name="text"> - <string>Allow hanging closing brackets</string> - </property> - </widget> - </item> - <item row="8" column="0"> - <widget class="QLabel" name="label_8"> - <property name="text"> - <string>Max. Complexity:</string> - </property> - </widget> - </item> - <item row="8" column="1" colspan="2"> - <layout class="QHBoxLayout" name="horizontalLayout_5"> - <item> - <widget class="QSpinBox" name="complexitySpinBox"> - <property name="statusTip"> - <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="minimum"> - <number>0</number> - </property> - <property name="maximum"> - <number>100</number> - </property> - <property name="value"> - <number>10</number> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_5"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - </layout> - </item> - <item row="9" column="0" colspan="3"> - <layout class="QHBoxLayout" name="horizontalLayout"> - <item> - <widget class="QCheckBox" name="repeatCheckBox"> - <property name="toolTip"> - <string>Select to repeat each message type</string> - </property> - <property name="text"> - <string>Repeat messages</string> - </property> - </widget> - </item> - <item> - <widget class="QCheckBox" name="fixIssuesCheckBox"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="toolTip"> - <string>Select to fix some issues</string> - </property> - <property name="text"> - <string>Fix issues automatically</string> - </property> - </widget> - </item> - <item> - <widget class="QCheckBox" name="ignoredCheckBox"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="toolTip"> - <string>Select to show ignored issues</string> - </property> - <property name="text"> - <string>Show ignored</string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> </layout> </item> </layout> @@ -476,8 +648,7 @@ </customwidget> </customwidgets> <tabstops> - <tabstop>startButton</tabstop> - <tabstop>loadDefaultButton</tabstop> + <tabstop>tabWidget</tabstop> <tabstop>excludeFilesEdit</tabstop> <tabstop>excludeMessagesEdit</tabstop> <tabstop>excludeMessagesSelectButton</tabstop> @@ -487,17 +658,21 @@ <tabstop>fixIssuesSelectButton</tabstop> <tabstop>noFixIssuesEdit</tabstop> <tabstop>noFixIssuesSelectButton</tabstop> - <tabstop>lineLengthSpinBox</tabstop> - <tabstop>docTypeComboBox</tabstop> - <tabstop>hangClosingCheckBox</tabstop> - <tabstop>complexitySpinBox</tabstop> <tabstop>repeatCheckBox</tabstop> <tabstop>fixIssuesCheckBox</tabstop> <tabstop>ignoredCheckBox</tabstop> - <tabstop>resultList</tabstop> + <tabstop>scrollArea</tabstop> + <tabstop>lineLengthSpinBox</tabstop> + <tabstop>hangClosingCheckBox</tabstop> + <tabstop>docTypeComboBox</tabstop> + <tabstop>encodingsEdit</tabstop> + <tabstop>complexitySpinBox</tabstop> + <tabstop>startButton</tabstop> <tabstop>fixButton</tabstop> + <tabstop>loadDefaultButton</tabstop> <tabstop>storeDefaultButton</tabstop> <tabstop>resetDefaultButton</tabstop> + <tabstop>resultList</tabstop> </tabstops> <resources/> <connections>
--- a/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCodeSelectionDialog.py Fri Oct 23 19:44:22 2015 +0200 +++ b/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCodeSelectionDialog.py Sat Oct 24 20:36:26 2015 +0200 @@ -50,7 +50,7 @@ else: continue itm = QTreeWidgetItem(self.codeTable, [code, message]) - if code.startswith(("W", "C")): + if code.startswith(("W", "C", "M")): itm.setIcon(0, UI.PixmapCache.getIcon("warning.png")) elif code.startswith("E"): itm.setIcon(0, UI.PixmapCache.getIcon("syntaxError.png"))
--- a/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleStatisticsDialog.py Fri Oct 23 19:44:22 2015 +0200 +++ b/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleStatisticsDialog.py Sat Oct 24 20:36:26 2015 +0200 @@ -84,7 +84,7 @@ itm.setData(0, Qt.DisplayRole, count) itm.setData(1, Qt.DisplayRole, code) itm.setData(2, Qt.DisplayRole, message) - if code.startswith(("W", "C")): + if code.startswith(("W", "C", "M")): itm.setIcon(1, UI.PixmapCache.getIcon("warning.png")) elif code.startswith("E"): itm.setIcon(1, UI.PixmapCache.getIcon("syntaxError.png"))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/CheckerPlugins/CodeStyleChecker/MiscellaneousChecker.py Sat Oct 24 20:36:26 2015 +0200 @@ -0,0 +1,255 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2015 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a checker for miscellaneous checks. +""" + +from __future__ import unicode_literals + +import sys +import ast +import re + + +class MiscellaneousChecker(object): + """ + Class implementing a checker for miscellaneous checks. + """ + Codes = [ + "M101", "M102", + "M111", "M112", + "M121", + "M131", + "M801", + + "M901", + ] + + def __init__(self, source, filename, select, ignore, expected, repeat, + args): + """ + Constructor + + @param source source code to be checked (list of string) + @param filename name of the source file (string) + @param select list of selected codes (list of string) + @param ignore list of codes to be ignored (list of string) + @param expected list of expected codes (list of string) + @param repeat flag indicating to report each occurrence of a code + (boolean) + @param args dictionary of arguments for the miscellaneous checks (dict) + """ + self.__select = tuple(select) + self.__ignore = ('',) if select else tuple(ignore) + self.__expected = expected[:] + self.__repeat = repeat + self.__filename = filename + self.__source = source[:] + self.__args = args + + self.__blindExceptRegex = re.compile( + r'(except:)') # __IGNORE_WARNING__ + self.__pep3101FormatRegex = re.compile( + r'^(?:[^\'"]*[\'"][^\'"]*[\'"])*\s*%|^\s*%') + + # statistics counters + self.counters = {} + + # collection of detected errors + self.errors = [] + + checkersWithCodes = [ + # TODO: fill this + (self.__checkCoding, ("M101", "M102")), + (self.__checkCopyright, ("M111", "M112")), + (self.__checkBlindExcept, ("M121",)), + (self.__checkPep3101, ("M131",)), + (self.__checkPrintStatements, ("M801",)), + ] + + self.__defaultArgs = { + "CodingChecker": 'latin-1, utf-8', + "CopyrightChecker": { + "MinFilesize": 0, + "Author": "", + }, + } + + self.__checkers = [] + for checker, codes in checkersWithCodes: + if any(not (code and self.__ignoreCode(code)) + for code in codes): + self.__checkers.append(checker) + + def __ignoreCode(self, code): + """ + Private method to check if the message code should be ignored. + + @param code message code to check for (string) + @return flag indicating to ignore the given code (boolean) + """ + return (code.startswith(self.__ignore) and + not code.startswith(self.__select)) + + def __error(self, lineNumber, offset, code, *args): + """ + Private method to record an issue. + + @param lineNumber line number of the issue (integer) + @param offset position within line of the issue (integer) + @param code message code (string) + @param args arguments for the message (list) + """ + if self.__ignoreCode(code): + return + + if code in self.counters: + self.counters[code] += 1 + else: + self.counters[code] = 1 + + # Don't care about expected codes + if code in self.__expected: + return + + if code and (self.counters[code] == 1 or self.__repeat): + # record the issue with one based line number + self.errors.append( + (self.__filename, lineNumber + 1, offset, (code, args))) + + 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 run(self): + """ + Public method to check the given source against miscellaneous + conditions. + """ + if not self.__filename: + # don't do anything, if essential data is missing + return + + if not self.__checkers: + # don't do anything, if no codes were selected + return + + try: + self.__tree = compile( + ''.join(self.__source), '', 'exec', ast.PyCF_ONLY_AST) + except (SyntaxError, TypeError): + self.__reportInvalidSyntax() + return + + for check in self.__checkers: + check() + + def __checkCoding(self): + """ + Private method to check the presence of a coding line and valid + encodings. + """ + if len(self.__source) == 0: + return + + encodings = [e.lower().strip() + for e in self.__args.get( + "CodingChecker", self.__defaultArgs["CodingChecker"]) + .split(",")] + for lineno, line in enumerate(self.__source[:2]): + matched = re.search('coding[:=]\s*([-\w.]+)', line, re.IGNORECASE) + if matched: + if encodings and matched.group(1).lower() not in encodings: + self.__error(lineno, 0, "M102", matched.group(1)) + break + else: + self.__error(0, 0, "M101") + + def __checkCopyright(self): + """ + Private method to check the presence of a copyright statement. + """ + source = "".join(self.__source) + copyrightArgs = self.__args.get( + "CopyrightChecker", self.__defaultArgs["CopyrightChecker"]) + copyrightMinFileSize = copyrightArgs.get( + "MinFilesize", + self.__defaultArgs["CopyrightChecker"]["MinFilesize"]) + copyrightAuthor = copyrightArgs.get( + "Author", + self.__defaultArgs["CopyrightChecker"]["Author"]) + copyrightRegexStr = \ + r"Copyright\s+(\(C\)\s+)?(\d{{4}}\s+-\s+)?\d{{4}}\s+{author}" + + tocheck = max(1024, copyrightMinFileSize) + topOfSource = source[:tocheck] + if len(topOfSource) < copyrightMinFileSize: + return + + copyrightRe = re.compile(copyrightRegexStr.format(author=r".*"), + re.IGNORECASE) + if not copyrightRe.search(topOfSource): + self.__error(0, 0, "M111") + return + + if copyrightAuthor: + copyrightAuthorRe = re.compile( + copyrightRegexStr.format(author=copyrightAuthor), + re.IGNORECASE) + if not copyrightAuthorRe.search(topOfSource): + self.__error(0, 0, "M112") + + def __checkBlindExcept(self): + """ + Private method to check for blind except statements. + """ + for lineno, line in enumerate(self.__source): + match = self.__blindExceptRegex.search(line) + if match: + self.__error(lineno, match.start(), "M121") + + def __checkPep3101(self): + """ + Private method to check for old style string formatting. + """ + for lineno, line in enumerate(self.__source): + match = self.__pep3101FormatRegex.search(line) + if match: + lineLen = len(line) + pos = line.find('%') + formatPos = pos + formatter = '%' + if line[pos + 1] == "(": + pos = line.find(")", pos) + c = line[pos] + while c not in "diouxXeEfFgGcrs": + pos += 1 + if pos >= lineLen: + break + c = line[pos] + if c in "diouxXeEfFgGcrs": + formatter += c + self.__error(lineno, formatPos, "M131", formatter) + + def __checkPrintStatements(self): + """ + Private method to check for print statements. + """ + for node in ast.walk(self.__tree): + if (isinstance(node, ast.Call) and + getattr(node.func, 'id', None) == 'print') or \ + (hasattr(ast, 'Print') and isinstance(node, ast.Print)): + self.__error(node.lineno - 1, node.col_offset, "M801")
--- a/Plugins/CheckerPlugins/CodeStyleChecker/translations.py Fri Oct 23 19:44:22 2015 +0200 +++ b/Plugins/CheckerPlugins/CodeStyleChecker/translations.py Sat Oct 24 20:36:26 2015 +0200 @@ -377,6 +377,33 @@ "C901": QCoreApplication.translate( "McCabeChecker", "{0}: {1}"), + # Messages of the Miscellaneous Checker + # TODO: Do this right + "M101": QCoreApplication.translate( + "MiscellaneousChecker", + "coding magic comment not found"), + "M102": QCoreApplication.translate( + "MiscellaneousChecker", + "unknown encoding ({0}) found in coding magic comment"), + "M111": QCoreApplication.translate( + "MiscellaneousChecker", + "copyright notice not present"), + "M112": QCoreApplication.translate( + "MiscellaneousChecker", + "copyright notice contains invalid author"), + "M121": QCoreApplication.translate( + "MiscellaneousChecker", + "blind except: statement"), + "M131": QCoreApplication.translate( + "MiscellaneousChecker", + "found {0} formatter"), + "M801": QCoreApplication.translate( + "MiscellaneousChecker", + "print statement found"), + "M901": QCoreApplication.translate( + "MiscellaneousChecker", + "{0}: {1}"), + # CodeStyleFixer messages "FD111": QCoreApplication.translate( 'CodeStyleFixer', @@ -547,6 +574,11 @@ "E902": ["IOError"], "D232": ["public"], "D901": ["SyntaxError", "Invalid Syntax"], + "C101": ["foo.bar", "42"], + "C901": ["SyntaxError", "Invalid Syntax"], + "M102": ["enc42"], + "M131": ["%s"], + "M901": ["SyntaxError", "Invalid Syntax"], "FWRITE_ERROR": ["IOError"], }
--- a/eric6.e4p Fri Oct 23 19:44:22 2015 +0200 +++ b/eric6.e4p Sat Oct 24 20:36:26 2015 +0200 @@ -26,54 +26,6 @@ <Source>DataViews/PyCoverageDialog.py</Source> <Source>DataViews/PyProfileDialog.py</Source> <Source>DataViews/__init__.py</Source> - <Source>DebugClients/Python/AsyncFile.py</Source> - <Source>DebugClients/Python/AsyncIO.py</Source> - <Source>DebugClients/Python/DCTestResult.py</Source> - <Source>DebugClients/Python/DebugBase.py</Source> - <Source>DebugClients/Python/DebugClient.py</Source> - <Source>DebugClients/Python/DebugClientBase.py</Source> - <Source>DebugClients/Python/DebugClientCapabilities.py</Source> - <Source>DebugClients/Python/DebugClientThreads.py</Source> - <Source>DebugClients/Python/DebugConfig.py</Source> - <Source>DebugClients/Python/DebugProtocol.py</Source> - <Source>DebugClients/Python/DebugThread.py</Source> - <Source>DebugClients/Python/FlexCompleter.py</Source> - <Source>DebugClients/Python/PyProfile.py</Source> - <Source>DebugClients/Python/__init__.py</Source> - <Source>DebugClients/Python/coverage/__init__.py</Source> - <Source>DebugClients/Python/coverage/__main__.py</Source> - <Source>DebugClients/Python/coverage/annotate.py</Source> - <Source>DebugClients/Python/coverage/backunittest.py</Source> - <Source>DebugClients/Python/coverage/backward.py</Source> - <Source>DebugClients/Python/coverage/bytecode.py</Source> - <Source>DebugClients/Python/coverage/cmdline.py</Source> - <Source>DebugClients/Python/coverage/collector.py</Source> - <Source>DebugClients/Python/coverage/config.py</Source> - <Source>DebugClients/Python/coverage/control.py</Source> - <Source>DebugClients/Python/coverage/data.py</Source> - <Source>DebugClients/Python/coverage/debug.py</Source> - <Source>DebugClients/Python/coverage/env.py</Source> - <Source>DebugClients/Python/coverage/execfile.py</Source> - <Source>DebugClients/Python/coverage/files.py</Source> - <Source>DebugClients/Python/coverage/html.py</Source> - <Source>DebugClients/Python/coverage/misc.py</Source> - <Source>DebugClients/Python/coverage/monkey.py</Source> - <Source>DebugClients/Python/coverage/parser.py</Source> - <Source>DebugClients/Python/coverage/phystokens.py</Source> - <Source>DebugClients/Python/coverage/pickle2json.py</Source> - <Source>DebugClients/Python/coverage/plugin.py</Source> - <Source>DebugClients/Python/coverage/plugin_support.py</Source> - <Source>DebugClients/Python/coverage/python.py</Source> - <Source>DebugClients/Python/coverage/pytracer.py</Source> - <Source>DebugClients/Python/coverage/report.py</Source> - <Source>DebugClients/Python/coverage/results.py</Source> - <Source>DebugClients/Python/coverage/summary.py</Source> - <Source>DebugClients/Python/coverage/templite.py</Source> - <Source>DebugClients/Python/coverage/test_helpers.py</Source> - <Source>DebugClients/Python/coverage/version.py</Source> - <Source>DebugClients/Python/coverage/xmlreport.py</Source> - <Source>DebugClients/Python/eric6dbgstub.py</Source> - <Source>DebugClients/Python/getpass.py</Source> <Source>DebugClients/Python3/AsyncFile.py</Source> <Source>DebugClients/Python3/AsyncIO.py</Source> <Source>DebugClients/Python3/DCTestResult.py</Source> @@ -123,6 +75,54 @@ <Source>DebugClients/Python3/coverage/xmlreport.py</Source> <Source>DebugClients/Python3/eric6dbgstub.py</Source> <Source>DebugClients/Python3/getpass.py</Source> + <Source>DebugClients/Python/AsyncFile.py</Source> + <Source>DebugClients/Python/AsyncIO.py</Source> + <Source>DebugClients/Python/DCTestResult.py</Source> + <Source>DebugClients/Python/DebugBase.py</Source> + <Source>DebugClients/Python/DebugClient.py</Source> + <Source>DebugClients/Python/DebugClientBase.py</Source> + <Source>DebugClients/Python/DebugClientCapabilities.py</Source> + <Source>DebugClients/Python/DebugClientThreads.py</Source> + <Source>DebugClients/Python/DebugConfig.py</Source> + <Source>DebugClients/Python/DebugProtocol.py</Source> + <Source>DebugClients/Python/DebugThread.py</Source> + <Source>DebugClients/Python/FlexCompleter.py</Source> + <Source>DebugClients/Python/PyProfile.py</Source> + <Source>DebugClients/Python/__init__.py</Source> + <Source>DebugClients/Python/coverage/__init__.py</Source> + <Source>DebugClients/Python/coverage/__main__.py</Source> + <Source>DebugClients/Python/coverage/annotate.py</Source> + <Source>DebugClients/Python/coverage/backunittest.py</Source> + <Source>DebugClients/Python/coverage/backward.py</Source> + <Source>DebugClients/Python/coverage/bytecode.py</Source> + <Source>DebugClients/Python/coverage/cmdline.py</Source> + <Source>DebugClients/Python/coverage/collector.py</Source> + <Source>DebugClients/Python/coverage/config.py</Source> + <Source>DebugClients/Python/coverage/control.py</Source> + <Source>DebugClients/Python/coverage/data.py</Source> + <Source>DebugClients/Python/coverage/debug.py</Source> + <Source>DebugClients/Python/coverage/env.py</Source> + <Source>DebugClients/Python/coverage/execfile.py</Source> + <Source>DebugClients/Python/coverage/files.py</Source> + <Source>DebugClients/Python/coverage/html.py</Source> + <Source>DebugClients/Python/coverage/misc.py</Source> + <Source>DebugClients/Python/coverage/monkey.py</Source> + <Source>DebugClients/Python/coverage/parser.py</Source> + <Source>DebugClients/Python/coverage/phystokens.py</Source> + <Source>DebugClients/Python/coverage/pickle2json.py</Source> + <Source>DebugClients/Python/coverage/plugin.py</Source> + <Source>DebugClients/Python/coverage/plugin_support.py</Source> + <Source>DebugClients/Python/coverage/python.py</Source> + <Source>DebugClients/Python/coverage/pytracer.py</Source> + <Source>DebugClients/Python/coverage/report.py</Source> + <Source>DebugClients/Python/coverage/results.py</Source> + <Source>DebugClients/Python/coverage/summary.py</Source> + <Source>DebugClients/Python/coverage/templite.py</Source> + <Source>DebugClients/Python/coverage/test_helpers.py</Source> + <Source>DebugClients/Python/coverage/version.py</Source> + <Source>DebugClients/Python/coverage/xmlreport.py</Source> + <Source>DebugClients/Python/eric6dbgstub.py</Source> + <Source>DebugClients/Python/getpass.py</Source> <Source>DebugClients/Ruby/AsyncFile.rb</Source> <Source>DebugClients/Ruby/AsyncIO.rb</Source> <Source>DebugClients/Ruby/Completer.rb</Source> @@ -514,6 +514,7 @@ <Source>Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleStatisticsDialog.py</Source> <Source>Plugins/CheckerPlugins/CodeStyleChecker/DocStyleChecker.py</Source> <Source>Plugins/CheckerPlugins/CodeStyleChecker/McCabeChecker.py</Source> + <Source>Plugins/CheckerPlugins/CodeStyleChecker/MiscellaneousChecker.py</Source> <Source>Plugins/CheckerPlugins/CodeStyleChecker/NamingStyleChecker.py</Source> <Source>Plugins/CheckerPlugins/CodeStyleChecker/__init__.py</Source> <Source>Plugins/CheckerPlugins/CodeStyleChecker/mccabe.py</Source> @@ -1663,14 +1664,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> @@ -1681,8 +1682,8 @@ <Other>CSSs</Other> <Other>CodeTemplates</Other> <Other>DTDs</Other> + <Other>DebugClients/Python3/coverage/doc</Other> <Other>DebugClients/Python/coverage/doc</Other> - <Other>DebugClients/Python3/coverage/doc</Other> <Other>DesignerTemplates</Other> <Other>Dictionaries</Other> <Other>Documentation/Help</Other>