Continued changing the names of the various code style checkers to make them more appropriate to the broadened scope.

Fri, 04 Oct 2013 14:26:08 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Fri, 04 Oct 2013 14:26:08 +0200
changeset 2982
556adfe76ba7
parent 2981
0c5205aa7a5a
child 2983
f2f33024b001

Continued changing the names of the various code style checkers to make them more appropriate to the broadened scope.

Documentation/Source/eric5.Plugins.PluginPep8Checker.html file | annotate | diff | comparison | revisions
Documentation/Source/index-eric5.Plugins.CheckerPlugins.Pep8.html 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/CodeStyleCodeSelectionDialog.py file | annotate | diff | comparison | revisions
Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCodeSelectionDialog.ui file | annotate | diff | comparison | revisions
Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleFixer.py file | annotate | diff | comparison | revisions
Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleStatisticsDialog.py file | annotate | diff | comparison | revisions
Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleStatisticsDialog.ui file | annotate | diff | comparison | revisions
Plugins/CheckerPlugins/CodeStyleChecker/DocStyleChecker.py file | annotate | diff | comparison | revisions
Plugins/CheckerPlugins/CodeStyleChecker/NamingStyleChecker.py file | annotate | diff | comparison | revisions
Plugins/CheckerPlugins/CodeStyleChecker/__init__.py file | annotate | diff | comparison | revisions
Plugins/CheckerPlugins/CodeStyleChecker/pep8.py file | annotate | diff | comparison | revisions
Plugins/CheckerPlugins/Pep8/CodeStyleChecker.py file | annotate | diff | comparison | revisions
Plugins/CheckerPlugins/Pep8/CodeStyleCheckerDialog.py file | annotate | diff | comparison | revisions
Plugins/CheckerPlugins/Pep8/CodeStyleCheckerDialog.ui file | annotate | diff | comparison | revisions
Plugins/CheckerPlugins/Pep8/CodeStyleCodeSelectionDialog.py file | annotate | diff | comparison | revisions
Plugins/CheckerPlugins/Pep8/CodeStyleCodeSelectionDialog.ui file | annotate | diff | comparison | revisions
Plugins/CheckerPlugins/Pep8/CodeStyleFixer.py file | annotate | diff | comparison | revisions
Plugins/CheckerPlugins/Pep8/CodeStyleStatisticsDialog.py file | annotate | diff | comparison | revisions
Plugins/CheckerPlugins/Pep8/CodeStyleStatisticsDialog.ui file | annotate | diff | comparison | revisions
Plugins/CheckerPlugins/Pep8/DocStyleChecker.py file | annotate | diff | comparison | revisions
Plugins/CheckerPlugins/Pep8/NamingStyleChecker.py file | annotate | diff | comparison | revisions
Plugins/CheckerPlugins/Pep8/__init__.py file | annotate | diff | comparison | revisions
Plugins/CheckerPlugins/Pep8/pep8.py file | annotate | diff | comparison | revisions
Plugins/PluginCodeStyleChecker.py file | annotate | diff | comparison | revisions
Plugins/PluginPep8Checker.py file | annotate | diff | comparison | revisions
eric5.e4p file | annotate | diff | comparison | revisions
--- a/Documentation/Source/eric5.Plugins.PluginPep8Checker.html	Wed Oct 02 18:58:13 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,216 +0,0 @@
-<!DOCTYPE html>
-<html><head>
-<title>eric5.Plugins.PluginPep8Checker</title>
-<meta charset="UTF-8">
-<style>
-body {
-    background: #EDECE6;
-    margin: 0em 1em 10em 1em;
-    color: black;
-}
-
-h1 { color: white; background: #85774A; }
-h2 { color: white; background: #85774A; }
-h3 { color: white; background: #9D936E; }
-h4 { color: white; background: #9D936E; }
-    
-a { color: #BA6D36; }
-
-</style>
-</head>
-<body><a NAME="top" ID="top"></a>
-<h1>eric5.Plugins.PluginPep8Checker</h1>
-<p>
-Module implementing the PEP 8 Checker plugin.
-</p>
-<h3>Global Attributes</h3>
-<table>
-<tr><td>author</td></tr><tr><td>autoactivate</td></tr><tr><td>className</td></tr><tr><td>deactivateable</td></tr><tr><td>error</td></tr><tr><td>longDescription</td></tr><tr><td>name</td></tr><tr><td>packageName</td></tr><tr><td>pyqtApi</td></tr><tr><td>shortDescription</td></tr><tr><td>version</td></tr>
-</table>
-<h3>Classes</h3>
-<table>
-<tr>
-<td><a href="#Pep8CheckerPlugin">Pep8CheckerPlugin</a></td>
-<td>Class implementing the PEP 8 Checker plugin.</td>
-</tr>
-</table>
-<h3>Functions</h3>
-<table>
-<tr><td>None</td></tr>
-</table>
-<hr /><hr />
-<a NAME="Pep8CheckerPlugin" ID="Pep8CheckerPlugin"></a>
-<h2>Pep8CheckerPlugin</h2>
-<p>
-    Class implementing the PEP 8 Checker plugin.
-</p>
-<h3>Derived from</h3>
-QObject
-<h3>Class Attributes</h3>
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Class Methods</h3>
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Methods</h3>
-<table>
-<tr>
-<td><a href="#Pep8CheckerPlugin.__init__">Pep8CheckerPlugin</a></td>
-<td>Constructor</td>
-</tr><tr>
-<td><a href="#Pep8CheckerPlugin.__editorClosed">__editorClosed</a></td>
-<td>Private slot called, when an editor was closed.</td>
-</tr><tr>
-<td><a href="#Pep8CheckerPlugin.__editorOpened">__editorOpened</a></td>
-<td>Private slot called, when a new editor was opened.</td>
-</tr><tr>
-<td><a href="#Pep8CheckerPlugin.__editorPep8Check">__editorPep8Check</a></td>
-<td>Private slot to handle the PEP 8 check context menu action of the editors.</td>
-</tr><tr>
-<td><a href="#Pep8CheckerPlugin.__editorShowMenu">__editorShowMenu</a></td>
-<td>Private slot called, when the the editor context menu or a submenu is about to be shown.</td>
-</tr><tr>
-<td><a href="#Pep8CheckerPlugin.__initialize">__initialize</a></td>
-<td>Private slot to (re)initialize the plugin.</td>
-</tr><tr>
-<td><a href="#Pep8CheckerPlugin.__projectBrowserPep8Check">__projectBrowserPep8Check</a></td>
-<td>Private method to handle the PEP 8 check context menu action of the project sources browser.</td>
-</tr><tr>
-<td><a href="#Pep8CheckerPlugin.__projectBrowserShowMenu">__projectBrowserShowMenu</a></td>
-<td>Private slot called, when the the project browser menu or a submenu is about to be shown.</td>
-</tr><tr>
-<td><a href="#Pep8CheckerPlugin.__projectPep8Check">__projectPep8Check</a></td>
-<td>Public slot used to check the project files for PEP 8 compliance.</td>
-</tr><tr>
-<td><a href="#Pep8CheckerPlugin.__projectShowMenu">__projectShowMenu</a></td>
-<td>Private slot called, when the the project menu or a submenu is about to be shown.</td>
-</tr><tr>
-<td><a href="#Pep8CheckerPlugin.activate">activate</a></td>
-<td>Public method to activate this plugin.</td>
-</tr><tr>
-<td><a href="#Pep8CheckerPlugin.deactivate">deactivate</a></td>
-<td>Public method to deactivate this plugin.</td>
-</tr>
-</table>
-<h3>Static Methods</h3>
-<table>
-<tr><td>None</td></tr>
-</table>
-<a NAME="Pep8CheckerPlugin.__init__" ID="Pep8CheckerPlugin.__init__"></a>
-<h4>Pep8CheckerPlugin (Constructor)</h4>
-<b>Pep8CheckerPlugin</b>(<i>ui</i>)
-<p>
-        Constructor
-</p><dl>
-<dt><i>ui</i></dt>
-<dd>
-reference to the user interface object (UI.UserInterface)
-</dd>
-</dl><a NAME="Pep8CheckerPlugin.__editorClosed" ID="Pep8CheckerPlugin.__editorClosed"></a>
-<h4>Pep8CheckerPlugin.__editorClosed</h4>
-<b>__editorClosed</b>(<i>editor</i>)
-<p>
-        Private slot called, when an editor was closed.
-</p><dl>
-<dt><i>editor</i></dt>
-<dd>
-reference to the editor (QScintilla.Editor)
-</dd>
-</dl><a NAME="Pep8CheckerPlugin.__editorOpened" ID="Pep8CheckerPlugin.__editorOpened"></a>
-<h4>Pep8CheckerPlugin.__editorOpened</h4>
-<b>__editorOpened</b>(<i>editor</i>)
-<p>
-        Private slot called, when a new editor was opened.
-</p><dl>
-<dt><i>editor</i></dt>
-<dd>
-reference to the new editor (QScintilla.Editor)
-</dd>
-</dl><a NAME="Pep8CheckerPlugin.__editorPep8Check" ID="Pep8CheckerPlugin.__editorPep8Check"></a>
-<h4>Pep8CheckerPlugin.__editorPep8Check</h4>
-<b>__editorPep8Check</b>(<i></i>)
-<p>
-        Private slot to handle the PEP 8 check context menu action
-        of the editors.
-</p><a NAME="Pep8CheckerPlugin.__editorShowMenu" ID="Pep8CheckerPlugin.__editorShowMenu"></a>
-<h4>Pep8CheckerPlugin.__editorShowMenu</h4>
-<b>__editorShowMenu</b>(<i>menuName, menu, editor</i>)
-<p>
-        Private slot called, when the the editor context menu or a submenu is
-        about to be shown.
-</p><dl>
-<dt><i>menuName</i></dt>
-<dd>
-name of the menu to be shown (string)
-</dd><dt><i>menu</i></dt>
-<dd>
-reference to the menu (QMenu)
-</dd><dt><i>editor</i></dt>
-<dd>
-reference to the editor
-</dd>
-</dl><a NAME="Pep8CheckerPlugin.__initialize" ID="Pep8CheckerPlugin.__initialize"></a>
-<h4>Pep8CheckerPlugin.__initialize</h4>
-<b>__initialize</b>(<i></i>)
-<p>
-        Private slot to (re)initialize the plugin.
-</p><a NAME="Pep8CheckerPlugin.__projectBrowserPep8Check" ID="Pep8CheckerPlugin.__projectBrowserPep8Check"></a>
-<h4>Pep8CheckerPlugin.__projectBrowserPep8Check</h4>
-<b>__projectBrowserPep8Check</b>(<i></i>)
-<p>
-        Private method to handle the PEP 8 check context menu action of
-        the project sources browser.
-</p><a NAME="Pep8CheckerPlugin.__projectBrowserShowMenu" ID="Pep8CheckerPlugin.__projectBrowserShowMenu"></a>
-<h4>Pep8CheckerPlugin.__projectBrowserShowMenu</h4>
-<b>__projectBrowserShowMenu</b>(<i>menuName, menu</i>)
-<p>
-        Private slot called, when the the project browser menu or a submenu is
-        about to be shown.
-</p><dl>
-<dt><i>menuName</i></dt>
-<dd>
-name of the menu to be shown (string)
-</dd><dt><i>menu</i></dt>
-<dd>
-reference to the menu (QMenu)
-</dd>
-</dl><a NAME="Pep8CheckerPlugin.__projectPep8Check" ID="Pep8CheckerPlugin.__projectPep8Check"></a>
-<h4>Pep8CheckerPlugin.__projectPep8Check</h4>
-<b>__projectPep8Check</b>(<i></i>)
-<p>
-        Public slot used to check the project files for PEP 8 compliance.
-</p><a NAME="Pep8CheckerPlugin.__projectShowMenu" ID="Pep8CheckerPlugin.__projectShowMenu"></a>
-<h4>Pep8CheckerPlugin.__projectShowMenu</h4>
-<b>__projectShowMenu</b>(<i>menuName, menu</i>)
-<p>
-        Private slot called, when the the project menu or a submenu is
-        about to be shown.
-</p><dl>
-<dt><i>menuName</i></dt>
-<dd>
-name of the menu to be shown (string)
-</dd><dt><i>menu</i></dt>
-<dd>
-reference to the menu (QMenu)
-</dd>
-</dl><a NAME="Pep8CheckerPlugin.activate" ID="Pep8CheckerPlugin.activate"></a>
-<h4>Pep8CheckerPlugin.activate</h4>
-<b>activate</b>(<i></i>)
-<p>
-        Public method to activate this plugin.
-</p><dl>
-<dt>Returns:</dt>
-<dd>
-tuple of None and activation status (boolean)
-</dd>
-</dl><a NAME="Pep8CheckerPlugin.deactivate" ID="Pep8CheckerPlugin.deactivate"></a>
-<h4>Pep8CheckerPlugin.deactivate</h4>
-<b>deactivate</b>(<i></i>)
-<p>
-        Public method to deactivate this plugin.
-</p>
-<div align="right"><a href="#top">Up</a></div>
-<hr />
-</body></html>
\ No newline at end of file
--- a/Documentation/Source/index-eric5.Plugins.CheckerPlugins.Pep8.html	Wed Oct 02 18:58:13 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-<!DOCTYPE html>
-<html><head>
-<title>eric5.Plugins.CheckerPlugins.Pep8</title>
-<meta charset="UTF-8">
-<style>
-body {
-    background: #EDECE6;
-    margin: 0em 1em 10em 1em;
-    color: black;
-}
-
-h1 { color: white; background: #85774A; }
-h2 { color: white; background: #85774A; }
-h3 { color: white; background: #9D936E; }
-h4 { color: white; background: #9D936E; }
-    
-a { color: #BA6D36; }
-
-</style>
-</head>
-<body>
-<h1>eric5.Plugins.CheckerPlugins.Pep8</h1>
-<p>
-Package containing the PEP 8 plugin.
-</p>
-
-
-<h3>Modules</h3>
-<table>
-<tr>
-<td><a href="eric5.Plugins.CheckerPlugins.Pep8.Pep257Checker.html">Pep257Checker</a></td>
-<td>Module implementing a checker for PEP-257 documentation string conventions.</td>
-</tr><tr>
-<td><a href="eric5.Plugins.CheckerPlugins.Pep8.Pep8Checker.html">Pep8Checker</a></td>
-<td>Module implementing the PEP 8 checker.</td>
-</tr><tr>
-<td><a href="eric5.Plugins.CheckerPlugins.Pep8.Pep8CodeSelectionDialog.html">Pep8CodeSelectionDialog</a></td>
-<td>Module implementing a dialog to select PEP 8 message codes.</td>
-</tr><tr>
-<td><a href="eric5.Plugins.CheckerPlugins.Pep8.Pep8Dialog.html">Pep8Dialog</a></td>
-<td>Module implementing a dialog to show the results of the PEP 8 check.</td>
-</tr><tr>
-<td><a href="eric5.Plugins.CheckerPlugins.Pep8.Pep8Fixer.html">Pep8Fixer</a></td>
-<td>Module implementing a class to fix certain code style issues.</td>
-</tr><tr>
-<td><a href="eric5.Plugins.CheckerPlugins.Pep8.Pep8NamingChecker.html">Pep8NamingChecker</a></td>
-<td>Module implementing a checker for PEP-8 naming conventions.</td>
-</tr><tr>
-<td><a href="eric5.Plugins.CheckerPlugins.Pep8.Pep8StatisticsDialog.html">Pep8StatisticsDialog</a></td>
-<td>Module implementing a dialog showing statistical data for the last code style checker run.</td>
-</tr><tr>
-<td><a href="eric5.Plugins.CheckerPlugins.Pep8.pep8.html">pep8</a></td>
-<td></td>
-</tr>
-</table>
-</body></html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleChecker.py	Fri Oct 04 14:26:08 2013 +0200
@@ -0,0 +1,128 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2011 - 2013 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing the code style checker.
+"""
+
+import os
+
+from PyQt4.QtCore import QProcess, QCoreApplication
+
+from . import pep8
+from .NamingStyleChecker import NamingStyleChecker
+from .DocStyleChecker import DocStyleChecker
+
+import Preferences
+import Utilities
+
+from eric5config import getConfig
+
+
+class CodeStyleCheckerPy2(object):
+    """
+    Class implementing the code style checker interface for Python 2.
+    """
+    def __init__(self, filename, lines, repeat=False,
+                 select="", ignore="", max_line_length=79,
+                 hang_closing=False, docType="pep257"):
+        """
+        Constructor
+        
+        @param filename name of the file to check (string)
+        @param lines source of the file (list of strings) (ignored)
+        @keyparam repeat flag indicating to repeat message categories (boolean)
+        @keyparam select list of message IDs to check for
+            (comma separated string)
+        @keyparam ignore list of message IDs to ignore
+            (comma separated string)
+        @keyparam max_line_length maximum allowed line length (integer)
+        @keyparam hang_closing flag indicating to allow hanging closing
+            brackets (boolean)
+        @keyparam docType type of the documentation strings
+            (string, one of 'eric' or 'pep257')
+        """
+        assert docType in ("eric", "pep257")
+        
+        self.errors = []
+        self.counters = {}
+        
+        interpreter = Preferences.getDebugger("PythonInterpreter")
+        if interpreter == "" or not Utilities.isExecutable(interpreter):
+            self.errors.append((filename, 1, 1,
+                QCoreApplication.translate("CodeStyleCheckerPy2",
+                    "Python2 interpreter not configured.")))
+            return
+        
+        checker = os.path.join(getConfig('ericDir'),
+                               "UtilitiesPython2", "Pep8Checker.py")
+        
+        args = [checker]
+        if repeat:
+            args.append("-r")
+        if select:
+            args.append("-s")
+            args.append(select)
+        if ignore:
+            args.append("-i")
+            args.append(ignore)
+        args.append("-m")
+        args.append(str(max_line_length))
+        if hang_closing:
+            args.append("-h")
+        args.append("-d")
+        args.append(docType)
+        args.append("-f")
+        args.append(filename)
+        
+        proc = QProcess()
+        proc.setProcessChannelMode(QProcess.MergedChannels)
+        proc.start(interpreter, args)
+        finished = proc.waitForFinished(15000)
+        if finished:
+            output = \
+                str(proc.readAllStandardOutput(),
+                        Preferences.getSystem("IOEncoding"),
+                        'replace').splitlines()
+            if output[0] == "ERROR":
+                self.errors.append((filename, 1, 1, output[2]))
+                return
+            
+            if output[0] == "NO_PEP8":
+                return
+            
+            index = 0
+            while index < len(output):
+                if output[index] == "PEP8_STATISTICS":
+                    index += 1
+                    break
+                
+                fname = output[index + 1]
+                lineno = int(output[index + 2])
+                position = int(output[index + 3])
+                code = output[index + 4]
+                arglen = int(output[index + 5])
+                args = []
+                argindex = 0
+                while argindex < arglen:
+                    args.append(output[index + 6 + argindex])
+                    argindex += 1
+                index += 6 + arglen
+                
+                if code in NamingStyleChecker.Codes:
+                    text = NamingStyleChecker.getMessage(code, *args)
+                elif code in DocStyleChecker.Codes:
+                    text = DocStyleChecker.getMessage(code, *args)
+                else:
+                    text = pep8.getMessage(code, *args)
+                self.errors.append((fname, lineno, position, text))
+            while index < len(output):
+                code, countStr = output[index].split(None, 1)
+                self.counters[code] = int(countStr)
+                index += 1
+        else:
+            self.errors.append((filename, 1, 1,
+                QCoreApplication.translate("CodeStyleCheckerPy2",
+                    "Python2 interpreter did not finish within 15s.")))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCheckerDialog.py	Fri Oct 04 14:26:08 2013 +0200
@@ -0,0 +1,906 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2011 - 2013 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a dialog to show the results of the code style check.
+"""
+
+import os
+import fnmatch
+
+from PyQt4.QtCore import pyqtSlot, Qt
+from PyQt4.QtGui import QDialog, QTreeWidgetItem, QAbstractButton, \
+    QDialogButtonBox, QApplication, QHeaderView, QIcon
+
+from E5Gui.E5Application import e5App
+
+from .Ui_CodeStyleCheckerDialog import Ui_CodeStyleCheckerDialog
+
+import UI.PixmapCache
+import Preferences
+import Utilities
+
+from . import pep8
+from .NamingStyleChecker import NamingStyleChecker
+
+# register the name checker
+pep8.register_check(NamingStyleChecker, NamingStyleChecker.Codes)
+
+from .DocStyleChecker import DocStyleChecker
+
+
+class CodeStyleCheckerReport(pep8.BaseReport):
+    """
+    Class implementing a special report to be used with our dialog.
+    """
+    def __init__(self, options):
+        """
+        Constructor
+        
+        @param options options for the report (optparse.Values)
+        """
+        super().__init__(options)
+        
+        self.__repeat = options.repeat
+        self.errors = []
+    
+    def error_args(self, line_number, offset, code, check, *args):
+        """
+        Public method to collect the error messages.
+        
+        @param line_number line number of the issue (integer)
+        @param offset position within line of the issue (integer)
+        @param code message code (string)
+        @param check reference to the checker function (function)
+        @param args arguments for the message (list)
+        @return error code (string)
+        """
+        code = super().error_args(line_number, offset, code, check, *args)
+        if code and (self.counters[code] == 1 or self.__repeat):
+            if code in NamingStyleChecker.Codes:
+                text = NamingStyleChecker.getMessage(code, *args)
+            else:
+                text = pep8.getMessage(code, *args)
+            self.errors.append(
+                (self.filename, line_number, offset, text)
+            )
+        return code
+
+
+class CodeStyleCheckerDialog(QDialog, Ui_CodeStyleCheckerDialog):
+    """
+    Class implementing a dialog to show the results of the code style check.
+    """
+    filenameRole = Qt.UserRole + 1
+    lineRole = Qt.UserRole + 2
+    positionRole = Qt.UserRole + 3
+    messageRole = Qt.UserRole + 4
+    fixableRole = Qt.UserRole + 5
+    codeRole = Qt.UserRole + 6
+    
+    def __init__(self, parent=None):
+        """
+        Constructor
+        
+        @param parent reference to the parent widget (QWidget)
+        """
+        super().__init__(parent)
+        self.setupUi(self)
+        
+        self.docTypeComboBox.addItem(self.trUtf8("PEP-257"), "pep257")
+        self.docTypeComboBox.addItem(self.trUtf8("Eric"), "eric")
+        
+        self.statisticsButton = self.buttonBox.addButton(
+            self.trUtf8("Statistics..."), QDialogButtonBox.ActionRole)
+        self.statisticsButton.setToolTip(
+            self.trUtf8("Press to show some statistics for the last run"))
+        self.statisticsButton.setEnabled(False)
+        self.showButton = self.buttonBox.addButton(
+            self.trUtf8("Show"), QDialogButtonBox.ActionRole)
+        self.showButton.setToolTip(
+            self.trUtf8("Press to show all files containing an issue"))
+        self.showButton.setEnabled(False)
+        self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False)
+        self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True)
+        
+        self.resultList.headerItem().setText(self.resultList.columnCount(), "")
+        self.resultList.header().setSortIndicator(0, Qt.AscendingOrder)
+        
+        self.checkProgress.setVisible(False)
+        self.checkProgressLabel.setVisible(False)
+        self.checkProgressLabel.setMaximumWidth(600)
+        
+        self.noResults = True
+        self.cancelled = False
+        self.__lastFileItem = None
+        
+        self.__fileOrFileList = ""
+        self.__project = None
+        self.__forProject = False
+        self.__data = {}
+        self.__statistics = {}
+        
+        self.on_loadDefaultButton_clicked()
+    
+    def __resort(self):
+        """
+        Private method to resort the tree.
+        """
+        self.resultList.sortItems(self.resultList.sortColumn(),
+                                  self.resultList.header().sortIndicatorOrder()
+                                 )
+    
+    def __createResultItem(self, file, line, pos, message, fixed, autofixing):
+        """
+        Private method to create an entry in the result list.
+        
+        @param file file name of the file (string)
+        @param line line number of issue (integer or string)
+        @param pos character position of issue (integer or string)
+        @param message message text (string)
+        @param fixed flag indicating a fixed issue (boolean)
+        @param autofixing flag indicating, that we are fixing issues
+            automatically (boolean)
+        @return reference to the created item (QTreeWidgetItem)
+        """
+        from .CodeStyleFixer import FixableCodeStyleIssues
+        
+        if self.__lastFileItem is None:
+            # It's a new file
+            self.__lastFileItem = QTreeWidgetItem(self.resultList, [file])
+            self.__lastFileItem.setFirstColumnSpanned(True)
+            self.__lastFileItem.setExpanded(True)
+            self.__lastFileItem.setData(0, self.filenameRole, file)
+        
+        fixable = False
+        code, message = message.split(None, 1)
+        itm = QTreeWidgetItem(self.__lastFileItem,
+            ["{0:6}".format(line), code, message])
+        if code.startswith("W"):
+            itm.setIcon(1, UI.PixmapCache.getIcon("warning.png"))
+        elif code.startswith("N"):
+            itm.setIcon(1, UI.PixmapCache.getIcon("namingError.png"))
+        elif code.startswith("D"):
+            itm.setIcon(1, UI.PixmapCache.getIcon("docstringError.png"))
+        else:
+            itm.setIcon(1, UI.PixmapCache.getIcon("syntaxError.png"))
+        if fixed:
+            itm.setIcon(0, UI.PixmapCache.getIcon("issueFixed.png"))
+        elif code in FixableCodeStyleIssues and not autofixing:
+            itm.setIcon(0, UI.PixmapCache.getIcon("issueFixable.png"))
+            fixable = True
+        
+        itm.setTextAlignment(0, Qt.AlignRight)
+        itm.setTextAlignment(1, Qt.AlignHCenter)
+        
+        itm.setTextAlignment(0, Qt.AlignVCenter)
+        itm.setTextAlignment(1, Qt.AlignVCenter)
+        itm.setTextAlignment(2, Qt.AlignVCenter)
+        
+        itm.setData(0, self.filenameRole, file)
+        itm.setData(0, self.lineRole, int(line))
+        itm.setData(0, self.positionRole, int(pos))
+        itm.setData(0, self.messageRole, message)
+        itm.setData(0, self.fixableRole, fixable)
+        itm.setData(0, self.codeRole, code)
+        
+        return itm
+    
+    def __modifyFixedResultItem(self, itm, text, fixed):
+        """
+        Private method to modify a result list entry to show its
+        positive fixed state.
+        
+        @param itm reference to the item to modify (QTreeWidgetItem)
+        @param text text to be appended (string)
+        @param fixed flag indicating a fixed issue (boolean)
+        """
+        if fixed:
+            message = itm.data(0, self.messageRole) + text
+            itm.setText(2, message)
+            itm.setIcon(0, UI.PixmapCache.getIcon("issueFixed.png"))
+            
+            itm.setData(0, self.messageRole, message)
+        else:
+            itm.setIcon(0, QIcon())
+        itm.setData(0, self.fixableRole, False)
+    
+    def __updateStatistics(self, statistics, fixer):
+        """
+        Private method to update the collected statistics.
+        
+        @param statistics dictionary of statistical data with
+            message code as key and message count as value
+        @param fixer reference to the code style fixer (CodeStyleFixer)
+        """
+        self.__statistics["_FilesCount"] += 1
+        stats = {v: k for v, k in statistics.items() if v[0].isupper()}
+        if stats:
+            self.__statistics["_FilesIssues"] += 1
+            for key in statistics:
+                if key in self.__statistics:
+                    self.__statistics[key] += statistics[key]
+                else:
+                    self.__statistics[key] = statistics[key]
+        if fixer:
+            self.__statistics["_IssuesFixed"] += fixer.fixed
+    
+    def __updateFixerStatistics(self, fixer):
+        """
+        Private method to update the collected fixer related statistics.
+        
+        @param fixer reference to the code style fixer (CodeStyleFixer)
+        """
+        self.__statistics["_IssuesFixed"] += fixer.fixed
+    
+    def __resetStatistics(self):
+        """
+        Private slot to reset the statistics data.
+        """
+        self.__statistics = {}
+        self.__statistics["_FilesCount"] = 0
+        self.__statistics["_FilesIssues"] = 0
+        self.__statistics["_IssuesFixed"] = 0
+    
+    def prepare(self, fileList, project):
+        """
+        Public method to prepare the dialog with a list of filenames.
+        
+        @param fileList list of filenames (list of strings)
+        @param project reference to the project object (Project)
+        """
+        self.__fileOrFileList = fileList[:]
+        self.__project = project
+        self.__forProject = True
+        
+        self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True)
+        self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False)
+        self.buttonBox.button(QDialogButtonBox.Close).setDefault(True)
+        
+        self.__data = self.__project.getData("CHECKERSPARMS", "Pep8Checker")
+        if self.__data is None or \
+           len(self.__data) < 6:
+            # initialize the data structure
+            self.__data = {
+                "ExcludeFiles": "",
+                "ExcludeMessages": pep8.DEFAULT_IGNORE,
+                "IncludeMessages": "",
+                "RepeatMessages": False,
+                "FixCodes": "",
+                "FixIssues": False,
+            }
+        if "MaxLineLength" not in self.__data:
+            self.__data["MaxLineLength"] = pep8.MAX_LINE_LENGTH
+        if "HangClosing" not in self.__data:
+            self.__data["HangClosing"] = False
+        if "NoFixCodes" not in self.__data:
+            self.__data["NoFixCodes"] = "E501"
+        if "DocstringType" not in self.__data:
+            self.__data["DocstringType"] = "pep257"
+        
+        self.excludeFilesEdit.setText(self.__data["ExcludeFiles"])
+        self.excludeMessagesEdit.setText(self.__data["ExcludeMessages"])
+        self.includeMessagesEdit.setText(self.__data["IncludeMessages"])
+        self.repeatCheckBox.setChecked(self.__data["RepeatMessages"])
+        self.fixIssuesEdit.setText(self.__data["FixCodes"])
+        self.noFixIssuesEdit.setText(self.__data["NoFixCodes"])
+        self.fixIssuesCheckBox.setChecked(self.__data["FixIssues"])
+        self.lineLengthSpinBox.setValue(self.__data["MaxLineLength"])
+        self.hangClosingCheckBox.setChecked(self.__data["HangClosing"])
+        self.docTypeComboBox.setCurrentIndex(
+            self.docTypeComboBox.findData(self.__data["DocstringType"]))
+    
+    def start(self, fn, save=False, repeat=None):
+        """
+        Public slot to start the code style check.
+        
+        @param fn file or list of files or directory to be checked
+                (string or list of strings)
+        @keyparam save flag indicating to save the given
+            file/file list/directory (boolean)
+        @keyparam repeat state of the repeat check box if it is not None
+            (None or boolean)
+        """
+        if self.__project is None:
+            self.__project = e5App().getObject("Project")
+        
+        self.cancelled = False
+        self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False)
+        self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(True)
+        self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True)
+        self.statisticsButton.setEnabled(False)
+        self.showButton.setEnabled(False)
+        self.fixButton.setEnabled(False)
+        self.startButton.setEnabled(False)
+        if repeat is not None:
+            self.repeatCheckBox.setChecked(repeat)
+        self.checkProgress.setVisible(True)
+        QApplication.processEvents()
+        
+        self.__resetStatistics()
+        
+        if save:
+            self.__fileOrFileList = fn
+        
+        if isinstance(fn, list):
+            files = fn[:]
+        elif os.path.isdir(fn):
+            files = []
+            for ext in Preferences.getPython("Python3Extensions"):
+                files.extend(
+                    Utilities.direntries(fn, 1, '*{0}'.format(ext), 0))
+            for ext in Preferences.getPython("PythonExtensions"):
+                files.extend(
+                    Utilities.direntries(fn, 1, '*{0}'.format(ext), 0))
+        else:
+            files = [fn]
+        
+        # filter the list depending on the filter string
+        if files:
+            filterString = self.excludeFilesEdit.text()
+            filterList = [f.strip() for f in filterString.split(",")
+                          if f.strip()]
+            for filter in filterList:
+                files = \
+                    [f for f in files
+                     if not fnmatch.fnmatch(f, filter.strip())]
+        
+        py3files = [f for f in files \
+                    if f.endswith(
+                        tuple(Preferences.getPython("Python3Extensions")))]
+        py2files = [f for f in files \
+                    if f.endswith(
+                        tuple(Preferences.getPython("PythonExtensions")))]
+        
+        if len(py3files) + len(py2files) > 0:
+            self.checkProgress.setMaximum(len(py3files) + len(py2files))
+            self.checkProgressLabel.setVisible(
+                len(py3files) + len(py2files) > 1)
+            QApplication.processEvents()
+            
+            # extract the configuration values
+            excludeMessages = self.excludeMessagesEdit.text()
+            includeMessages = self.includeMessagesEdit.text()
+            repeatMessages = self.repeatCheckBox.isChecked()
+            fixCodes = self.fixIssuesEdit.text()
+            noFixCodes = self.noFixIssuesEdit.text()
+            fixIssues = self.fixIssuesCheckBox.isChecked() and repeatMessages
+            maxLineLength = self.lineLengthSpinBox.value()
+            hangClosing = self.hangClosingCheckBox.isChecked()
+            docType = self.docTypeComboBox.itemData(
+                self.docTypeComboBox.currentIndex())
+            
+            try:
+                # disable updates of the list for speed
+                self.resultList.setUpdatesEnabled(False)
+                self.resultList.setSortingEnabled(False)
+                
+                # now go through all the files
+                progress = 0
+                for file in sorted(py3files + py2files):
+                    self.checkProgress.setValue(progress)
+                    self.checkProgressLabel.setPath(file)
+                    QApplication.processEvents()
+                    
+                    if self.cancelled:
+                        self.__resort()
+                        return
+                    
+                    self.__lastFileItem = None
+                    
+                    try:
+                        source, encoding = Utilities.readEncodedFile(file)
+                        source = source.splitlines(True)
+                    except (UnicodeError, IOError) as msg:
+                        self.noResults = False
+                        self.__createResultItem(file, "1", "1",
+                            self.trUtf8("Error: {0}").format(str(msg))\
+                                .rstrip()[1:-1], False, False)
+                        progress += 1
+                        continue
+                    
+                    stats = {}
+                    flags = Utilities.extractFlags(source)
+                    ext = os.path.splitext(file)[1]
+                    if fixIssues:
+                        from .CodeStyleFixer import CodeStyleFixer
+                        fixer = CodeStyleFixer(self.__project, file, source,
+                                          fixCodes, noFixCodes, maxLineLength,
+                                          True)  # always fix in place
+                    else:
+                        fixer = None
+                    if ("FileType" in flags and
+                        flags["FileType"] in ["Python", "Python2"]) or \
+                       file in py2files or \
+                       (ext in [".py", ".pyw"] and \
+                        Preferences.getProject("DeterminePyFromProject") and \
+                        self.__project.isOpen() and \
+                        self.__project.isProjectFile(file) and \
+                        self.__project.getProjectLanguage() in ["Python",
+                                                                "Python2"]):
+                        from .CodeStyleChecker import CodeStyleCheckerPy2
+                        report = CodeStyleCheckerPy2(file, [],
+                            repeat=repeatMessages,
+                            select=includeMessages,
+                            ignore=excludeMessages,
+                            max_line_length=maxLineLength,
+                            hang_closing=hangClosing,
+                            docType=docType,
+                        )
+                        errors = report.errors[:]
+                        stats.update(report.counters)
+                    else:
+                        if includeMessages:
+                            select = [s.strip() for s in includeMessages.split(',')
+                                      if s.strip()]
+                        else:
+                            select = []
+                        if excludeMessages:
+                            ignore = [i.strip() for i in excludeMessages.split(',')
+                                      if i.strip()]
+                        else:
+                            ignore = []
+                        
+                        # check PEP-8
+                        styleGuide = pep8.StyleGuide(
+                            reporter=CodeStyleCheckerReport,
+                            repeat=repeatMessages,
+                            select=select,
+                            ignore=ignore,
+                            max_line_length=maxLineLength,
+                            hang_closing=hangClosing,
+                        )
+                        report = styleGuide.check_files([file])
+                        stats.update(report.counters)
+                        
+                        # check PEP-257
+                        pep257Checker = DocStyleChecker(
+                            source, file, select, ignore, [], repeatMessages,
+                            maxLineLength=maxLineLength, docType=docType)
+                        pep257Checker.run()
+                        stats.update(pep257Checker.counters)
+                        
+                        errors = report.errors + pep257Checker.errors
+                    
+                    deferredFixes = {}
+                    for error in errors:
+                        fname, lineno, position, text = error
+                        if lineno > len(source):
+                            lineno = len(source)
+                        if "__IGNORE_WARNING__" not in Utilities.extractLineFlags(
+                                source[lineno - 1].strip()):
+                            self.noResults = False
+                            if fixer:
+                                res, msg, id_ = fixer.fixIssue(lineno, position, text)
+                                if res == 1:
+                                    text += "\n" + \
+                                            self.trUtf8("Fix: {0}").format(msg)
+                                    self.__createResultItem(
+                                        fname, lineno, position, text, True, True)
+                                elif res == 0:
+                                    self.__createResultItem(
+                                        fname, lineno, position, text, False, True)
+                                else:
+                                    itm = self.__createResultItem(
+                                        fname, lineno, position,
+                                        text, False, False)
+                                    deferredFixes[id_] = itm
+                            else:
+                                self.__createResultItem(
+                                    fname, lineno, position, text, False, False)
+                    if fixer:
+                        deferredResults = fixer.finalize()
+                        for id_ in deferredResults:
+                            fixed, msg = deferredResults[id_]
+                            itm = deferredFixes[id_]
+                            if fixed == 1:
+                                text = "\n" + self.trUtf8("Fix: {0}").format(msg)
+                                self.__modifyFixedResultItem(itm, text, True)
+                            else:
+                                self.__modifyFixedResultItem(itm, "", False)
+                        fixer.saveFile(encoding)
+                    self.__updateStatistics(stats, fixer)
+                    progress += 1
+            finally:
+                # reenable updates of the list
+                self.resultList.setSortingEnabled(True)
+                self.resultList.setUpdatesEnabled(True)
+            self.checkProgress.setValue(progress)
+            self.checkProgressLabel.setPath("")
+            QApplication.processEvents()
+            self.__resort()
+        else:
+            self.checkProgress.setMaximum(1)
+            self.checkProgress.setValue(1)
+        self.__finish()
+    
+    def __finish(self):
+        """
+        Private slot called when the code style check finished or the user
+        pressed the cancel button.
+        """
+        self.cancelled = True
+        self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True)
+        self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False)
+        self.buttonBox.button(QDialogButtonBox.Close).setDefault(True)
+        self.statisticsButton.setEnabled(True)
+        self.showButton.setEnabled(True)
+        self.startButton.setEnabled(True)
+        
+        if self.noResults:
+            QTreeWidgetItem(self.resultList, [self.trUtf8('No issues found.')])
+            QApplication.processEvents()
+            self.statisticsButton.setEnabled(False)
+            self.showButton.setEnabled(False)
+            self.__clearErrors()
+        else:
+            self.statisticsButton.setEnabled(True)
+            self.showButton.setEnabled(True)
+        self.resultList.header().resizeSections(QHeaderView.ResizeToContents)
+        self.resultList.header().setStretchLastSection(True)
+        
+        self.checkProgress.setVisible(False)
+        self.checkProgressLabel.setVisible(False)
+    
+    @pyqtSlot()
+    def on_startButton_clicked(self):
+        """
+        Private slot to start a code style check run.
+        """
+        if self.__forProject:
+            data = {
+                "ExcludeFiles": self.excludeFilesEdit.text(),
+                "ExcludeMessages": self.excludeMessagesEdit.text(),
+                "IncludeMessages": self.includeMessagesEdit.text(),
+                "RepeatMessages": self.repeatCheckBox.isChecked(),
+                "FixCodes": self.fixIssuesEdit.text(),
+                "NoFixCodes": self.noFixIssuesEdit.text(),
+                "FixIssues": self.fixIssuesCheckBox.isChecked(),
+                "MaxLineLength": self.lineLengthSpinBox.value(),
+                "HangClosing": self.hangClosingCheckBox.isChecked(),
+                "DocstringType": self.docTypeComboBox.itemData(
+                    self.docTypeComboBox.currentIndex()),
+            }
+            if data != self.__data:
+                self.__data = data
+                self.__project.setData("CHECKERSPARMS", "Pep8Checker",
+                                       self.__data)
+        
+        self.resultList.clear()
+        self.noResults = True
+        self.cancelled = False
+        self.start(self.__fileOrFileList)
+    
+    def __selectCodes(self, edit, showFixCodes):
+        """
+        Private method to select message codes via a selection dialog.
+        
+        @param edit reference of the line edit to be populated (QLineEdit)
+        @param showFixCodes flag indicating to show a list of fixable
+            issues (boolean)
+        """
+        from .CodeStyleCodeSelectionDialog import CodeStyleCodeSelectionDialog
+        dlg = CodeStyleCodeSelectionDialog(edit.text(), showFixCodes, self)
+        if dlg.exec_() == QDialog.Accepted:
+            edit.setText(dlg.getSelectedCodes())
+    
+    @pyqtSlot()
+    def on_excludeMessagesSelectButton_clicked(self):
+        """
+        Private slot to select the message codes to be excluded via a
+        selection dialog.
+        """
+        self.__selectCodes(self.excludeMessagesEdit, False)
+    
+    @pyqtSlot()
+    def on_includeMessagesSelectButton_clicked(self):
+        """
+        Private slot to select the message codes to be included via a
+        selection dialog.
+        """
+        self.__selectCodes(self.includeMessagesEdit, False)
+    
+    @pyqtSlot()
+    def on_fixIssuesSelectButton_clicked(self):
+        """
+        Private slot to select the issue codes to be fixed via a
+        selection dialog.
+        """
+        self.__selectCodes(self.fixIssuesEdit, True)
+    
+    @pyqtSlot()
+    def on_noFixIssuesSelectButton_clicked(self):
+        """
+        Private slot to select the issue codes not to be fixed via a
+        selection dialog.
+        """
+        self.__selectCodes(self.noFixIssuesEdit, True)
+    
+    @pyqtSlot(QTreeWidgetItem, int)
+    def on_resultList_itemActivated(self, item, column):
+        """
+        Private slot to handle the activation of an item.
+        
+        @param item reference to the activated item (QTreeWidgetItem)
+        @param column column the item was activated in (integer)
+        """
+        if self.noResults:
+            return
+        
+        if item.parent():
+            fn = Utilities.normabspath(item.data(0, self.filenameRole))
+            lineno = item.data(0, self.lineRole)
+            position = item.data(0, self.positionRole)
+            message = item.data(0, self.messageRole)
+            code = item.data(0, self.codeRole)
+            
+            vm = e5App().getObject("ViewManager")
+            vm.openSourceFile(fn, lineno=lineno, pos=position + 1)
+            editor = vm.getOpenEditor(fn)
+            
+            if code == "E901":
+                editor.toggleSyntaxError(lineno, 0, True, message, True)
+            else:
+                editor.toggleFlakesWarning(
+                    lineno, True, message, warningType=editor.WarningStyle)
+    
+    @pyqtSlot()
+    def on_resultList_itemSelectionChanged(self):
+        """
+        Private slot to change the dialog state depending on the selection.
+        """
+        self.fixButton.setEnabled(len(self.__getSelectedFixableItems()) > 0)
+    
+    @pyqtSlot()
+    def on_showButton_clicked(self):
+        """
+        Private slot to handle the "Show" button press.
+        """
+        vm = e5App().getObject("ViewManager")
+        
+        selectedIndexes = []
+        for index in range(self.resultList.topLevelItemCount()):
+            if self.resultList.topLevelItem(index).isSelected():
+                selectedIndexes.append(index)
+        if len(selectedIndexes) == 0:
+            selectedIndexes = list(range(self.resultList.topLevelItemCount()))
+        for index in selectedIndexes:
+            itm = self.resultList.topLevelItem(index)
+            fn = Utilities.normabspath(itm.data(0, self.filenameRole))
+            vm.openSourceFile(fn, 1)
+            editor = vm.getOpenEditor(fn)
+            editor.clearFlakesWarnings()
+            for cindex in range(itm.childCount()):
+                citm = itm.child(cindex)
+                lineno = citm.data(0, self.lineRole)
+                message = citm.data(0, self.messageRole)
+                editor.toggleFlakesWarning(lineno, True, message)
+        
+        # go through the list again to clear warning markers for files,
+        # that are ok
+        openFiles = vm.getOpenFilenames()
+        errorFiles = []
+        for index in range(self.resultList.topLevelItemCount()):
+            itm = self.resultList.topLevelItem(index)
+            errorFiles.append(
+                Utilities.normabspath(itm.data(0, self.filenameRole)))
+        for file in openFiles:
+            if not file in errorFiles:
+                editor = vm.getOpenEditor(file)
+                editor.clearFlakesWarnings()
+    
+    @pyqtSlot()
+    def on_statisticsButton_clicked(self):
+        """
+        Private slot to show the statistics dialog.
+        """
+        from .CodeStyleStatisticsDialog import CodeStyleStatisticsDialog
+        dlg = CodeStyleStatisticsDialog(self.__statistics, self)
+        dlg.exec_()
+    
+    @pyqtSlot()
+    def on_loadDefaultButton_clicked(self):
+        """
+        Private slot to load the default configuration values.
+        """
+        self.excludeFilesEdit.setText(Preferences.Prefs.settings.value(
+            "PEP8/ExcludeFilePatterns"))
+        self.excludeMessagesEdit.setText(Preferences.Prefs.settings.value(
+            "PEP8/ExcludeMessages", pep8.DEFAULT_IGNORE))
+        self.includeMessagesEdit.setText(Preferences.Prefs.settings.value(
+            "PEP8/IncludeMessages"))
+        self.repeatCheckBox.setChecked(Preferences.toBool(
+            Preferences.Prefs.settings.value("PEP8/RepeatMessages")))
+        self.fixIssuesEdit.setText(Preferences.Prefs.settings.value(
+            "PEP8/FixCodes"))
+        self.noFixIssuesEdit.setText(Preferences.Prefs.settings.value(
+            "PEP8/NoFixCodes", "E501"))
+        self.fixIssuesCheckBox.setChecked(Preferences.toBool(
+            Preferences.Prefs.settings.value("PEP8/FixIssues")))
+        self.lineLengthSpinBox.setValue(int(Preferences.Prefs.settings.value(
+            "PEP8/MaxLineLength", pep8.MAX_LINE_LENGTH)))
+        self.hangClosingCheckBox.setChecked(Preferences.toBool(
+            Preferences.Prefs.settings.value("PEP8/HangClosing")))
+        self.docTypeComboBox.setCurrentIndex(self.docTypeComboBox.findData(
+            Preferences.Prefs.settings.value("PEP8/DocstringType", "pep257")))
+    
+    @pyqtSlot()
+    def on_storeDefaultButton_clicked(self):
+        """
+        Private slot to store the current configuration values as
+        default values.
+        """
+        Preferences.Prefs.settings.setValue("PEP8/ExcludeFilePatterns",
+            self.excludeFilesEdit.text())
+        Preferences.Prefs.settings.setValue("PEP8/ExcludeMessages",
+            self.excludeMessagesEdit.text())
+        Preferences.Prefs.settings.setValue("PEP8/IncludeMessages",
+            self.includeMessagesEdit.text())
+        Preferences.Prefs.settings.setValue("PEP8/RepeatMessages",
+            self.repeatCheckBox.isChecked())
+        Preferences.Prefs.settings.setValue("PEP8/FixCodes",
+            self.fixIssuesEdit.text())
+        Preferences.Prefs.settings.setValue("PEP8/NoFixCodes",
+            self.noFixIssuesEdit.text())
+        Preferences.Prefs.settings.setValue("PEP8/FixIssues",
+            self.fixIssuesCheckBox.isChecked())
+        Preferences.Prefs.settings.setValue("PEP8/MaxLineLength",
+            self.lineLengthSpinBox.value())
+        Preferences.Prefs.settings.setValue("PEP8/HangClosing",
+            self.hangClosingCheckBox.isChecked())
+        Preferences.Prefs.settings.setValue("PEP8/DocstringType",
+            self.docTypeComboBox.itemData(
+                self.docTypeComboBox.currentIndex()))
+    
+    @pyqtSlot()
+    def on_resetDefaultButton_clicked(self):
+        """
+        Private slot to reset the configuration values to their default values.
+        """
+        Preferences.Prefs.settings.setValue("PEP8/ExcludeFilePatterns", "")
+        Preferences.Prefs.settings.setValue("PEP8/ExcludeMessages",
+            pep8.DEFAULT_IGNORE)
+        Preferences.Prefs.settings.setValue("PEP8/IncludeMessages", "")
+        Preferences.Prefs.settings.setValue("PEP8/RepeatMessages", False)
+        Preferences.Prefs.settings.setValue("PEP8/FixCodes", "")
+        Preferences.Prefs.settings.setValue("PEP8/NoFixCodes", "E501")
+        Preferences.Prefs.settings.setValue("PEP8/FixIssues", False)
+        Preferences.Prefs.settings.setValue("PEP8/MaxLineLength",
+            pep8.MAX_LINE_LENGTH)
+        Preferences.Prefs.settings.setValue("PEP8/HangClosing", False)
+        Preferences.Prefs.settings.setValue("PEP8/DocstringType", "pep257")
+    
+    @pyqtSlot(QAbstractButton)
+    def on_buttonBox_clicked(self, button):
+        """
+        Private slot called by a button of the button box clicked.
+        
+        @param button button that was clicked (QAbstractButton)
+        """
+        if button == self.buttonBox.button(QDialogButtonBox.Close):
+            self.close()
+        elif button == self.buttonBox.button(QDialogButtonBox.Cancel):
+            self.__finish()
+        elif button == self.showButton:
+            self.on_showButton_clicked()
+        elif button == self.statisticsButton:
+            self.on_statisticsButton_clicked()
+    
+    def __clearErrors(self):
+        """
+        Private method to clear all warning markers of open editors.
+        """
+        vm = e5App().getObject("ViewManager")
+        openFiles = vm.getOpenFilenames()
+        for file in openFiles:
+            editor = vm.getOpenEditor(file)
+            editor.clearFlakesWarnings()
+    
+    @pyqtSlot()
+    def on_fixButton_clicked(self):
+        """
+        Private slot to fix selected issues.
+        """
+        from .CodeStyleFixer import CodeStyleFixer
+        
+        # build a dictionary of issues to fix
+        fixableItems = self.__getSelectedFixableItems()
+        fixesDict = {}      # dictionary of lists of tuples containing
+                            # the issue and the item
+        for itm in fixableItems:
+            filename = itm.data(0, self.filenameRole)
+            if filename not in fixesDict:
+                fixesDict[filename] = []
+            fixesDict[filename].append((
+                (itm.data(0, self.lineRole),
+                 itm.data(0, self.positionRole),
+                 "{0} {1}".format(itm.data(0, self.codeRole), 
+                                  itm.data(0, self.messageRole))),
+                itm
+            ))
+        
+        # extract the configuration values
+        fixCodes = self.fixIssuesEdit.text()
+        noFixCodes = self.noFixIssuesEdit.text()
+        maxLineLength = self.lineLengthSpinBox.value()
+        
+        # now go through all the files
+        if fixesDict:
+            self.checkProgress.setMaximum(len(fixesDict))
+            progress = 0
+            for file in fixesDict:
+                self.checkProgress.setValue(progress)
+                QApplication.processEvents()
+                
+                try:
+                    source, encoding = Utilities.readEncodedFile(file)
+                    source = source.splitlines(True)
+                except (UnicodeError, IOError) as msg:
+                    # skip silently because that should not happen
+                    progress += 1
+                    continue
+                
+                deferredFixes = {}
+                fixer = CodeStyleFixer(self.__project, file, source,
+                                  fixCodes, noFixCodes, maxLineLength,
+                                  True)  # always fix in place
+                errors = fixesDict[file]
+                errors.sort(key=lambda a: a[0][0])
+                for error in errors:
+                    (lineno, position, text), itm = error
+                    if lineno > len(source):
+                        lineno = len(source)
+                    fixed, msg, id_ = fixer.fixIssue(lineno, position, text)
+                    if fixed == 1:
+                        text = "\n" + self.trUtf8("Fix: {0}").format(msg)
+                        self.__modifyFixedResultItem(itm, text, True)
+                    elif fixed == 0:
+                        self.__modifyFixedResultItem(itm, "", False)
+                    else:
+                        # remember item for the deferred fix
+                        deferredFixes[id_] = itm
+                deferredResults = fixer.finalize()
+                for id_ in deferredResults:
+                    fixed, msg = deferredResults[id_]
+                    itm = deferredFixes[id_]
+                    if fixed == 1:
+                        text = "\n" + self.trUtf8("Fix: {0}").format(msg)
+                        self.__modifyFixedResultItem(itm, text, True)
+                    else:
+                        self.__modifyFixedResultItem(itm, "", False)
+                fixer.saveFile(encoding)
+                
+                self.__updateFixerStatistics(fixer)
+                progress += 1
+            
+            self.checkProgress.setValue(progress)
+            QApplication.processEvents()
+
+    def __getSelectedFixableItems(self):
+        """
+        Private method to extract all selected items for fixable issues.
+        
+        @return selected items for fixable issues (list of QTreeWidgetItem)
+        """
+        fixableItems = []
+        for itm in self.resultList.selectedItems():
+            if itm.childCount() > 0:
+                for index in range(itm.childCount()):
+                    citm = itm.child(index)
+                    if self.__itemFixable(citm) and not citm in fixableItems:
+                        fixableItems.append(citm)
+            elif self.__itemFixable(itm) and not itm in fixableItems:
+                fixableItems.append(itm)
+        
+        return fixableItems
+    
+    def __itemFixable(self, itm):
+        """
+        Private method to check, if an item has a fixable issue.
+        
+        @param itm item to be checked (QTreeWidgetItem)
+        @return flag indicating a fixable issue (boolean)
+        """
+        return itm.data(0, self.fixableRole)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCheckerDialog.ui	Fri Oct 04 14:26:08 2013 +0200
@@ -0,0 +1,510 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>CodeStyleCheckerDialog</class>
+ <widget class="QDialog" name="CodeStyleCheckerDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>650</width>
+    <height>700</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Code Style Check Result</string>
+  </property>
+  <property name="whatsThis">
+   <string>&lt;b&gt;Code Style Check Results&lt;/b&gt;
+&lt;p&gt;This dialog shows the results of the code style check. Double clicking an
+entry will open an editor window and position the cursor at the respective line and position.&lt;/p&gt;</string>
+  </property>
+  <property name="sizeGripEnabled">
+   <bool>true</bool>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout_2">
+   <item>
+    <widget class="QFrame" name="filterFrame">
+     <property name="frameShape">
+      <enum>QFrame::NoFrame</enum>
+     </property>
+     <layout class="QGridLayout" name="gridLayout">
+      <property name="margin">
+       <number>0</number>
+      </property>
+      <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="0" column="3" rowspan="9">
+       <widget class="Line" name="line">
+        <property name="lineWidth">
+         <number>2</number>
+        </property>
+        <property name="orientation">
+         <enum>Qt::Vertical</enum>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="4" rowspan="9">
+       <layout class="QVBoxLayout" name="verticalLayout">
+        <item>
+         <widget class="QPushButton" name="startButton">
+          <property name="toolTip">
+           <string>Press to start the code style check run</string>
+          </property>
+          <property name="text">
+           <string>Start</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QPushButton" name="fixButton">
+          <property name="toolTip">
+           <string>Press to fix the selected issues</string>
+          </property>
+          <property name="text">
+           <string>Fix Selected</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <spacer name="verticalSpacer">
+          <property name="orientation">
+           <enum>Qt::Vertical</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>20</width>
+            <height>18</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+        <item>
+         <widget class="QPushButton" name="loadDefaultButton">
+          <property name="toolTip">
+           <string>Press to load the default values</string>
+          </property>
+          <property name="text">
+           <string>Load Defaults</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QPushButton" name="storeDefaultButton">
+          <property name="toolTip">
+           <string>Press to store the current values as defaults</string>
+          </property>
+          <property name="text">
+           <string>Store Defaults</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QPushButton" name="resetDefaultButton">
+          <property name="toolTip">
+           <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>
+        <property name="text">
+         <string>...</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>
+        <property name="text">
+         <string>...</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>
+        <property name="text">
+         <string>...</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>
+        <property name="text">
+         <string>...</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>
+          </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">
+       <layout class="QHBoxLayout" name="horizontalLayout_2">
+        <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>
+        <item>
+         <spacer name="horizontalSpacer_2">
+          <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="8" 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>
+         <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>
+     <zorder>label_2</zorder>
+     <zorder>excludeFilesEdit</zorder>
+     <zorder>line</zorder>
+     <zorder>label</zorder>
+     <zorder>excludeMessagesEdit</zorder>
+     <zorder>excludeMessagesSelectButton</zorder>
+     <zorder>label_3</zorder>
+     <zorder>includeMessagesEdit</zorder>
+     <zorder>includeMessagesSelectButton</zorder>
+     <zorder>label_4</zorder>
+     <zorder>fixIssuesEdit</zorder>
+     <zorder>fixIssuesSelectButton</zorder>
+     <zorder>label_6</zorder>
+     <zorder>noFixIssuesEdit</zorder>
+     <zorder>noFixIssuesSelectButton</zorder>
+     <zorder>label_5</zorder>
+     <zorder></zorder>
+     <zorder>label_7</zorder>
+    </widget>
+   </item>
+   <item>
+    <widget class="QTreeWidget" name="resultList">
+     <property name="whatsThis">
+      <string>&lt;b&gt;Result List&lt;/b&gt;
+&lt;p&gt;This list shows the results of the code style check. Double clicking
+an entry will open this entry in an editor window and position the cursor at
+the respective line and position.&lt;/p&gt;</string>
+     </property>
+     <property name="alternatingRowColors">
+      <bool>true</bool>
+     </property>
+     <property name="selectionMode">
+      <enum>QAbstractItemView::ExtendedSelection</enum>
+     </property>
+     <property name="sortingEnabled">
+      <bool>true</bool>
+     </property>
+     <column>
+      <property name="text">
+       <string>File/Line</string>
+      </property>
+     </column>
+     <column>
+      <property name="text">
+       <string>Code</string>
+      </property>
+     </column>
+     <column>
+      <property name="text">
+       <string>Message</string>
+      </property>
+     </column>
+    </widget>
+   </item>
+   <item>
+    <widget class="E5SqueezeLabelPath" name="checkProgressLabel">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="text">
+      <string/>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QProgressBar" name="checkProgress">
+     <property name="toolTip">
+      <string>Shows the progress of the style check check</string>
+     </property>
+     <property name="value">
+      <number>0</number>
+     </property>
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Close</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <layoutdefault spacing="6" margin="6"/>
+ <pixmapfunction>qPixmapFromMimeSource</pixmapfunction>
+ <customwidgets>
+  <customwidget>
+   <class>E5SqueezeLabelPath</class>
+   <extends>QLabel</extends>
+   <header>E5Gui/E5SqueezeLabels.h</header>
+  </customwidget>
+  <customwidget>
+   <class>E5ClearableLineEdit</class>
+   <extends>QLineEdit</extends>
+   <header>E5Gui/E5LineEdit.h</header>
+  </customwidget>
+ </customwidgets>
+ <tabstops>
+  <tabstop>startButton</tabstop>
+  <tabstop>loadDefaultButton</tabstop>
+  <tabstop>excludeFilesEdit</tabstop>
+  <tabstop>excludeMessagesEdit</tabstop>
+  <tabstop>excludeMessagesSelectButton</tabstop>
+  <tabstop>includeMessagesEdit</tabstop>
+  <tabstop>includeMessagesSelectButton</tabstop>
+  <tabstop>fixIssuesEdit</tabstop>
+  <tabstop>fixIssuesSelectButton</tabstop>
+  <tabstop>noFixIssuesEdit</tabstop>
+  <tabstop>noFixIssuesSelectButton</tabstop>
+  <tabstop>lineLengthSpinBox</tabstop>
+  <tabstop>hangClosingCheckBox</tabstop>
+  <tabstop>repeatCheckBox</tabstop>
+  <tabstop>fixIssuesCheckBox</tabstop>
+  <tabstop>storeDefaultButton</tabstop>
+  <tabstop>resultList</tabstop>
+  <tabstop>fixButton</tabstop>
+  <tabstop>resetDefaultButton</tabstop>
+  <tabstop>buttonBox</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>repeatCheckBox</sender>
+   <signal>toggled(bool)</signal>
+   <receiver>fixIssuesCheckBox</receiver>
+   <slot>setEnabled(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>121</x>
+     <y>153</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>186</x>
+     <y>160</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCodeSelectionDialog.py	Fri Oct 04 14:26:08 2013 +0200
@@ -0,0 +1,90 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2011 - 2013 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a dialog to select code style message codes.
+"""
+
+from PyQt4.QtCore import QCoreApplication
+from PyQt4.QtGui import QDialog, QTreeWidgetItem
+
+from . import pep8
+from .NamingStyleChecker import NamingStyleChecker
+from .DocStyleChecker import DocStyleChecker
+
+from .Ui_CodeStyleCodeSelectionDialog import Ui_CodeStyleCodeSelectionDialog
+
+import UI.PixmapCache
+
+
+class CodeStyleCodeSelectionDialog(QDialog, Ui_CodeStyleCodeSelectionDialog):
+    """
+    Class implementing a dialog to select code style message codes.
+    """
+    def __init__(self, codes, showFixCodes, parent=None):
+        """
+        Constructor
+        
+        @param codes comma separated list of selected codes (string)
+        @param showFixCodes flag indicating to show a list of fixable
+            issues (boolean)
+        @param parent reference to the parent widget (QWidget)
+        """
+        super().__init__(parent)
+        self.setupUi(self)
+        
+        codeList = [code.strip() for code in codes.split(",") if code.strip()]
+        
+        if showFixCodes:
+            from .CodeStyleFixer import FixableCodeStyleIssues
+            selectableCodes = FixableCodeStyleIssues
+        else:
+            selectableCodes = list(pep8.pep8_messages.keys())
+            selectableCodes.extend(NamingStyleChecker.Messages.keys())
+            selectableCodes.extend(DocStyleChecker.Messages.keys())
+        for code in sorted(selectableCodes):
+            if code in pep8.pep8_messages_sample_args:
+                message = QCoreApplication.translate(
+                    "pep8", pep8.pep8_messages[code]).format(
+                    *pep8.pep8_messages_sample_args[code])
+            elif code in pep8.pep8_messages:
+                message = QCoreApplication.translate(
+                    "pep8", pep8.pep8_messages[code])
+            elif code in NamingStyleChecker.Messages:
+                message = QCoreApplication.translate(
+                    "NamingStyleChecker",
+                    NamingStyleChecker.Messages[code])
+            elif code in DocStyleChecker.Messages:
+                message = QCoreApplication.translate(
+                    "DocStyleChecker", DocStyleChecker.Messages[code])
+            else:
+                continue
+            itm = QTreeWidgetItem(self.codeTable, [code, message])
+            if code.startswith("W"):
+                itm.setIcon(0, UI.PixmapCache.getIcon("warning.png"))
+            elif code.startswith("E"):
+                itm.setIcon(0, UI.PixmapCache.getIcon("syntaxError.png"))
+            elif code.startswith("N"):
+                itm.setIcon(0, UI.PixmapCache.getIcon("namingError.png"))
+            elif code.startswith("D"):
+                itm.setIcon(0, UI.PixmapCache.getIcon("docstringError.png"))
+            if code in codeList:
+                itm.setSelected(True)
+                codeList.remove(code)
+        
+        self.__extraCodes = codeList[:]
+    
+    def getSelectedCodes(self):
+        """
+        Public method to get a comma separated list of codes selected.
+        
+        @return comma separated list of selected codes (string)
+        """
+        selectedCodes = []
+        
+        for itm in self.codeTable.selectedItems():
+            selectedCodes.append(itm.text(0))
+        
+        return ", ".join(self.__extraCodes + selectedCodes)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCodeSelectionDialog.ui	Fri Oct 04 14:26:08 2013 +0200
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>CodeStyleCodeSelectionDialog</class>
+ <widget class="QDialog" name="CodeStyleCodeSelectionDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>450</width>
+    <height>350</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Code Style Message Codes</string>
+  </property>
+  <property name="sizeGripEnabled">
+   <bool>true</bool>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QLabel" name="label">
+     <property name="text">
+      <string>Select the message codes from the list:</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QTreeWidget" name="codeTable">
+     <property name="toolTip">
+      <string>Select the message codes from this table</string>
+     </property>
+     <property name="editTriggers">
+      <set>QAbstractItemView::NoEditTriggers</set>
+     </property>
+     <property name="alternatingRowColors">
+      <bool>true</bool>
+     </property>
+     <property name="selectionMode">
+      <enum>QAbstractItemView::ExtendedSelection</enum>
+     </property>
+     <property name="selectionBehavior">
+      <enum>QAbstractItemView::SelectRows</enum>
+     </property>
+     <property name="rootIsDecorated">
+      <bool>false</bool>
+     </property>
+     <property name="allColumnsShowFocus">
+      <bool>true</bool>
+     </property>
+     <property name="wordWrap">
+      <bool>true</bool>
+     </property>
+     <column>
+      <property name="text">
+       <string>Code</string>
+      </property>
+     </column>
+     <column>
+      <property name="text">
+       <string>Message</string>
+      </property>
+     </column>
+    </widget>
+   </item>
+   <item>
+    <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>
+ <tabstops>
+  <tabstop>codeTable</tabstop>
+  <tabstop>buttonBox</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>CodeStyleCodeSelectionDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>227</x>
+     <y>279</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>CodeStyleCodeSelectionDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>295</x>
+     <y>285</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleFixer.py	Fri Oct 04 14:26:08 2013 +0200
@@ -0,0 +1,2713 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2011 - 2013 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a class to fix certain code style issues.
+"""
+
+import os
+import re
+import tokenize
+import io
+
+from PyQt4.QtCore import QObject
+
+from E5Gui import E5MessageBox
+
+from . import pep8
+
+import Utilities
+
+FixableCodeStyleIssues = [
+    "D111", "D112", "D113", "D121", "D131", "D141",
+    "D142", "D143", "D144", "D145",
+    "D221", "D222", "D231", "D242", "D243", "D244",
+    "D245", "D246", "D247",
+    "E101", "E111", "E121", "E122", "E123", "E124",
+    "E125", "E126", "E127", "E128", "E133", "E201",
+    "E202", "E203", "E211", "E221", "E222", "E223",
+    "E224", "E225", "E226", "E227", "E228", "E231",
+    "E241", "E242", "E251", "E261", "E262", "E271",
+    "E272", "E273", "E274", "E301", "E302", "E303",
+    "E304", "E401", "E501", "E502", "E701", "E702",
+    "E703", "E711", "E712",
+    "N804", "N805", "N806",
+    "W191", "W291", "W292", "W293", "W391", "W603",
+]
+
+
+class CodeStyleFixer(QObject):
+    """
+    Class implementing a fixer for certain code style issues.
+    """
+    def __init__(self, project, filename, sourceLines, fixCodes, noFixCodes,
+                 maxLineLength, inPlace):
+        """
+        Constructor
+        
+        @param project  reference to the project object (Project)
+        @param filename name of the file to be fixed (string)
+        @param sourceLines list of source lines including eol marker
+            (list of string)
+        @param fixCodes list of codes to be fixed as a comma separated
+            string (string)
+        @param noFixCodes list of codes not to be fixed as a comma
+            separated string (string)
+        @param maxLineLength maximum allowed line length (integer)
+        @param inPlace flag indicating to modify the file in place (boolean)
+        """
+        super().__init__()
+        
+        self.__project = project
+        self.__filename = filename
+        self.__origName = ""
+        self.__source = sourceLines[:]  # save a copy
+        self.__fixCodes = [c.strip() for c in fixCodes.split(",") if c.strip()]
+        self.__noFixCodes = [
+            c.strip() for c in noFixCodes.split(",") if c.strip()]
+        self.__maxLineLength = maxLineLength
+        self.fixed = 0
+        
+        self.__reindenter = None
+        self.__eol = ""
+        self.__indentWord = self.__getIndentWord()
+        
+        if not inPlace:
+            self.__origName = self.__filename
+            self.__filename = os.path.join(
+                os.path.dirname(self.__filename),
+                "fixed_" + os.path.basename(self.__filename))
+        
+        self.__fixes = {
+            "D111": self.__fixD111,
+            "D112": self.__fixD112,
+            "D113": self.__fixD112,
+            "D121": self.__fixD121,
+            "D131": self.__fixD131,
+            "D141": self.__fixD141,
+            "D142": self.__fixD142,
+            "D143": self.__fixD143,
+            "D144": self.__fixD144,
+            "D145": self.__fixD145,
+            "D221": self.__fixD221,
+            "D222": self.__fixD221,
+            "D231": self.__fixD131,
+            "D242": self.__fixD242,
+            "D243": self.__fixD243,
+            "D244": self.__fixD242,
+            "D245": self.__fixD243,
+            "D246": self.__fixD144,
+            "D247": self.__fixD247,
+            "E101": self.__fixE101,
+            "E111": self.__fixE101,
+            "E121": self.__fixE121,
+            "E122": self.__fixE122,
+            "E123": self.__fixE123,
+            "E124": self.__fixE121,
+            "E125": self.__fixE125,
+            "E126": self.__fixE126,
+            "E127": self.__fixE127,
+            "E128": self.__fixE127,
+            "E133": self.__fixE126,
+            "E201": self.__fixE201,
+            "E202": self.__fixE201,
+            "E203": self.__fixE201,
+            "E211": self.__fixE201,
+            "E221": self.__fixE221,
+            "E222": self.__fixE221,
+            "E223": self.__fixE221,
+            "E224": self.__fixE221,
+            "E225": self.__fixE221,
+            "E226": self.__fixE221,
+            "E227": self.__fixE221,
+            "E228": self.__fixE221,
+            "E231": self.__fixE231,
+            "E241": self.__fixE221,
+            "E242": self.__fixE221,
+            "E251": self.__fixE251,
+            "E261": self.__fixE261,
+            "E262": self.__fixE261,
+            "E271": self.__fixE221,
+            "E272": self.__fixE221,
+            "E273": self.__fixE221,
+            "E274": self.__fixE221,
+            "E301": self.__fixE301,
+            "E302": self.__fixE302,
+            "E303": self.__fixE303,
+            "E304": self.__fixE304,
+            "E401": self.__fixE401,
+            "E501": self.__fixE501,
+            "E502": self.__fixE502,
+            "E701": self.__fixE701,
+            "E702": self.__fixE702,
+            "E703": self.__fixE702,
+            "E711": self.__fixE711,
+            "E712": self.__fixE711,
+            "N804": self.__fixN804,
+            "N805": self.__fixN804,
+            "N806": self.__fixN806,
+            "W191": self.__fixE101,
+            "W291": self.__fixW291,
+            "W292": self.__fixW292,
+            "W293": self.__fixW291,
+            "W391": self.__fixW391,
+            "W603": self.__fixW603,
+        }
+        self.__modified = False
+        self.__stackLogical = []    # these need to be fixed before the file
+                                    # is saved but after all other inline
+                                    # fixes. These work with logical lines.
+        self.__stack = []           # these need to be fixed before the file
+                                    # is saved but after all inline fixes
+        
+        self.__multiLineNumbers = None
+        self.__docLineNumbers = None
+        
+        self.__lastID = 0
+    
+    def saveFile(self, encoding):
+        """
+        Public method to save the modified file.
+        
+        @param encoding encoding of the source file (string)
+        @return flag indicating success (boolean)
+        """
+        if not self.__modified:
+            # no need to write
+            return True
+        
+        txt = "".join(self.__source)
+        try:
+            Utilities.writeEncodedFile(self.__filename, txt, encoding)
+        except (IOError, Utilities.CodingError, UnicodeError) as err:
+            E5MessageBox.critical(
+                self,
+                self.trUtf8("Fix Code Style Issues"),
+                self.trUtf8(
+                    """<p>Could not save the file <b>{0}</b>."""
+                    """ Skipping it.</p><p>Reason: {1}</p>""")
+                .format(self.__filename, str(err))
+            )
+            return False
+        
+        return True
+    
+    def __codeMatch(self, code):
+        """
+        Private method to check, if the code should be fixed.
+        
+        @param code to check (string)
+        @return flag indicating it should be fixed (boolean)
+        """
+        def mutualStartswith(a, b):
+            """
+            Local helper method to compare the beginnings of two strings
+            against each other.
+            
+            @return flag indicating that one string starts with the other
+                (boolean)
+            """
+            return b.startswith(a) or a.startswith(b)
+        
+        if self.__noFixCodes:
+            for noFixCode in [c.strip() for c in self.__noFixCodes]:
+                if mutualStartswith(code.lower(), noFixCode.lower()):
+                    return False
+
+        if self.__fixCodes:
+            for fixCode in [c.strip() for c in self.__fixCodes]:
+                if mutualStartswith(code.lower(), fixCode.lower()):
+                    return True
+            return False
+
+        return True
+    
+    def fixIssue(self, line, pos, message):
+        """
+        Public method to fix the fixable issues.
+        
+        @param line line number of issue (integer)
+        @param pos character position of issue (integer)
+        @param message message text (string)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        code = message.split(None, 1)[0].strip()
+        
+        if line <= len(self.__source) and \
+           self.__codeMatch(code) and \
+           code in self.__fixes:
+            res = self.__fixes[code](code, line, pos)
+            if res[0] == 1:
+                self.__modified = True
+                self.fixed += 1
+        else:
+            res = (0, "", 0)
+        
+        return res
+    
+    def finalize(self):
+        """
+        Public method to apply all deferred fixes.
+        
+        @return dictionary containing the fix results
+        """
+        results = {}
+        
+        # step 1: do fixes operating on logical lines first
+        for id_, code, line, pos in self.__stackLogical:
+            res, msg, _ = self.__fixes[code](code, line, pos, apply=True)
+            if res == 1:
+                self.__modified = True
+                self.fixed += 1
+            results[id_] = (res, msg)
+        
+        # step 2: do fixes that change the number of lines
+        for id_, code, line, pos in reversed(self.__stack):
+            res, msg, _ = self.__fixes[code](code, line, pos, apply=True)
+            if res == 1:
+                self.__modified = True
+                self.fixed += 1
+            results[id_] = (res, msg)
+        
+        return results
+    
+    def __getID(self):
+        """
+        Private method to get the ID for a deferred fix.
+        
+        @return ID for a deferred fix (integer)
+        """
+        self.__lastID += 1
+        return self.__lastID
+    
+    def __getEol(self):
+        """
+        Private method to get the applicable eol string.
+        
+        @return eol string (string)
+        """
+        if not self.__eol:
+            if self.__origName:
+                fn = self.__origName
+            else:
+                fn = self.__filename
+            
+            if self.__project.isOpen() and self.__project.isProjectFile(fn):
+                self.__eol = self.__project.getEolString()
+            else:
+                self.__eol = Utilities.linesep()
+        return self.__eol
+    
+    def __findLogical(self):
+        """
+        Private method to extract the index of all the starts and ends of
+        lines.
+        
+        @return tuple containing two lists of integer with start and end tuples
+            of lines
+        """
+        logical_start = []
+        logical_end = []
+        last_newline = True
+        sio = io.StringIO("".join(self.__source))
+        parens = 0
+        for t in tokenize.generate_tokens(sio.readline):
+            if t[0] in [tokenize.COMMENT, tokenize.DEDENT,
+                        tokenize.INDENT, tokenize.NL,
+                        tokenize.ENDMARKER]:
+                continue
+            if not parens and t[0] in [tokenize.NEWLINE, tokenize.SEMI]:
+                last_newline = True
+                logical_end.append((t[3][0] - 1, t[2][1]))
+                continue
+            if last_newline and not parens:
+                logical_start.append((t[2][0] - 1, t[2][1]))
+                last_newline = False
+            if t[0] == tokenize.OP:
+                if t[1] in '([{':
+                    parens += 1
+                elif t[1] in '}])':
+                    parens -= 1
+        return logical_start, logical_end
+    
+    def __getLogical(self, line, pos):
+        """
+        Private method to get the logical line corresponding to the given
+        position.
+        
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @return tuple of a tuple of two integers giving the start of the
+            logical line, another tuple of two integers giving the end
+            of the logical line and a list of strings with the original
+            source lines
+        """
+        try:
+            (logical_start, logical_end) = self.__findLogical()
+        except (SyntaxError, tokenize.TokenError):
+            return None
+
+        line = line - 1
+        ls = None
+        le = None
+        for i in range(0, len(logical_start)):
+            x = logical_end[i]
+            if x[0] > line or (x[0] == line and x[1] > pos):
+                le = x
+                ls = logical_start[i]
+                break
+        if ls is None:
+            return None
+        
+        original = self.__source[ls[0]:le[0] + 1]
+        return ls, le, original
+    
+    def __getIndentWord(self):
+        """
+        Private method to determine the indentation type.
+        
+        @return string to be used for an indentation (string)
+        """
+        sio = io.StringIO("".join(self.__source))
+        indentWord = "    "     # default in case of failure
+        try:
+            for token in tokenize.generate_tokens(sio.readline):
+                if token[0] == tokenize.INDENT:
+                    indentWord = token[1]
+                    break
+        except (SyntaxError, tokenize.TokenError):
+            pass
+        return indentWord
+    
+    def __getIndent(self, line):
+        """
+        Private method to get the indentation string.
+        
+        @param line line to determine the indentation string from (string)
+        @return indentation string (string)
+        """
+        return line.replace(line.lstrip(), "")
+    
+    def __multilineStringLines(self):
+        """
+        Private method to determine the line numbers that are within multi line
+        strings and these which are part of a documentation string.
+        
+        @return tuple of a set of line numbers belonging to a multi line
+            string and a set of line numbers belonging to a multi line
+            documentation string (tuple of two set of integer)
+        """
+        if self.__multiLineNumbers is None:
+            source = "".join(self.__source)
+            sio = io.StringIO(source)
+            self.__multiLineNumbers = set()
+            self.__docLineNumbers = set()
+            previousTokenType = ''
+            try:
+                for t in tokenize.generate_tokens(sio.readline):
+                    tokenType = t[0]
+                    startRow = t[2][0]
+                    endRow = t[3][0]
+
+                    if (tokenType == tokenize.STRING and startRow != endRow):
+                        if previousTokenType != tokenize.INDENT:
+                            self.__multiLineNumbers |= set(
+                                range(startRow, 1 + endRow))
+                        else:
+                            self.__docLineNumbers |= set(
+                                range(startRow, 1 + endRow))
+
+                    previousTokenType = tokenType
+            except (SyntaxError, tokenize.TokenError):
+                pass
+        
+        return self.__multiLineNumbers, self.__docLineNumbers
+    
+    def __fixReindent(self, line, pos, logical):
+        """
+        Private method to fix a badly indented line.
+
+        This is done by adding or removing from its initial indent only.
+        
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @param logical logical line structure
+        @return flag indicating a change was done (boolean)
+        """
+        assert logical
+        ls, _, original = logical
+
+        rewrapper = IndentationWrapper(original)
+        valid_indents = rewrapper.pep8Expected()
+        if not rewrapper.rel_indent:
+            return False
+        
+        if line > ls[0]:
+            # got a valid continuation line number
+            row = line - ls[0] - 1
+            # always pick the first option for this
+            valid = valid_indents[row]
+            got = rewrapper.rel_indent[row]
+        else:
+            return False
+        
+        line1 = ls[0] + row
+        # always pick the expected indent, for now.
+        indent_to = valid[0]
+
+        if got != indent_to:
+            orig_line = self.__source[line1]
+            new_line = ' ' * (indent_to) + orig_line.lstrip()
+            if new_line == orig_line:
+                return False
+            else:
+                self.__source[line1] = new_line
+                return True
+        else:
+            return False
+    
+    def __fixWhitespace(self, line, offset, replacement):
+        """
+        Private method to correct whitespace at the given offset.
+        
+        @param line line to be corrected (string)
+        @param offset offset within line (integer)
+        @param replacement replacement string (string)
+        @return corrected line
+        """
+        left = line[:offset].rstrip(" \t")
+        right = line[offset:].lstrip(" \t")
+        if right.startswith("#"):
+            return line
+        else:
+            return left + replacement + right
+    
+    def __fixD111(self, code, line, pos):
+        """
+        Private method to fix docstring enclosed in wrong quotes.
+       
+        Codes: D111
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        line = line - 1
+        left, right = self.__source[line].split("'''", 1)
+        self.__source[line] = left + '"""' + right
+        while line < len(self.__source):
+            if self.__source[line].rstrip().endswith("'''"):
+                left, right = self.__source[line].rsplit("'''", 1)
+                self.__source[line] = left + '"""' + right
+                break
+            line += 1
+        
+        return (
+            1,
+            self.trUtf8(
+                "Triple single quotes converted to triple double quotes."),
+            0)
+    
+    def __fixD112(self, code, line, pos):
+        """
+        Private method to fix docstring 'r' or 'u' in leading quotes.
+        
+        Codes: D112, D113
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        line = line - 1
+        if code == "D112":
+            insertChar = "r"
+        elif code == "D113":
+            insertChar = "u"
+        else:
+            return (0, "", 0)
+        
+        newText = self.__getIndent(self.__source[line]) + \
+            insertChar + self.__source[line].lstrip()
+        self.__source[line] = newText
+        return (
+            1,
+            self.trUtf8('Introductory quotes corrected to be {0}"""')
+                .format(insertChar),
+            0)
+    
+    def __fixD121(self, code, line, pos, apply=False):
+        """
+        Private method to fix a single line docstring on multiple lines.
+       
+        Codes: D121
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @keyparam apply flag indicating, that the fix should be applied
+            (boolean)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        if apply:
+            line = line - 1
+            if not self.__source[line].lstrip().startswith(
+                    ('"""', 'r"""', 'u"""')):
+                # only correctly formatted docstrings will be fixed
+                return (0, "", 0)
+            
+            docstring = self.__source[line].rstrip() + \
+                self.__source[line + 1].strip()
+            if docstring.endswith('"""'):
+                docstring += self.__getEol()
+            else:
+                docstring += self.__source[line + 2].lstrip()
+                self.__source[line + 2] = ""
+            
+            self.__source[line] = docstring
+            self.__source[line + 1] = ""
+            return (
+                1,
+                self.trUtf8("Single line docstring put on one line."),
+                0)
+        else:
+            id = self.__getID()
+            self.__stack.append((id, code, line, pos))
+            return (-1, "", id)
+    
+    def __fixD131(self, code, line, pos):
+        """
+        Private method to fix a docstring summary not ending with a
+        period.
+       
+        Codes: D131
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        line = line - 1
+        newText = ""
+        if self.__source[line].rstrip().endswith(('"""', "'''")) and \
+           self.__source[line].lstrip().startswith(('"""', 'r"""', 'u"""')):
+            # it is a one-liner
+            newText = self.__source[line].rstrip()[:-3].rstrip() + "." + \
+                self.__source[line].rstrip()[-3:] + self.__getEol()
+        else:
+            if line < len(self.__source) - 1 and \
+                (not self.__source[line + 1].strip() or
+                 self.__source[line + 1].lstrip().startswith("@") or
+                 (self.__source[line + 1].strip() in ('"""', "'''") and
+                  not self.__source[line].lstrip().startswith("@"))):
+                newText = self.__source[line].rstrip() + "." + self.__getEol()
+        
+        if newText:
+            self.__source[line] = newText
+            return (1, self.trUtf8("Period added to summary line."), 0)
+        else:
+            return (0, "", 0)
+    
+    def __fixD141(self, code, line, pos, apply=False):
+        """
+        Private method to fix a function/method docstring preceded by a
+        blank line.
+       
+        Codes: D141
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @keyparam apply flag indicating, that the fix should be applied
+            (boolean)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        if apply:
+            line = line - 1
+            self.__source[line - 1] = ""
+            return (
+                1,
+                self.trUtf8(
+                    "Blank line before function/method docstring removed."),
+                0)
+        else:
+            id = self.__getID()
+            self.__stack.append((id, code, line, pos))
+            return (-1, "", id)
+    
+    def __fixD142(self, code, line, pos, apply=False):
+        """
+        Private method to fix a class docstring not preceded by a
+        blank line.
+       
+        Codes: D142
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @keyparam apply flag indicating, that the fix should be applied
+            (boolean)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        if apply:
+            line = line - 1
+            self.__source[line] = self.__getEol() + self.__source[line]
+            return (
+                1,
+                self.trUtf8("Blank line inserted before class docstring."),
+                0)
+        else:
+            id = self.__getID()
+            self.__stack.append((id, code, line, pos))
+            return (-1, "", id)
+    
+    def __fixD143(self, code, line, pos, apply=False):
+        """
+        Private method to fix a class docstring not followed by a
+        blank line.
+       
+        Codes: D143
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @keyparam apply flag indicating, that the fix should be applied
+            (boolean)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        if apply:
+            line = line - 1
+            self.__source[line] += self.__getEol()
+            return (
+                1,
+                self.trUtf8("Blank line inserted after class docstring."),
+                0)
+        else:
+            id = self.__getID()
+            self.__stack.append((id, code, line, pos))
+            return (-1, "", id)
+    
+    def __fixD144(self, code, line, pos, apply=False):
+        """
+        Private method to fix a docstring summary not followed by a
+        blank line.
+       
+        Codes: D144
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @keyparam apply flag indicating, that the fix should be applied
+            (boolean)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        if apply:
+            line = line - 1
+            if not self.__source[line].rstrip().endswith("."):
+                # only correct summary lines can be fixed here
+                return (0, "", 0)
+            
+            self.__source[line] += self.__getEol()
+            return (
+                1,
+                self.trUtf8("Blank line inserted after docstring summary."),
+                0)
+        else:
+            id = self.__getID()
+            self.__stack.append((id, code, line, pos))
+            return (-1, "", id)
+    
+    def __fixD145(self, code, line, pos, apply=False):
+        """
+        Private method to fix the last paragraph of a multi-line docstring
+        not followed by a blank line.
+       
+        Codes: D143
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @keyparam apply flag indicating, that the fix should be applied
+            (boolean)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        if apply:
+            line = line - 1
+            self.__source[line] = self.__getEol() + self.__source[line]
+            return (
+                1,
+                self.trUtf8("Blank line inserted after last paragraph"
+                            " of docstring."),
+                0)
+        else:
+            id = self.__getID()
+            self.__stack.append((id, code, line, pos))
+            return (-1, "", id)
+    
+    def __fixD221(self, code, line, pos, apply=False):
+        """
+        Private method to fix leading and trailing quotes of docstring
+        not on separate lines.
+       
+        Codes: D221, D222
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @keyparam apply flag indicating, that the fix should be applied
+            (boolean)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        if apply:
+            line = line - 1
+            indent = self.__getIndent(self.__source[line])
+            source = self.__source[line].strip()
+            if code == "D221":
+                # leading
+                if source.startswith(("r", "u")):
+                    first, second = source[:4], source[4:].strip()
+                else:
+                    first, second = source[:3], source[3:].strip()
+            else:
+                # trailing
+                first, second = source[:-3].strip(), source[-3:]
+            newText = indent + first + self.__getEol() + \
+                indent + second + self.__getEol()
+            self.__source[line] = newText
+            if code == "D221":
+                msg = self.trUtf8("Leading quotes put on separate line.")
+            else:
+                msg = self.trUtf8("Trailing quotes put on separate line.")
+            return (1, msg, 0)
+        else:
+            id = self.__getID()
+            self.__stack.append((id, code, line, pos))
+            return (-1, "", id)
+    
+    def __fixD242(self, code, line, pos, apply=False):
+        """
+        Private method to fix a class or function/method docstring preceded
+        by a blank line.
+       
+        Codes: D242, D244
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @keyparam apply flag indicating, that the fix should be applied
+            (boolean)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        if apply:
+            line = line - 1
+            self.__source[line - 1] = ""
+            if code == "D242":
+                msg = self.trUtf8("Blank line before class docstring removed.")
+            else:
+                msg = self.trUtf8(
+                    "Blank line before function/method docstring removed.")
+            return (1, msg, 0)
+        else:
+            id = self.__getID()
+            self.__stack.append((id, code, line, pos))
+            return (-1, "", id)
+    
+    def __fixD243(self, code, line, pos, apply=False):
+        """
+        Private method to fix a class or function/method docstring followed
+        by a blank line.
+       
+        Codes: D243, D245
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @keyparam apply flag indicating, that the fix should be applied
+            (boolean)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        if apply:
+            line = line - 1
+            self.__source[line + 1] = ""
+            if code == "D243":
+                msg = self.trUtf8("Blank line after class docstring removed.")
+            else:
+                msg = self.trUtf8(
+                    "Blank line after function/method docstring removed.")
+            return (1, msg, 0)
+        else:
+            id = self.__getID()
+            self.__stack.append((id, code, line, pos))
+            return (-1, "", id)
+    
+    def __fixD247(self, code, line, pos, apply=False):
+        """
+        Private method to fix a last paragraph of a docstring followed
+        by a blank line.
+       
+        Codes: D247
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @keyparam apply flag indicating, that the fix should be applied
+            (boolean)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        if apply:
+            line = line - 1
+            self.__source[line - 1] = ""
+            return (
+                1,
+                self.trUtf8("Blank line after last paragraph removed."),
+                0)
+        else:
+            id = self.__getID()
+            self.__stack.append((id, code, line, pos))
+            return (-1, "", id)
+    
+    def __fixE101(self, code, line, pos):
+        """
+        Private method to fix obsolete tab usage and indentation errors.
+        
+        Codes: E101, E111, W191
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        if self.__reindenter is None:
+            self.__reindenter = Reindenter(self.__source)
+            self.__reindenter.run()
+        fixedLine = self.__reindenter.fixedLine(line - 1)
+        if fixedLine is not None and fixedLine != self.__source[line - 1]:
+            self.__source[line - 1] = fixedLine
+            if code in ["E101", "W191"]:
+                msg = self.trUtf8("Tab converted to 4 spaces.")
+            else:
+                msg = self.trUtf8(
+                    "Indentation adjusted to be a multiple of four.")
+            return (1, msg, 0)
+        else:
+            return (0, "", 0)
+    
+    def __fixE121(self, code, line, pos, apply=False):
+        """
+        Private method to fix the indentation of continuation lines and
+        closing brackets.
+       
+        Codes: E121, E124
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @keyparam apply flag indicating, that the fix should be applied
+            (boolean)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        if apply:
+            logical = self.__getLogical(line, pos)
+            if logical:
+                # Fix by adjusting initial indent level.
+                changed = self.__fixReindent(line, pos, logical)
+                if changed:
+                    if code == "E121":
+                        msg = self.trUtf8(
+                            "Indentation of continuation line corrected.")
+                    elif code == "E124":
+                        msg = self.trUtf8(
+                            "Indentation of closing bracket corrected.")
+                    return (1, msg, 0)
+            return (0, "", 0)
+        else:
+            id = self.__getID()
+            self.__stackLogical.append((id, code, line, pos))
+            return (-1, "", id)
+    
+    def __fixE122(self, code, line, pos, apply=False):
+        """
+        Private method to fix a missing indentation of continuation lines.
+        
+        Codes: E122
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @keyparam apply flag indicating, that the fix should be applied
+            (boolean)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        if apply:
+            logical = self.__getLogical(line, pos)
+            if logical:
+                # Fix by adding an initial indent.
+                modified = self.__fixReindent(line, pos, logical)
+                if not modified:
+                    # fall back to simple method
+                    line = line - 1
+                    text = self.__source[line]
+                    indentation = self.__getIndent(text)
+                    self.__source[line] = indentation + \
+                        self.__indentWord + text.lstrip()
+                return (
+                    1,
+                    self.trUtf8(
+                        "Missing indentation of continuation line corrected."),
+                    0)
+            return (0, "", 0)
+        else:
+            id = self.__getID()
+            self.__stackLogical.append((id, code, line, pos))
+            return (-1, "", id)
+    
+    def __fixE123(self, code, line, pos, apply=False):
+        """
+        Private method to fix the indentation of a closing bracket lines.
+        
+        Codes: E123
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @keyparam apply flag indicating, that the fix should be applied
+            (boolean)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        if apply:
+            logical = self.__getLogical(line, pos)
+            if logical:
+                # Fix by deleting whitespace to the correct level.
+                logicalLines = logical[2]
+                row = line - 1
+                text = self.__source[row]
+                newText = self.__getIndent(logicalLines[0]) + text.lstrip()
+                if newText == text:
+                    # fall back to slower method
+                    changed = self.__fixReindent(line, pos, logical)
+                else:
+                    self.__source[row] = newText
+                    changed = True
+                if changed:
+                    return (1, self.trUtf8(
+                        "Closing bracket aligned to opening bracket."),
+                        0)
+            return (0, "", 0)
+        else:
+            id = self.__getID()
+            self.__stackLogical.append((id, code, line, pos))
+            return (-1, "", id)
+    
+    def __fixE125(self, code, line, pos, apply=False):
+        """
+        Private method to fix the indentation of continuation lines not
+        distinguishable from next logical line.
+       
+        Codes: E125
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @keyparam apply flag indicating, that the fix should be applied
+            (boolean)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        if apply:
+            logical = self.__getLogical(line, pos)
+            if logical:
+                # Fix by adjusting initial indent level.
+                modified = self.__fixReindent(line, pos, logical)
+                if not modified:
+                    row = line - 1
+                    text = self.__source[row]
+                    self.__source[row] = self.__getIndent(text) + \
+                        self.__indentWord + text.lstrip()
+                return (1, self.trUtf8("Indentation level changed."), 0)
+            return (0, "", 0)
+        else:
+            id = self.__getID()
+            self.__stackLogical.append((id, code, line, pos))
+            return (-1, "", id)
+    
+    def __fixE126(self, code, line, pos, apply=False):
+        """
+        Private method to fix over-indented/under-indented hanging
+        indentation.
+       
+        Codes: E126, E133
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @keyparam apply flag indicating, that the fix should be applied
+            (boolean)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        if apply:
+            logical = self.__getLogical(line, pos)
+            if logical:
+                # Fix by deleting whitespace to the left.
+                logicalLines = logical[2]
+                row = line - 1
+                text = self.__source[row]
+                newText = self.__getIndent(logicalLines[0]) + \
+                    self.__indentWord + text.lstrip()
+                if newText == text:
+                    # fall back to slower method
+                    changed = self.__fixReindent(line, pos, logical)
+                else:
+                    self.__source[row] = newText
+                    changed = True
+                if changed:
+                    return (1, self.trUtf8(
+                        "Indentation level of hanging indentation changed."),
+                        0)
+            return (0, "", 0)
+        else:
+            id = self.__getID()
+            self.__stackLogical.append((id, code, line, pos))
+            return (-1, "", id)
+    
+    def __fixE127(self, code, line, pos, apply=False):
+        """
+        Private method to fix over/under indented lines.
+       
+        Codes: E127, E128
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @keyparam apply flag indicating, that the fix should be applied
+            (boolean)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        if apply:
+            logical = self.__getLogical(line, pos)
+            if logical:
+                # Fix by inserting/deleting whitespace to the correct level.
+                logicalLines = logical[2]
+                row = line - 1
+                text = self.__source[row]
+                newText = text
+                
+                if logicalLines[0].rstrip().endswith('\\'):
+                    newText = self.__getIndent(logicalLines[0]) + \
+                        self.__indentWord + text.lstrip()
+                else:
+                    startIndex = None
+                    for symbol in '([{':
+                        if symbol in logicalLines[0]:
+                            foundIndex = logicalLines[0].find(symbol) + 1
+                            if startIndex is None:
+                                startIndex = foundIndex
+                            else:
+                                startIndex = min(startIndex, foundIndex)
+
+                    if startIndex is not None:
+                        newText = startIndex * ' ' + text.lstrip()
+                    
+                if newText == text:
+                    # fall back to slower method
+                    changed = self.__fixReindent(line, pos, logical)
+                else:
+                    self.__source[row] = newText
+                    changed = True
+                if changed:
+                    return (1, self.trUtf8("Visual indentation corrected."), 0)
+            return (0, "", 0)
+        else:
+            id = self.__getID()
+            self.__stackLogical.append((id, code, line, pos))
+            return (-1, "", id)
+    
+    def __fixE201(self, code, line, pos):
+        """
+        Private method to fix extraneous whitespace.
+       
+        Codes: E201, E202, E203, E211
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        line = line - 1
+        text = self.__source[line]
+        
+        if '"""' in text or "'''" in text or text.rstrip().endswith('\\'):
+            return (0, "", 0)
+        
+        newText = self.__fixWhitespace(text, pos, '')
+        if newText == text:
+            return (0, "", 0)
+        
+        self.__source[line] = newText
+        return (1, self.trUtf8("Extraneous whitespace removed."), 0)
+    
+    def __fixE221(self, code, line, pos):
+        """
+        Private method to fix extraneous whitespace around operator or
+        keyword.
+       
+        Codes: E221, E222, E223, E224, E225, E226, E227, E228, E241,
+               E242, E271, E272, E273, E274).
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        line = line - 1
+        text = self.__source[line]
+        
+        if '"""' in text or "'''" in text or text.rstrip().endswith('\\'):
+            return (0, "", 0)
+        
+        newText = self.__fixWhitespace(text, pos, ' ')
+        if newText == text:
+            return (0, "", 0)
+        
+        self.__source[line] = newText
+        if code in ["E225", "E226", "E227", "E228"]:
+            return (1, self.trUtf8("Missing whitespace added."), 0)
+        else:
+            return (1, self.trUtf8("Extraneous whitespace removed."), 0)
+    
+    def __fixE231(self, code, line, pos):
+        """
+        Private method to fix missing whitespace after ',;:'.
+        
+        Codes: E231
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        line = line - 1
+        pos = pos + 1
+        self.__source[line] = self.__source[line][:pos] + \
+            " " + self.__source[line][pos:]
+        return (1, self.trUtf8("Missing whitespace added."), 0)
+    
+    def __fixE251(self, code, line, pos):
+        """
+        Private method to fix extraneous whitespace around keyword and
+        default parameter equals.
+       
+        Codes: E251
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        line = line - 1
+        text = self.__source[line]
+        
+        # This is necessary since pep8 sometimes reports columns that goes
+        # past the end of the physical line. This happens in cases like,
+        # foo(bar\n=None)
+        col = min(pos, len(text) - 1)
+        if text[col].strip():
+            newText = text
+        else:
+            newText = text[:col].rstrip() + text[col:].lstrip()
+        
+        # There could be an escaped newline
+        #
+        #     def foo(a=\
+        #             1)
+        if newText.endswith(('=\\\n', '=\\\r\n', '=\\\r')):
+            self.__source[line] = newText.rstrip("\n\r \t\\")
+            self.__source[line + 1] = self.__source[line + 1].lstrip()
+        else:
+            self.__source[line] = newText
+        return (1, self.trUtf8("Extraneous whitespace removed."), 0)
+    
+    def __fixE261(self, code, line, pos):
+        """
+        Private method to fix whitespace before or after inline comment.
+        
+        Codes: E261, E262
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        line = line - 1
+        text = self.__source[line]
+        left = text[:pos].rstrip(' \t#')
+        right = text[pos:].lstrip(' \t#')
+        newText = left + ("  # " + right if right.strip() else right)
+        self.__source[line] = newText
+        return (1, self.trUtf8("Whitespace around comment sign corrected."), 0)
+    
+    def __fixE301(self, code, line, pos, apply=False):
+        """
+        Private method to fix the need for one blank line.
+       
+        Codes: E301
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @keyparam apply flag indicating, that the fix should be applied
+            (boolean)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        if apply:
+            self.__source.insert(line - 1, self.__getEol())
+            return (1, self.trUtf8("One blank line inserted."), 0)
+        else:
+            id = self.__getID()
+            self.__stack.append((id, code, line, pos))
+            return (-1, "", id)
+    
+    def __fixE302(self, code, line, pos, apply=False):
+        """
+        Private method to fix the need for two blank lines.
+       
+        Codes: E302
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @keyparam apply flag indicating, that the fix should be applied
+            (boolean)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        if apply:
+            # count blank lines
+            index = line - 1
+            blanks = 0
+            while index:
+                if self.__source[index - 1].strip() == "":
+                    blanks += 1
+                    index -= 1
+                else:
+                    break
+            delta = blanks - 2
+            
+            line -= 1
+            if delta < 0:
+                # insert blank lines (one or two)
+                while delta < 0:
+                    self.__source.insert(line, self.__getEol())
+                    delta += 1
+                changed = True
+            elif delta > 0:
+                # delete superfluous blank lines
+                while delta > 0:
+                    del self.__source[line - 1]
+                    line -= 1
+                    delta -= 1
+                changed = True
+            else:
+                changed = False
+            
+            if changed:
+                if delta < 0:
+                    msg = self.trUtf8(
+                        "%n blank line(s) inserted.", "", -delta)
+                elif delta > 0:
+                    msg = self.trUtf8(
+                        "%n superfluous lines removed", "", delta)
+                else:
+                    msg = ""
+                return (1, msg, 0)
+            return (0, "", 0)
+        else:
+            id = self.__getID()
+            self.__stack.append((id, code, line, pos))
+            return (-1, "", id)
+    
+    def __fixE303(self, code, line, pos, apply=False):
+        """
+        Private method to fix superfluous blank lines.
+       
+        Codes: E303
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @keyparam apply flag indicating, that the fix should be applied
+            (boolean)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        if apply:
+            index = line - 3
+            while index:
+                if self.__source[index].strip() == "":
+                    del self.__source[index]
+                    index -= 1
+                else:
+                    break
+            return (1, self.trUtf8("Superfluous blank lines removed."), 0)
+        else:
+            id = self.__getID()
+            self.__stack.append((id, code, line, pos))
+            return (-1, "", id)
+    
+    def __fixE304(self, code, line, pos, apply=False):
+        """
+        Private method to fix superfluous blank lines after a function
+        decorator.
+       
+        Codes: E304
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @keyparam apply flag indicating, that the fix should be applied
+            (boolean)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        if apply:
+            index = line - 2
+            while index:
+                if self.__source[index].strip() == "":
+                    del self.__source[index]
+                    index -= 1
+                else:
+                    break
+            return (1, self.trUtf8(
+                "Superfluous blank lines after function decorator removed."),
+                0)
+        else:
+            id = self.__getID()
+            self.__stack.append((id, code, line, pos))
+            return (-1, "", id)
+    
+    def __fixE401(self, code, line, pos, apply=False):
+        """
+        Private method to fix multiple imports on one line.
+       
+        Codes: E401
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @keyparam apply flag indicating, that the fix should be applied
+            (boolean)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        if apply:
+            line = line - 1
+            text = self.__source[line]
+            if not text.lstrip().startswith("import"):
+                return (0, "", 0)
+            
+            # pep8 (1.3.1) reports false positive if there is an import
+            # statement followed by a semicolon and some unrelated
+            # statement with commas in it.
+            if ';' in text:
+                return (0, "", 0)
+            
+            newText = text[:pos].rstrip("\t ,") + self.__getEol() + \
+                self.__getIndent(text) + "import " + text[pos:].lstrip("\t ,")
+            self.__source[line] = newText
+            return (1, self.trUtf8("Imports were put on separate lines."), 0)
+        else:
+            id = self.__getID()
+            self.__stack.append((id, code, line, pos))
+            return (-1, "", id)
+    
+    def __fixE501(self, code, line, pos, apply=False):
+        """
+        Private method to fix the long lines by breaking them.
+       
+        Codes: E501
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @keyparam apply flag indicating, that the fix should be applied
+            (boolean)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        if apply:
+            multilineStringLines, docStringLines = \
+                self.__multilineStringLines()
+            isDocString = line in docStringLines
+            line = line - 1
+            text = self.__source[line]
+            if line > 0:
+                prevText = self.__source[line - 1]
+            else:
+                prevText = ""
+            if line < len(self.__source) - 1:
+                nextText = self.__source[line + 1]
+            else:
+                nextText = ""
+            shortener = LineShortener(
+                text, prevText, nextText,
+                maxLength=self.__maxLineLength, eol=self.__getEol(),
+                indentWord=self.__indentWord, isDocString=isDocString)
+            changed, newText, newNextText = shortener.shorten()
+            if changed:
+                if newText != text:
+                    self.__source[line] = newText
+                if newNextText and newNextText != nextText:
+                    if newNextText == " ":
+                        newNextText = ""
+                    self.__source[line + 1] = newNextText
+                return (1, self.trUtf8("Long lines have been shortened."), 0)
+            else:
+                return (0, "", 0)
+        else:
+            id = self.__getID()
+            self.__stack.append((id, code, line, pos))
+            return (-1, "", id)
+    
+    def __fixE502(self, code, line, pos):
+        """
+        Private method to fix redundant backslash within brackets.
+       
+        Codes: E502
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        self.__source[line - 1] = \
+            self.__source[line - 1].rstrip("\n\r \t\\") + self.__getEol()
+        return (1, self.trUtf8("Redundant backslash in brackets removed."), 0)
+    
+    def __fixE701(self, code, line, pos, apply=False):
+        """
+        Private method to fix colon-separated compound statements.
+       
+        Codes: E701
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @keyparam apply flag indicating, that the fix should be applied
+            (boolean)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        if apply:
+            line = line - 1
+            text = self.__source[line]
+            pos = pos + 1
+            
+            newText = text[:pos] + self.__getEol() + self.__getIndent(text) + \
+                self.__indentWord + text[pos:].lstrip("\n\r \t\\") + \
+                self.__getEol()
+            self.__source[line] = newText
+            return (1, self.trUtf8("Compound statement corrected."), 0)
+        else:
+            id = self.__getID()
+            self.__stack.append((id, code, line, pos))
+            return (-1, "", id)
+    
+    def __fixE702(self, code, line, pos, apply=False):
+        """
+        Private method to fix semicolon-separated compound statements.
+        
+        Codes: E702, E703
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @keyparam apply flag indicating, that the fix should be applied
+            (boolean)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        if apply:
+            line = line - 1
+            text = self.__source[line]
+            
+            if text.rstrip().endswith("\\"):
+                # normalize '1; \\\n2' into '1; 2'
+                self.__source[line] = text.rstrip("\n\r \t\\")
+                self.__source[line + 1] = self.__source[line + 1].lstrip()
+            elif text.rstrip().endswith(";"):
+                self.__source[line] = text.rstrip("\n\r \t;") + self.__getEol()
+            else:
+                first = text[:pos].rstrip("\n\r \t;") + self.__getEol()
+                second = text[pos:].lstrip("\n\r \t;")
+                self.__source[line] = first + self.__getIndent(text) + second
+            return (1, self.trUtf8("Compound statement corrected."), 0)
+        else:
+            id = self.__getID()
+            self.__stack.append((id, code, line, pos))
+            return (-1, "", id)
+    
+    def __fixE711(self, code, line, pos):
+        """
+        Private method to fix comparison with None.
+       
+        Codes: E711, E712
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        line = line - 1
+        text = self.__source[line]
+        
+        rightPos = pos + 2
+        if rightPos >= len(text):
+            return (0, "", 0)
+        
+        left = text[:pos].rstrip()
+        center = text[pos:rightPos]
+        right = text[rightPos:].lstrip()
+        
+        if not right.startswith(("None", "True", "False")):
+            return (0, "", 0)
+        
+        if center.strip() == "==":
+            center = "is"
+        elif center.strip() == "!=":
+            center = "is not"
+        else:
+            return (0, "", 0)
+        
+        self.__source[line] = " ".join([left, center, right])
+        return (1, self.trUtf8("Comparison to None/True/False corrected."), 0)
+    
+    def __fixN804(self, code, line, pos, apply=False):
+        """
+        Private method to fix a wrong first argument of normal and
+        class methods.
+       
+        Codes: N804, N805
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @keyparam apply flag indicating, that the fix should be applied
+            (boolean)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        if apply:
+            line = line - 1
+            text = self.__source[line]
+            if code == "N804":
+                arg = "cls"
+            else:
+                arg = "self"
+            
+            if text.rstrip().endswith("("):
+                newText = text + self.__getIndent(text) + \
+                    self.__indentWord + arg + "," + self.__getEol()
+            else:
+                index = text.find("(") + 1
+                left = text[:index]
+                right = text[index:]
+                if right.startswith(")"):
+                    center = arg
+                else:
+                    center = arg + ", "
+                newText = left + center + right
+            self.__source[line] = newText
+            return (1, self.trUtf8("'{0}' argument added.").format(arg), 0)
+        else:
+            id = self.__getID()
+            self.__stack.append((id, code, line, pos))
+            return (-1, "", id)
+    
+    def __fixN806(self, code, line, pos, apply=False):
+        """
+        Private method to fix a wrong first argument of static methods.
+        
+        Codes: N806
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @keyparam apply flag indicating, that the fix should be applied
+            (boolean)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        if apply:
+            line = line - 1
+            text = self.__source[line]
+            index = text.find("(") + 1
+            left = text[:index]
+            right = text[index:]
+            
+            if right.startswith(("cls", "self")):
+                # cls or self are on the definition line
+                if right.startswith("cls"):
+                    right = right[3:]
+                    arg = "cls"
+                else:
+                    right = right[4:]
+                    arg = "self"
+                right = right.lstrip(", ")
+                newText = left + right
+                self.__source[line] = newText
+            else:
+                # they are on the next line
+                line = line + 1
+                text = self.__source[line]
+                indent = self.__getIndent(text)
+                right = text.lstrip()
+                if right.startswith("cls"):
+                    right = right[3:]
+                    arg = "cls"
+                else:
+                    right = right[4:]
+                    arg = "self"
+                right = right.lstrip(", ")
+                if right.startswith("):"):
+                    # merge with previous line
+                    self.__source[line - 1] = \
+                        self.__source[line - 1].rstrip() + right
+                    self.__source[line] = ""
+                else:
+                    self.__source[line] = indent + right
+            
+            return (1, self.trUtf8("'{0}' argument removed.").format(arg), 0)
+        else:
+            id = self.__getID()
+            self.__stack.append((id, code, line, pos))
+            return (-1, "", id)
+    
+    def __fixW291(self, code, line, pos):
+        """
+        Private method to fix trailing whitespace.
+       
+        Codes: W291, W293
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        self.__source[line - 1] = re.sub(r'[\t ]+(\r?)$', r"\1",
+                                         self.__source[line - 1])
+        return (1, self.trUtf8("Whitespace stripped from end of line."), 0)
+    
+    def __fixW292(self, code, line, pos):
+        """
+        Private method to fix a missing newline at the end of file.
+       
+        Codes: W292
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        self.__source[line - 1] += self.__getEol()
+        return (1, self.trUtf8("newline added to end of file."), 0)
+    
+    def __fixW391(self, code, line, pos):
+        """
+        Private method to fix trailing blank lines.
+       
+        Codes: W391
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        index = line - 1
+        while index:
+            if self.__source[index].strip() == "":
+                del self.__source[index]
+                index -= 1
+            else:
+                break
+        return (1, self.trUtf8(
+            "Superfluous trailing blank lines removed from end of file."), 0)
+    
+    def __fixW603(self, code, line, pos):
+        """
+        Private method to fix the not equal notation.
+       
+        Codes: W603
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @return value indicating an applied/deferred fix (-1, 0, 1),
+            a message for the fix (string) and an ID for a deferred
+            fix (integer)
+        """
+        self.__source[line - 1] = self.__source[line - 1].replace("<>", "!=")
+        return (1, self.trUtf8("'<>' replaced by '!='."), 0)
+
+
+class Reindenter(object):
+    """
+    Class to reindent badly-indented code to uniformly use four-space
+    indentation.
+
+    Released to the public domain, by Tim Peters, 03 October 2000.
+    """
+    def __init__(self, sourceLines):
+        """
+        Constructor
+        
+        @param sourceLines list of source lines including eol marker
+            (list of string)
+        """
+        # Raw file lines.
+        self.raw = sourceLines
+        self.after = []
+
+        # File lines, rstripped & tab-expanded.  Dummy at start is so
+        # that we can use tokenize's 1-based line numbering easily.
+        # Note that a line is all-blank iff it's "\n".
+        self.lines = [line.rstrip().expandtabs() + "\n"
+                      for line in self.raw]
+        self.lines.insert(0, None)
+        self.index = 1  # index into self.lines of next line
+
+        # List of (lineno, indentlevel) pairs, one for each stmt and
+        # comment line.  indentlevel is -1 for comment lines, as a
+        # signal that tokenize doesn't know what to do about them;
+        # indeed, they're our headache!
+        self.stats = []
+    
+    def run(self):
+        """
+        Public method to run the re-indenter.
+        
+        @return flag indicating that a change was done (boolean)
+        """
+        try:
+            stats = self.__genStats(tokenize.generate_tokens(self.getline))
+        except (SyntaxError, tokenize.TokenError):
+            return False
+        
+        # Remove trailing empty lines.
+        lines = self.lines
+        while lines and lines[-1] == "\n":
+            lines.pop()
+        # Sentinel.
+        stats.append((len(lines), 0))
+        # Map count of leading spaces to # we want.
+        have2want = {}
+        # Program after transformation.
+        after = self.after = []
+        # Copy over initial empty lines -- there's nothing to do until
+        # we see a line with *something* on it.
+        i = stats[0][0]
+        after.extend(lines[1:i])
+        for i in range(len(stats) - 1):
+            thisstmt, thislevel = stats[i]
+            nextstmt = stats[i + 1][0]
+            have = self.__getlspace(lines[thisstmt])
+            want = thislevel * 4
+            if want < 0:
+                # A comment line.
+                if have:
+                    # An indented comment line.  If we saw the same
+                    # indentation before, reuse what it most recently
+                    # mapped to.
+                    want = have2want.get(have, -1)
+                    if want < 0:
+                        # Then it probably belongs to the next real stmt.
+                        for j in range(i + 1, len(stats) - 1):
+                            jline, jlevel = stats[j]
+                            if jlevel >= 0:
+                                if have == self.__getlspace(lines[jline]):
+                                    want = jlevel * 4
+                                break
+                    if want < 0:           # Maybe it's a hanging
+                                           # comment like this one,
+                        # in which case we should shift it like its base
+                        # line got shifted.
+                        for j in range(i - 1, -1, -1):
+                            jline, jlevel = stats[j]
+                            if jlevel >= 0:
+                                want = \
+                                    have + \
+                                    self.__getlspace(after[jline - 1]) - \
+                                    self.__getlspace(lines[jline])
+                                break
+                    if want < 0:
+                        # Still no luck -- leave it alone.
+                        want = have
+                else:
+                    want = 0
+            assert want >= 0
+            have2want[have] = want
+            diff = want - have
+            if diff == 0 or have == 0:
+                after.extend(lines[thisstmt:nextstmt])
+            else:
+                for line in lines[thisstmt:nextstmt]:
+                    if diff > 0:
+                        if line == "\n":
+                            after.append(line)
+                        else:
+                            after.append(" " * diff + line)
+                    else:
+                        remove = min(self.__getlspace(line), -diff)
+                        after.append(line[remove:])
+        return self.raw != self.after
+    
+    def fixedLine(self, line):
+        """
+        Public method to get a fixed line.
+        
+        @param line number of the line to retrieve (integer)
+        @return fixed line (string)
+        """
+        if line < len(self.after):
+            return self.after[line]
+    
+    def getline(self):
+        """
+        Public method to get a line of text for tokenize.
+        
+        @return line of text (string)
+        """
+        if self.index >= len(self.lines):
+            line = ""
+        else:
+            line = self.lines[self.index]
+            self.index += 1
+        return line
+
+    def __genStats(self, tokens):
+        """
+        Private method to generate the re-indent statistics.
+        
+        @param tokens tokens generator (tokenize._tokenize)
+        @return reference to the generated statistics
+        """
+        find_stmt = True  # next token begins a fresh stmt?
+        level = 0  # current indent level
+        stats = []
+
+        for t in tokens:
+            token_type = t[0]
+            sline = t[2][0]
+            line = t[4]
+
+            if token_type == tokenize.NEWLINE:
+                # A program statement, or ENDMARKER, will eventually follow,
+                # after some (possibly empty) run of tokens of the form
+                #     (NL | COMMENT)* (INDENT | DEDENT+)?
+                self.find_stmt = True
+
+            elif token_type == tokenize.INDENT:
+                find_stmt = True
+                level += 1
+
+            elif token_type == tokenize.DEDENT:
+                find_stmt = True
+                level -= 1
+
+            elif token_type == tokenize.COMMENT:
+                if find_stmt:
+                    stats.append((sline, -1))
+                    # but we're still looking for a new stmt, so leave
+                    # find_stmt alone
+
+            elif token_type == tokenize.NL:
+                pass
+
+            elif find_stmt:
+                # This is the first "real token" following a NEWLINE, so it
+                # must be the first token of the next program statement, or an
+                # ENDMARKER.
+                find_stmt = False
+                if line:   # not endmarker
+                    stats.append((sline, level))
+        
+        return stats
+    
+    def __getlspace(self, line):
+        """
+        Private method to count number of leading blanks.
+        
+        @param line line to check (string)
+        @return number of leading blanks (integer)
+        """
+        i = 0
+        n = len(line)
+        while i < n and line[i] == " ":
+            i += 1
+        return i
+
+
+class IndentationWrapper(object):
+    """
+    Class used by fixers dealing with indentation.
+
+    Each instance operates on a single logical line.
+    """
+    SKIP_TOKENS = frozenset([
+        tokenize.COMMENT, tokenize.NL, tokenize.INDENT,
+        tokenize.DEDENT, tokenize.NEWLINE, tokenize.ENDMARKER
+    ])
+
+    def __init__(self, physical_lines):
+        """
+        Constructor
+        
+        @param physical_lines list of physical lines to operate on
+            (list of strings)
+        """
+        self.lines = physical_lines
+        self.tokens = []
+        self.rel_indent = None
+        sio = io.StringIO(''.join(physical_lines))
+        for t in tokenize.generate_tokens(sio.readline):
+            if not len(self.tokens) and t[0] in self.SKIP_TOKENS:
+                continue
+            if t[0] != tokenize.ENDMARKER:
+                self.tokens.append(t)
+
+        self.logical_line = self.__buildTokensLogical(self.tokens)
+
+    def __buildTokensLogical(self, tokens):
+        """
+        Private method to build a logical line from a list of tokens.
+        
+        @param tokens list of tokens as generated by tokenize.generate_tokens
+        @return logical line (string)
+        """
+        # from pep8.py with minor modifications
+        logical = []
+        previous = None
+        for t in tokens:
+            token_type, text = t[0:2]
+            if token_type in self.SKIP_TOKENS:
+                continue
+            if previous:
+                end_line, end = previous[3]
+                start_line, start = t[2]
+                if end_line != start_line:  # different row
+                    prev_text = self.lines[end_line - 1][end - 1]
+                    if prev_text == ',' or (prev_text not in '{[('
+                                            and text not in '}])'):
+                        logical.append(' ')
+                elif end != start:  # different column
+                    fill = self.lines[end_line - 1][end:start]
+                    logical.append(fill)
+            logical.append(text)
+            previous = t
+        logical_line = ''.join(logical)
+        assert logical_line.lstrip() == logical_line
+        assert logical_line.rstrip() == logical_line
+        return logical_line
+
+    def pep8Expected(self):
+        """
+        Public method to replicate logic in pep8.py, to know what level to
+        indent things to.
+
+        @return list of lists, where each list represents valid indent levels
+        for the line in question, relative from the initial indent. However,
+        the first entry is the indent level which was expected.
+        """
+        # What follows is an adjusted version of
+        # pep8.py:continuation_line_indentation. All of the comments have been
+        # stripped and the 'yield' statements replaced with 'pass'.
+        if not self.tokens:
+            return
+
+        first_row = self.tokens[0][2][0]
+        nrows = 1 + self.tokens[-1][2][0] - first_row
+
+        # here are the return values
+        valid_indents = [list()] * nrows
+        indent_level = self.tokens[0][2][1]
+        valid_indents[0].append(indent_level)
+
+        if nrows == 1:
+            # bug, really.
+            return valid_indents
+
+        indent_next = self.logical_line.endswith(':')
+
+        row = depth = 0
+        parens = [0] * nrows
+        self.rel_indent = rel_indent = [0] * nrows
+        indent = [indent_level]
+        indent_chances = {}
+        last_indent = (0, 0)
+        last_token_multiline = None
+
+        for token_type, text, start, end, line in self.tokens:
+            newline = row < start[0] - first_row
+            if newline:
+                row = start[0] - first_row
+                newline = (not last_token_multiline and
+                           token_type not in (tokenize.NL, tokenize.NEWLINE))
+
+            if newline:
+                # This is where the differences start. Instead of looking at
+                # the line and determining whether the observed indent matches
+                # our expectations, we decide which type of indentation is in
+                # use at the given indent level, and return the offset. This
+                # algorithm is susceptible to "carried errors", but should
+                # through repeated runs eventually solve indentation for
+                # multiline expressions.
+
+                if depth:
+                    for open_row in range(row - 1, -1, -1):
+                        if parens[open_row]:
+                            break
+                else:
+                    open_row = 0
+
+                # That's all we get to work with. This code attempts to
+                # "reverse" the below logic, and place into the valid indents
+                # list
+                vi = []
+                add_second_chances = False
+                if token_type == tokenize.OP and text in ']})':
+                    # this line starts with a closing bracket, so it needs to
+                    # be closed at the same indent as the opening one.
+                    if indent[depth]:
+                        # hanging indent
+                        vi.append(indent[depth])
+                    else:
+                        # visual indent
+                        vi.append(indent_level + rel_indent[open_row])
+                elif depth and indent[depth]:
+                    # visual indent was previously confirmed.
+                    vi.append(indent[depth])
+                    add_second_chances = True
+                elif depth and True in indent_chances.values():
+                    # visual indent happened before, so stick to
+                    # visual indent this time.
+                    if depth > 1 and indent[depth - 1]:
+                        vi.append(indent[depth - 1])
+                    else:
+                        # stupid fallback
+                        vi.append(indent_level + 4)
+                    add_second_chances = True
+                elif not depth:
+                    vi.append(indent_level + 4)
+                else:
+                    # must be in hanging indent
+                    hang = rel_indent[open_row] + 4
+                    vi.append(indent_level + hang)
+
+                # about the best we can do without look-ahead
+                if (indent_next and vi[0] == indent_level + 4 and
+                        nrows == row + 1):
+                    vi[0] += 4
+
+                if add_second_chances:
+                    # visual indenters like to line things up.
+                    min_indent = vi[0]
+                    for col, what in indent_chances.items():
+                        if col > min_indent and (
+                            what is True or
+                            (what == str and token_type == tokenize.STRING) or
+                            (what == text and token_type == tokenize.OP)
+                        ):
+                            vi.append(col)
+                    vi = sorted(vi)
+
+                valid_indents[row] = vi
+
+                # Returning to original continuation_line_indentation() from
+                # pep8.
+                visual_indent = indent_chances.get(start[1])
+                last_indent = start
+                rel_indent[row] = pep8.expand_indent(line) - indent_level
+                hang = rel_indent[row] - rel_indent[open_row]
+
+                if token_type == tokenize.OP and text in ']})':
+                    pass
+                elif visual_indent is True:
+                    if not indent[depth]:
+                        indent[depth] = start[1]
+
+            # line altered: comments shouldn't define a visual indent
+            if parens[row] and not indent[depth] and token_type not in (
+                tokenize.NL, tokenize.COMMENT
+            ):
+                indent[depth] = start[1]
+                indent_chances[start[1]] = True
+            elif token_type == tokenize.STRING or text in (
+                'u', 'ur', 'b', 'br'
+            ):
+                indent_chances[start[1]] = str
+
+            if token_type == tokenize.OP:
+                if text in '([{':
+                    depth += 1
+                    indent.append(0)
+                    parens[row] += 1
+                elif text in ')]}' and depth > 0:
+                    prev_indent = indent.pop() or last_indent[1]
+                    for d in range(depth):
+                        if indent[d] > prev_indent:
+                            indent[d] = 0
+                    for ind in list(indent_chances):
+                        if ind >= prev_indent:
+                            del indent_chances[ind]
+                    depth -= 1
+                    if depth and indent[depth]:  # modified
+                        indent_chances[indent[depth]] = True
+                    for idx in range(row, -1, -1):
+                        if parens[idx]:
+                            parens[idx] -= 1
+                            break
+                assert len(indent) == depth + 1
+                if start[1] not in indent_chances:
+                    indent_chances[start[1]] = text
+
+            last_token_multiline = (start[0] != end[0])
+
+        return valid_indents
+
+
+class LineShortener(object):
+    """
+    Class used to shorten lines to a given maximum of characters.
+    """
+    def __init__(self, curLine, prevLine, nextLine, maxLength=79, eol="\n",
+                 indentWord="    ", isDocString=False):
+        """
+        Constructor
+        
+        @param curLine text to work on (string)
+        @param prevLine line before the text to work on (string)
+        @param nextLine line after the text to work on (string)
+        @keyparam maxLength maximum allowed line length (integer)
+        @keyparam eol eond-of-line marker (string)
+        @keyparam indentWord string used for indentation (string)
+        @keyparam isDocString flag indicating that the line belongs to
+            a documentation string (boolean)
+        """
+        self.__text = curLine
+        self.__prevText = prevLine
+        self.__nextText = nextLine
+        self.__maxLength = maxLength
+        self.__eol = eol
+        self.__indentWord = indentWord
+        self.__isDocString = isDocString
+    
+    def shorten(self):
+        """
+        Public method to shorten the line wrapped by the class instance.
+        
+        @return tuple of a flag indicating successful shortening, the
+            shortened line and the changed next line (boolean, string, string)
+        """
+        # 1. check for comment
+        if self.__text.lstrip().startswith('#'):
+            lastComment = True
+            if self.__nextText.lstrip().startswith('#'):
+                lastComment = False
+
+            # Wrap commented lines.
+            newText = self.__shortenComment(lastComment)
+            if newText == self.__text:
+                return False, "", ""
+            else:
+                return True, newText, ""
+        elif '#' in self.__text:
+            pos = self.__text.rfind("#")
+            newText = self.__text[:pos].rstrip() + self.__eol + \
+                self.__getIndent(self.__text) + self.__text[pos:]
+            if newText == self.__text:
+                return False, "", ""
+            else:
+                return True, newText, ""
+
+        # Do multi line doc strings
+        if self.__isDocString:
+            source = self.__text.rstrip()
+            blank = source.rfind(" ")
+            while blank > self.__maxLength and blank != -1:
+                blank = source.rfind(" ", 0, blank)
+            if blank == -1:
+                # Cannot break
+                return False, "", ""
+            else:
+                first = self.__text[:blank]
+                second = self.__text[blank:].lstrip()
+                if self.__nextText.strip():
+                    if self.__nextText.lstrip().startswith("@"):
+                        # eric doc comment
+                        # create a new line and indent it
+                        newText = first + self.__eol + \
+                            self.__getIndent(first) + self.__indentWord + \
+                            second
+                        newNext = ""
+                    else:
+                        newText = first + self.__eol
+                        newNext = self.__getIndent(self.__nextText) + \
+                            second.rstrip() + " " + self.__nextText.lstrip()
+                else:
+                    # empty line, add a new line
+                    newText = first + self.__eol + self.__getIndent(first) + \
+                        second
+                    newNext = ""
+            return True, newText, newNext
+        
+        indent = self.__getIndent(self.__text)
+        source = self.__text[len(indent):]
+        assert source.lstrip() == source
+        sio = io.StringIO(source)
+        
+        # Check for multi line string.
+        try:
+            tokens = list(tokenize.generate_tokens(sio.readline))
+        except (SyntaxError, tokenize.TokenError):
+            if source.rstrip().endswith("\\"):
+                # just join the continuation line and let the next run
+                # handle it once it tokenizes ok
+                newText = indent + source.rstrip()[:-1].rstrip() + " " + \
+                    self.__nextText.lstrip()
+                if indent:
+                    newNext = indent
+                else:
+                    newNext = " "
+                return True, newText, newNext
+            else:
+                multilineCandidate = self.__breakMultiline()
+                if multilineCandidate:
+                    return True, multilineCandidate[0], multilineCandidate[1]
+                else:
+                    return False, "", ""
+
+        # Handle statements by putting the right hand side on a line by itself.
+        # This should let the next pass shorten it.
+        if source.startswith('return '):
+            newText = (
+                indent +
+                'return (' +
+                self.__eol +
+                indent + self.__indentWord + re.sub('^return ', '', source) +
+                indent + ')' + self.__eol
+            )
+            return True, newText, ""
+        
+        candidates = self.__shortenLine(tokens, source, indent)
+        if candidates:
+            candidates = list(sorted(
+                set(candidates).union([self.__text]),
+                key=lambda x: self.__lineShorteningRank(x)))
+            if candidates[0] == self.__text:
+                return False, "", ""
+            return True, candidates[0], ""
+        
+        source = self.__text
+        rs = source.rstrip()
+        if rs.endswith(("'", '"')) and " " in source:
+            if rs.endswith(('"""', "'''")):
+                quote = rs[-3:]
+            else:
+                quote = rs[-1]
+            blank = source.rfind(" ")
+            maxLen = self.__maxLength - 2 - len(quote)
+            while blank > maxLen and blank != -1:
+                blank = source.rfind(" ", 0, blank)
+            if blank != -1:
+                if source[blank + 1:].startswith(quote):
+                    first = source[:maxLen]
+                    second = source[maxLen:]
+                else:
+                    first = source[:blank]
+                    second = source[blank + 1:]
+                return (
+                    True,
+                    first + quote + " \\" + self.__eol +
+                    indent + self.__indentWord + quote + second,
+                    "")
+            else:
+                # Cannot break
+                return False, "", ""
+        
+        return False, "", ""
+    
+    def __shortenComment(self, isLast):
+        """
+        Private method to shorten a comment line.
+        
+        @param isLast flag indicating, that the line is the last comment line
+            (boolean)
+        @return shortened comment line (string)
+        """
+        if len(self.__text) <= self.__maxLength:
+            return self.__text
+        
+        newText = self.__text.rstrip()
+
+        # PEP 8 recommends 72 characters for comment text.
+        indentation = self.__getIndent(newText) + '# '
+        maxLength = min(self.__maxLength,
+                        len(indentation) + 72)
+
+        MIN_CHARACTER_REPEAT = 5
+        if len(newText) - len(newText.rstrip(newText[-1])) >= \
+                MIN_CHARACTER_REPEAT and \
+                not newText[-1].isalnum():
+            # Trim comments that end with things like ---------
+            return newText[:maxLength] + self.__eol
+        elif isLast and re.match(r"\s*#+\s*\w+", newText):
+            import textwrap
+            splitLines = textwrap.wrap(newText.lstrip(" \t#"),
+                                       initial_indent=indentation,
+                                       subsequent_indent=indentation,
+                                       width=maxLength,
+                                       break_long_words=False,
+                                       break_on_hyphens=False)
+            return self.__eol.join(splitLines) + self.__eol
+        else:
+            return newText + self.__eol
+    
+    def __breakMultiline(self):
+        """
+        Private method to break multi line strings.
+        
+        @return tuple of the shortened line and the changed next line
+            (string, string)
+        """
+        indentation = self.__getIndent(self.__text)
+
+        # Handle special case.
+        for symbol in '([{':
+            # Only valid if symbol is not on a line by itself.
+            if (
+                symbol in self.__text and
+                self.__text.strip() != symbol and
+                self.__text.rstrip().endswith((',', '%'))
+            ):
+                index = 1 + self.__text.find(symbol)
+
+                if index <= len(self.__indentWord) + len(indentation):
+                    continue
+
+                if self.__isProbablyInsideStringOrComment(
+                        self.__text, index - 1):
+                    continue
+
+                return (self.__text[:index].rstrip() + self.__eol +
+                        indentation + self.__indentWord +
+                        self.__text[index:].lstrip(), "")
+        
+        newText = self.__text
+        newNext = self.__nextText
+        blank = newText.rfind(" ")
+        while blank > self.__maxLength and blank != -1:
+            blank = newText.rfind(" ", 0, blank)
+        if blank != -1:
+            first = self.__text[:blank]
+            second = self.__text[blank:].strip()
+            if newNext.strip():
+                newText = first + self.__eol
+                if second.endswith(")"):
+                    # don't merge with next line
+                    newText += self.__getIndent(newText) + second + self.__eol
+                    newNext = ""
+                else:
+                    newNext = self.__getIndent(newNext) + \
+                        second + " " + newNext.lstrip()
+            else:
+                # empty line, add a new line
+                newText = first + self.__eol
+                newNext = self.__getIndent(newNext) + \
+                    second + self.__eol + newNext.lstrip()
+            return newText, newNext
+        else:
+            return None
+    
+    def __isProbablyInsideStringOrComment(self, line, index):
+        """
+        Private method to check, if the given string might be inside a string
+        or comment.
+        
+        @param line line to check (string)
+        @param index position inside line to check (integer)
+        @return flag indicating the possibility of being inside a string
+            or comment
+        """
+        # Check against being in a string.
+        for quote in ['"', "'"]:
+            pos = line.find(quote)
+            if pos != -1 and pos <= index:
+                return True
+
+        # Check against being in a comment.
+        pos = line.find('#')
+        if pos != -1 and pos <= index:
+            return True
+
+        return False
+    
+    def __shortenLine(self, tokens, source, indent):
+        """
+        Private method to shorten a line of code at an operator.
+        
+        @param tokens tokens of the line as generated by tokenize
+            (list of token)
+        @param source code string to work at (string)
+        @param indent indentation string of the code line (string)
+        @return list of candidates (list of string)
+        """
+        candidates = []
+        
+        for tkn in tokens:
+            tokenType = tkn[0]
+            tokenString = tkn[1]
+
+            if (
+                tokenType == tokenize.COMMENT and
+                not self.__prevText.rstrip().endswith('\\')
+            ):
+                # Move inline comments to previous line.
+                offset = tkn[2][1]
+                first = source[:offset]
+                second = source[offset:]
+                candidates.append(
+                    indent + second.strip() + self.__eol +
+                    indent + first.strip() + self.__eol)
+            elif tokenType == tokenize.OP and tokenString != '=':
+                # Don't break on '=' after keyword as this violates PEP 8.
+
+                assert tokenType != tokenize.INDENT
+
+                offset = tkn[2][1] + 1
+                first = source[:offset]
+
+                secondIndent = indent
+                if first.rstrip().endswith('('):
+                    secondIndent += self.__indentWord
+                elif '(' in first:
+                    secondIndent += ' ' * (1 + first.find('('))
+                else:
+                    secondIndent += self.__indentWord
+
+                second = (secondIndent + source[offset:].lstrip())
+                if not second.strip():
+                    continue
+
+                # Do not begin a line with a comma
+                if second.lstrip().startswith(','):
+                    continue
+                
+                # Do end a line with a dot
+                if first.rstrip().endswith('.'):
+                    continue
+                
+                if tokenString in '+-*/,':
+                    newText = first + ' \\' + self.__eol + second
+                else:
+                    newText = first + self.__eol + second
+
+                # Only fix if syntax is okay.
+                if self.__checkSyntax(self.__normalizeMultiline(newText)):
+                    candidates.append(indent + newText)
+        
+        return candidates
+    
+    def __normalizeMultiline(self, text):
+        """
+        Private method to remove multiline-related code that will cause syntax
+        error.
+        
+        @param text code line to work on (string)
+        @return normalized code line (string)
+        """
+        for quote in '\'"':
+            dictPattern = r"^{q}[^{q}]*{q} *: *".format(q=quote)
+            if re.match(dictPattern, text):
+                if not text.strip().endswith('}'):
+                    text += '}'
+                return '{' + text
+
+        if text.startswith('def ') and text.rstrip().endswith(':'):
+            # Do not allow ':' to be alone. That is invalid.
+            splitText = [item.strip() for item in text.split(self.__eol)]
+            if ':' not in splitText and 'def' not in splitText:
+                return text[len('def'):].strip().rstrip(':')
+
+        return text
+    
+    def __lineShorteningRank(self, candidate):
+        """
+        Private method to rank a candidate.
+        
+        @param candidate candidate line to rank (string)
+        @return rank of the candidate (integer)
+        """
+        rank = 0
+        if candidate.strip():
+            if candidate == self.__text:
+                # give the original a disadvantage
+                rank += 50
+            
+            lines = candidate.split(self.__eol)
+
+            offset = 0
+            if lines[0].rstrip()[-1] not in '([{':
+                for symbol in '([{':
+                    offset = max(offset, 1 + lines[0].find(symbol))
+
+            maxLength = max([offset + len(x.strip()) for x in lines])
+            rank += maxLength
+            rank += len(lines)
+
+            badStartingSymbol = {
+                '(': ')',
+                '[': ']',
+                '{': '}'}.get(lines[0][-1], None)
+
+            if len(lines) > 1:
+                if (badStartingSymbol and
+                        lines[1].lstrip().startswith(badStartingSymbol)):
+                    rank += 20
+
+            if re.match(r".*[+\-\*/] \($", lines[0]):
+                # "1 * (\n" is ugly as hell.
+                rank += 100
+
+            for currentLine in lines:
+                for badStart in ['.', '%', '+', '-', '/']:
+                    if currentLine.startswith(badStart):
+                        rank += 100
+
+                for ending in '([{':
+                    # Avoid lonely opening. They result in longer lines.
+                    if currentLine.endswith(ending) and \
+                            len(currentLine.strip()) <= len(self.__indentWord):
+                        rank += 100
+
+                if currentLine.endswith('%'):
+                    rank -= 20
+
+                # Try to break list comprehensions at the "for".
+                if currentLine.lstrip().startswith('for'):
+                    rank -= 50
+
+                rank += 10 * self.__countUnbalancedBrackets(currentLine)
+        else:
+            rank = 100000
+        
+        return max(0, rank)
+    
+    def __countUnbalancedBrackets(self, line):
+        """
+        Private method to determine the number of unmatched open/close
+        brackets.
+        
+        @param line line to work at (string)
+        @return number of unmatched open/close brackets (integer)
+        """
+        count = 0
+        for opening, closing in ['()', '[]', '{}']:
+            count += abs(line.count(opening) - line.count(closing))
+        
+        return count
+    
+    def __getIndent(self, line):
+        """
+        Private method to get the indentation string.
+        
+        @param line line to determine the indentation string from (string)
+        @return indentation string (string)
+        """
+        # copied from CodeStyleFixer
+        return line.replace(line.lstrip(), "")
+    
+    def __checkSyntax(self, code):
+        """
+        Private method to check the syntax of the given code fragment.
+        
+        @param code code fragment to check (string)
+        @return flag indicating syntax is ok (boolean)
+        """
+        code = code.replace("\r\n", "\n").replace("\r", "\n")
+        try:
+            return compile(code, '<string>', 'exec')
+        except (SyntaxError, TypeError, UnicodeDecodeError):
+            return False
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleStatisticsDialog.py	Fri Oct 04 14:26:08 2013 +0200
@@ -0,0 +1,101 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2011 - 2013 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a dialog showing statistical data for the last code
+style checker run.
+"""
+
+from PyQt4.QtCore import Qt, QCoreApplication
+from PyQt4.QtGui import QDialog, QTreeWidgetItem
+
+from . import pep8
+from .NamingStyleChecker import NamingStyleChecker
+from .DocStyleChecker import DocStyleChecker
+
+from .Ui_CodeStyleStatisticsDialog import Ui_CodeStyleStatisticsDialog
+
+import UI.PixmapCache
+
+
+class CodeStyleStatisticsDialog(QDialog, Ui_CodeStyleStatisticsDialog):
+    """
+    Class implementing a dialog showing statistical data for the last
+    code style checker run.
+    """
+    def __init__(self, statistics, parent=None):
+        """
+        Constructor
+        
+        @param statistics dictionary with the statistical data
+        @param parent reference to the parent widget (QWidget)
+        """
+        super().__init__(parent)
+        self.setupUi(self)
+        
+        stats = statistics.copy()
+        filesCount = stats["_FilesCount"]
+        filesIssues = stats["_FilesIssues"]
+        fixesCount = stats["_IssuesFixed"]
+        del stats["_FilesCount"]
+        del stats["_FilesIssues"]
+        del stats["_IssuesFixed"]
+        
+        totalIssues = 0
+        
+        for code in sorted(stats.keys()):
+            if code in pep8.pep8_messages_sample_args:
+                message = QCoreApplication.translate(
+                    "pep8", pep8.pep8_messages[code]).format(
+                    *pep8.pep8_messages_sample_args[code])
+            elif code in pep8.pep8_messages:
+                message = QCoreApplication.translate(
+                    "pep8", pep8.pep8_messages[code])
+            elif code in NamingStyleChecker.Messages:
+                message = QCoreApplication.translate(
+                    "NamingStyleChecker", NamingStyleChecker.Messages[code])
+            elif code in DocStyleChecker.Messages:
+                message = QCoreApplication.translate(
+                    "DocStyleChecker", DocStyleChecker.Messages[code])
+            else:
+                continue
+            self.__createItem(stats[code], code, message)
+            totalIssues += stats[code]
+        
+        self.totalIssues.setText(
+            self.trUtf8("%n issue(s) found", "", totalIssues))
+        self.fixedIssues.setText(
+            self.trUtf8("%n issue(s) fixed", "", fixesCount))
+        self.filesChecked.setText(
+            self.trUtf8("%n file(s) checked", "", filesCount))
+        self.filesIssues.setText(
+            self.trUtf8("%n file(s) with issues found", "", filesIssues))
+        
+        self.statisticsList.resizeColumnToContents(0)
+        self.statisticsList.resizeColumnToContents(1)
+    
+    def __createItem(self, count, code, message):
+        """
+        Private method to create an entry in the result list.
+        
+        @param count occurrences of the issue (integer)
+        @param code of a code style issue message (string)
+        @param message code style issue message to be shown (string)
+        """
+        itm = QTreeWidgetItem(self.statisticsList)
+        itm.setData(0, Qt.DisplayRole, count)
+        itm.setData(1, Qt.DisplayRole, code)
+        itm.setData(2, Qt.DisplayRole, message)
+        if code.startswith("W"):
+            itm.setIcon(1, UI.PixmapCache.getIcon("warning.png"))
+        elif code.startswith("E"):
+            itm.setIcon(1, UI.PixmapCache.getIcon("syntaxError.png"))
+        elif code.startswith("N"):
+            itm.setIcon(1, UI.PixmapCache.getIcon("namingError.png"))
+        elif code.startswith("D"):
+            itm.setIcon(1, UI.PixmapCache.getIcon("docstringError.png"))
+        
+        itm.setTextAlignment(0, Qt.AlignRight)
+        itm.setTextAlignment(1, Qt.AlignHCenter)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleStatisticsDialog.ui	Fri Oct 04 14:26:08 2013 +0200
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>CodeStyleStatisticsDialog</class>
+ <widget class="QDialog" name="CodeStyleStatisticsDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>531</width>
+    <height>372</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Code Style Checker Statistics</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QTreeWidget" name="statisticsList">
+     <property name="alternatingRowColors">
+      <bool>true</bool>
+     </property>
+     <property name="rootIsDecorated">
+      <bool>false</bool>
+     </property>
+     <property name="wordWrap">
+      <bool>true</bool>
+     </property>
+     <column>
+      <property name="text">
+       <string>Count</string>
+      </property>
+     </column>
+     <column>
+      <property name="text">
+       <string>Code</string>
+      </property>
+     </column>
+     <column>
+      <property name="text">
+       <string>Message</string>
+      </property>
+     </column>
+    </widget>
+   </item>
+   <item>
+    <layout class="QGridLayout" name="gridLayout">
+     <item row="0" column="0">
+      <widget class="QLabel" name="filesChecked">
+       <property name="text">
+        <string/>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="1">
+      <widget class="QLabel" name="filesIssues">
+       <property name="text">
+        <string/>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="0">
+      <widget class="QLabel" name="totalIssues">
+       <property name="text">
+        <string/>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="1">
+      <widget class="QLabel" name="fixedIssues">
+       <property name="text">
+        <string/>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Close</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <tabstops>
+  <tabstop>statisticsList</tabstop>
+  <tabstop>buttonBox</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>CodeStyleStatisticsDialog</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>CodeStyleStatisticsDialog</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>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/CheckerPlugins/CodeStyleChecker/DocStyleChecker.py	Fri Oct 04 14:26:08 2013 +0200
@@ -0,0 +1,1307 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2013 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a checker for PEP-257 documentation string conventions.
+"""
+
+#
+# The routines of the checker class are modeled after the ones found in
+# pep257.py (version 0.2.4).
+#
+
+try:
+    # Python 2
+    from StringIO import StringIO       # __IGNORE_EXCEPTION__
+except ImportError:
+    # Python 3
+    from io import StringIO             # __IGNORE_WARNING__
+import tokenize
+import ast
+import sys
+
+from PyQt4.QtCore import QT_TRANSLATE_NOOP, QCoreApplication
+
+
+class DocStyleContext(object):
+    """
+    Class implementing the source context.
+    """
+    def __init__(self, source, startLine, contextType):
+        """
+        Constructor
+        
+        @param source source code of the context (list of string or string)
+        @param startLine line number the context starts in the source (integer)
+        @param contextType type of the context object (string)
+        """
+        if isinstance(source, str):
+            self.__source = source.splitlines(True)
+        else:
+            self.__source = source[:]
+        self.__start = startLine
+        self.__indent = ""
+        self.__type = contextType
+        
+        # ensure first line is left justified
+        if self.__source:
+            self.__indent = self.__source[0].replace(
+                self.__source[0].lstrip(), "")
+            self.__source[0] = self.__source[0].lstrip()
+    
+    def source(self):
+        """
+        Public method to get the source.
+        
+        @return source (list of string)
+        """
+        return self.__source
+    
+    def ssource(self):
+        """
+        Public method to get the joined source lines.
+        
+        @return source (string)
+        """
+        return "".join(self.__source)
+    
+    def start(self):
+        """
+        Public method to get the start line number.
+        
+        @return start line number (integer)
+        """
+        return self.__start
+    
+    def end(self):
+        """
+        Public method to get the end line number.
+        
+        @return end line number (integer)
+        """
+        return self.__start + len(self.__source) - 1
+    
+    def indent(self):
+        """
+        Public method to get the indentation of the first line.
+        
+        @return indentation string (string)
+        """
+        return self.__indent
+    
+    def contextType(self):
+        """
+        Public method to get the context type.
+        
+        @return context type (string)
+        """
+        return self.__type
+
+
+class DocStyleChecker(object):
+    """
+    Class implementing a checker for PEP-257 documentation string conventions.
+    """
+    Codes = [
+        "D101", "D102", "D103", "D104", "D105",
+        "D111", "D112", "D113",
+        "D121", "D122",
+        "D131", "D132", "D133", "D134",
+        "D141", "D142", "D143", "D144", "D145",
+        
+        "D203", "D205",
+        "D221", "D222",
+        "D231", "D234", "D235", "D236", "D237", "D238", "D239",
+        "D242", "D243", "D244", "D245", "D246", "D247",
+        "D250", "D251",
+    ]
+    
+    Messages = {
+        "D101": QT_TRANSLATE_NOOP(
+            "DocStyleChecker", "module is missing a docstring"),
+        "D102": QT_TRANSLATE_NOOP(
+            "DocStyleChecker",
+            "public function/method is missing a docstring"),
+        "D103": QT_TRANSLATE_NOOP(
+            "DocStyleChecker",
+            "private function/method may be missing a docstring"),
+        "D104": QT_TRANSLATE_NOOP(
+            "DocStyleChecker", "public class is missing a docstring"),
+        "D105": QT_TRANSLATE_NOOP(
+            "DocStyleChecker", "private class may be missing a docstring"),
+        "D111": QT_TRANSLATE_NOOP(
+            "DocStyleChecker", 'docstring not surrounded by """'),
+        "D112": QT_TRANSLATE_NOOP(
+            "DocStyleChecker",
+            'docstring containing \\ not surrounded by r"""'),
+        "D113": QT_TRANSLATE_NOOP(
+            "DocStyleChecker",
+            'docstring containing unicode character not surrounded by u"""'),
+        "D121": QT_TRANSLATE_NOOP(
+            "DocStyleChecker", "one-liner docstring on multiple lines"),
+        "D122": QT_TRANSLATE_NOOP(
+            "DocStyleChecker", "docstring has wrong indentation"),
+        "D131": QT_TRANSLATE_NOOP(
+            "DocStyleChecker", "docstring summary does not end with a period"),
+        "D132": QT_TRANSLATE_NOOP(
+            "DocStyleChecker",
+            "docstring summary is not in imperative mood"
+            " (Does instead of Do)"),
+        "D133": QT_TRANSLATE_NOOP(
+            "DocStyleChecker",
+            "docstring summary looks like a function's/method's signature"),
+        "D134": QT_TRANSLATE_NOOP(
+            "DocStyleChecker",
+            "docstring does not mention the return value type"),
+        "D141": QT_TRANSLATE_NOOP(
+            "DocStyleChecker",
+            "function/method docstring is separated by a blank line"),
+        "D142": QT_TRANSLATE_NOOP(
+            "DocStyleChecker",
+            "class docstring is not preceded by a blank line"),
+        "D143": QT_TRANSLATE_NOOP(
+            "DocStyleChecker",
+            "class docstring is not followed by a blank line"),
+        "D144": QT_TRANSLATE_NOOP(
+            "DocStyleChecker",
+            "docstring summary is not followed by a blank line"),
+        "D145": QT_TRANSLATE_NOOP(
+            "DocStyleChecker",
+            "last paragraph of docstring is not followed by a blank line"),
+        
+        "D203": QT_TRANSLATE_NOOP(
+            "DocStyleChecker",
+            "private function/method is missing a docstring"),
+        "D205": QT_TRANSLATE_NOOP(
+            "DocStyleChecker", "private class is missing a docstring"),
+        "D221": QT_TRANSLATE_NOOP(
+            "DocStyleChecker",
+            "leading quotes of docstring not on separate line"),
+        "D222": QT_TRANSLATE_NOOP(
+            "DocStyleChecker",
+            "trailing quotes of docstring not on separate line"),
+        "D231": QT_TRANSLATE_NOOP(
+            "DocStyleChecker", "docstring summary does not end with a period"),
+        "D234": QT_TRANSLATE_NOOP(
+            "DocStyleChecker",
+            "docstring does not contain a @return line but function/method"
+            " returns something"),
+        "D235": QT_TRANSLATE_NOOP(
+            "DocStyleChecker",
+            "docstring contains a @return line but function/method doesn't"
+            " return anything"),
+        "D236": QT_TRANSLATE_NOOP(
+            "DocStyleChecker",
+            "docstring does not contain enough @param/@keyparam lines"),
+        "D237": QT_TRANSLATE_NOOP(
+            "DocStyleChecker",
+            "docstring contains too many @param/@keyparam lines"),
+        "D238": QT_TRANSLATE_NOOP(
+            "DocStyleChecker",
+            "keyword only arguments must be documented with @keyparam lines"),
+        "D239": QT_TRANSLATE_NOOP(
+            "DocStyleChecker", "order of @param/@keyparam lines does"
+            " not match the function/method signature"),
+        "D242": QT_TRANSLATE_NOOP(
+            "DocStyleChecker", "class docstring is preceded by a blank line"),
+        "D243": QT_TRANSLATE_NOOP(
+            "DocStyleChecker", "class docstring is followed by a blank line"),
+        "D244": QT_TRANSLATE_NOOP(
+            "DocStyleChecker",
+            "function/method docstring is preceded by a blank line"),
+        "D245": QT_TRANSLATE_NOOP(
+            "DocStyleChecker",
+            "function/method docstring is followed by a blank line"),
+        "D246": QT_TRANSLATE_NOOP(
+            "DocStyleChecker",
+            "docstring summary is not followed by a blank line"),
+        "D247": QT_TRANSLATE_NOOP(
+            "DocStyleChecker",
+            "last paragraph of docstring is followed by a blank line"),
+        "D250": QT_TRANSLATE_NOOP(
+            "DocStyleChecker",
+            "docstring does not contain a @exception line but function/method"
+            " raises an exception"),
+        "D251": QT_TRANSLATE_NOOP(
+            "DocStyleChecker",
+            "docstring contains a @exception line but function/method doesn't"
+            " raise an exception"),
+    }
+    
+    def __init__(self, source, filename, select, ignore, expected, repeat,
+                 maxLineLength=79, docType="pep257"):
+        """
+        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)
+        @keyparam maxLineLength allowed line length (integer)
+        @keyparam docType type of the documentation strings
+            (string, one of 'eric' or 'pep257')
+        """
+        assert docType in ("eric", "pep257")
+        
+        self.__select = tuple(select)
+        self.__ignore = tuple(ignore)
+        self.__expected = expected[:]
+        self.__repeat = repeat
+        self.__maxLineLength = maxLineLength
+        self.__docType = docType
+        self.__filename = filename
+        self.__source = source[:]
+        
+        # statistics counters
+        self.counters = {}
+        
+        # collection of detected errors
+        self.errors = []
+        
+        self.__lineNumber = 0
+        
+        # caches
+        self.__functionsCache = None
+        self.__classesCache = None
+        self.__methodsCache = None
+        
+        self.__keywords = [
+            'moduleDocstring', 'functionDocstring',
+            'classDocstring', 'methodDocstring',
+            'defDocstring', 'docstring'
+        ]
+        if self.__docType == "pep257":
+            checkersWithCodes = {
+                "moduleDocstring": [
+                    (self.__checkModulesDocstrings, ("D101",)),
+                ],
+                "functionDocstring": [
+                ],
+                "classDocstring": [
+                    (self.__checkClassDocstring, ("D104", "D105")),
+                    (self.__checkBlankBeforeAndAfterClass, ("D142", "D143")),
+                ],
+                "methodDocstring": [
+                ],
+                "defDocstring": [
+                    (self.__checkFunctionDocstring, ("D102", "D103")),
+                    (self.__checkImperativeMood, ("D132",)),
+                    (self.__checkNoSignature, ("D133",)),
+                    (self.__checkReturnType, ("D134",)),
+                    (self.__checkNoBlankLineBefore, ("D141",)),
+                ],
+                "docstring": [
+                    (self.__checkTripleDoubleQuotes, ("D111",)),
+                    (self.__checkBackslashes, ("D112",)),
+                    (self.__checkUnicode, ("D113",)),
+                    (self.__checkOneLiner, ("D121",)),
+                    (self.__checkIndent, ("D122",)),
+                    (self.__checkEndsWithPeriod, ("D131",)),
+                    (self.__checkBlankAfterSummary, ("D144",)),
+                    (self.__checkBlankAfterLastParagraph, ("D145",)),
+                ],
+            }
+        elif self.__docType == "eric":
+            checkersWithCodes = {
+                "moduleDocstring": [
+                    (self.__checkModulesDocstrings, ("D101",)),
+                ],
+                "functionDocstring": [
+                ],
+                "classDocstring": [
+                    (self.__checkClassDocstring, ("D104", "D205")),
+                    (self.__checkEricNoBlankBeforeAndAfterClassOrFunction,
+                     ("D242", "D243")),
+                ],
+                "methodDocstring": [
+                ],
+                "defDocstring": [
+                    (self.__checkFunctionDocstring, ("D102", "D203")),
+                    (self.__checkImperativeMood, ("D132",)),
+                    (self.__checkNoSignature, ("D133",)),
+                    (self.__checkEricReturn, ("D234", "D235")),
+                    (self.__checkEricFunctionArguments,
+                     ("D236", "D237", "D238", "D239")),
+                    (self.__checkEricNoBlankBeforeAndAfterClassOrFunction,
+                     ("D244", "D245")),
+                    (self.__checkEricException, ("D250", "D251")),
+                ],
+                "docstring": [
+                    (self.__checkTripleDoubleQuotes, ("D111",)),
+                    (self.__checkBackslashes, ("D112",)),
+                    (self.__checkUnicode, ("D113",)),
+                    (self.__checkIndent, ("D122",)),
+                    (self.__checkEricEndsWithPeriod, ("D231",)),
+                    (self.__checkEricBlankAfterSummary, ("D246",)),
+                    (self.__checkEricNBlankAfterLastParagraph, ("D247",)),
+                    (self.__checkEricQuotesOnSeparateLines, ("D222", "D223"))
+                ],
+            }
+        
+        self.__checkers = {}
+        for key, checkers in checkersWithCodes.items():
+            for checker, codes in checkers:
+                if any(not (code and self.__ignoreCode(code))
+                        for code in codes):
+                    if key not in self.__checkers:
+                        self.__checkers[key] = []
+                    self.__checkers[key].append(checker)
+    
+    def __ignoreCode(self, code):
+        """
+        Private method to check if the error 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):
+            if code in DocStyleChecker.Codes:
+                text = self.getMessage(code, *args)
+            else:
+                text = code + " " + QCoreApplication.translate(
+                    "DocStyleChecker", "no message for this code defined")
+            # record the issue with one based line number
+            self.errors.append((self.__filename, lineNumber + 1, offset, text))
+    
+    @classmethod
+    def getMessage(cls, code, *args):
+        """
+        Class method to get a translated and formatted message for a
+        given code.
+        
+        @param code message code (string)
+        @param args arguments for a formatted message (list)
+        @return translated and formatted message (string)
+        """
+        if code in DocStyleChecker.Messages:
+            return code + " " + QCoreApplication.translate(
+                "DocStyleChecker", DocStyleChecker.Messages[code]).format(*args)
+        else:
+            return code + " " + QCoreApplication.translate(
+                "DocStyleChecker", "no message for this code defined")
+    
+    def __resetReadline(self):
+        """
+        Private method to reset the internal readline function.
+        """
+        self.__lineNumber = 0
+    
+    def __readline(self):
+        """
+        Private method to get the next line from the source.
+        
+        @return next line of source (string)
+        """
+        self.__lineNumber += 1
+        if self.__lineNumber > len(self.__source):
+            return ''
+        return self.__source[self.__lineNumber - 1]
+    
+    def run(self):
+        """
+        Public method to check the given source for violations of doc string
+        conventions according to PEP-257.
+        """
+        if not self.__source or 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
+        
+        for keyword in self.__keywords:
+            if keyword in self.__checkers:
+                for check in self.__checkers[keyword]:
+                    for context in self.__parseContexts(keyword):
+                        docstring = self.__parseDocstring(context, keyword)
+                        check(docstring, context)
+    
+    def __getSummaryLine(self, docstringContext):
+        """
+        Private method to extract the summary line.
+        
+        @param docstringContext docstring context (DocStyleContext)
+        @return summary line (string) and the line it was found on (integer)
+        """
+        lines = docstringContext.source()
+        
+        line = (lines[0]
+                .replace('r"""', "", 1)
+                .replace('u"""', "", 1)
+                .replace('"""', "")
+                .replace("r'''", "", 1)
+                .replace("u'''", "", 1)
+                .replace("'''", "")
+                .strip())
+        
+        if len(lines) == 1 or len(line) > 0:
+            return line, 0
+        return lines[1].strip().replace('"""', "").replace("'''", ""), 1
+    
+    def __getSummaryLines(self, docstringContext):
+        """
+        Private method to extract the summary lines.
+        
+        @param docstringContext docstring context (DocStyleContext)
+        @return summary lines (list of string) and the line it was found on
+            (integer)
+        """
+        summaries = []
+        lines = docstringContext.source()
+        
+        line0 = (lines[0]
+                 .replace('r"""', "", 1)
+                 .replace('u"""', "", 1)
+                 .replace('"""', "")
+                 .replace("r'''", "", 1)
+                 .replace("u'''", "", 1)
+                 .replace("'''", "")
+                 .strip())
+        if len(lines) > 1:
+            line1 = lines[1].strip().replace('"""', "").replace("'''", "")
+        else:
+            line1 = ""
+        if len(lines) > 2:
+            line2 = lines[2].strip().replace('"""', "").replace("'''", "")
+        else:
+            line2 = ""
+        if line0:
+            lineno = 0
+            summaries.append(line0)
+            if not line0.endswith(".") and line1:
+                # two line summary
+                summaries.append(line1)
+        elif line1:
+            lineno = 1
+            summaries.append(line1)
+            if not line1.endswith(".") and line2:
+                # two line summary
+                summaries.append(line2)
+        else:
+            lineno = 2
+            summaries.append(line2)
+        return summaries, lineno
+    
+    if sys.version_info[0] < 3:
+        def __getArgNames(self, node):
+            """
+            Private method to get the argument names of a function node.
+            
+            @param node AST node to extract arguments names from
+            @return tuple of two list of argument names, one for arguments
+                and one for keyword arguments (tuple of list of string)
+            """
+            def unpackArgs(args):
+                """
+                Local helper function to unpack function argument names.
+                
+                @param args list of AST node arguments
+                @return list of argument names (list of string)
+                """
+                ret = []
+                for arg in args:
+                    if isinstance(arg, ast.Tuple):
+                        ret.extend(unpackArgs(arg.elts))
+                    else:
+                        ret.append(arg.id)
+                return ret
+            
+            arguments = unpackArgs(node.args.args)
+            if node.args.vararg is not None:
+                arguments.append(node.args.vararg)
+            kwarguments = []
+            if node.args.kwarg is not None:
+                kwarguments.append(node.args.kwarg)
+            return arguments, kwarguments
+    else:
+        def __getArgNames(self, node):          # __IGNORE_WARNING__
+            """
+            Private method to get the argument names of a function node.
+            
+            @param node AST node to extract arguments names from
+            @return tuple of two list of argument names, one for arguments
+                and one for keyword arguments (tuple of list of string)
+            """
+            arguments = []
+            arguments.extend([arg.arg for arg in node.args.args])
+            if node.args.vararg is not None:
+                arguments.append(node.args.vararg)
+            
+            kwarguments = []
+            kwarguments.extend([arg.arg for arg in node.args.kwonlyargs])
+            if node.args.kwarg is not None:
+                kwarguments.append(node.args.kwarg)
+            return arguments, kwarguments
+    
+    ##################################################################
+    ## Parsing functionality below
+    ##################################################################
+    
+    def __parseModuleDocstring(self, source):
+        """
+        Private method to extract a docstring given a module source.
+        
+        @param source source to parse (list of string)
+        @return context of extracted docstring (DocStyleContext)
+        """
+        for kind, value, (line, char), _, _ in tokenize.generate_tokens(
+                StringIO("".join(source)).readline):
+            if kind in [tokenize.COMMENT, tokenize.NEWLINE, tokenize.NL]:
+                continue
+            elif kind == tokenize.STRING:  # first STRING should be docstring
+                return DocStyleContext(value, line - 1, "docstring")
+            else:
+                return None
+
+    def __parseDocstring(self, context, what=''):
+        """
+        Private method to extract a docstring given `def` or `class` source.
+        
+        @param context context data to get the docstring from (DocStyleContext)
+        @param what string denoting what is being parsed (string)
+        @return context of extracted docstring (DocStyleContext)
+        """
+        moduleDocstring = self.__parseModuleDocstring(context.source())
+        if what.startswith('module') or context.contextType() == "module":
+            return moduleDocstring
+        if moduleDocstring:
+            return moduleDocstring
+        
+        tokenGenerator = tokenize.generate_tokens(
+            StringIO(context.ssource()).readline)
+        try:
+            kind = None
+            while kind != tokenize.INDENT:
+                kind, _, _, _, _ = next(tokenGenerator)
+            kind, value, (line, char), _, _ = next(tokenGenerator)
+            if kind == tokenize.STRING:  # STRING after INDENT is a docstring
+                return DocStyleContext(
+                    value, context.start() + line - 1, "docstring")
+        except StopIteration:
+            pass
+        
+        return None
+    
+    def __parseTopLevel(self, keyword):
+        """
+        Private method to extract top-level functions or classes.
+        
+        @param keyword keyword signaling what to extract (string)
+        @return extracted function or class contexts (list of DocStyleContext)
+        """
+        self.__resetReadline()
+        tokenGenerator = tokenize.generate_tokens(self.__readline)
+        kind, value, char = None, None, None
+        contexts = []
+        try:
+            while True:
+                start, end = None, None
+                while not (kind == tokenize.NAME and
+                           value == keyword and
+                           char == 0):
+                    kind, value, (line, char), _, _ = next(tokenGenerator)
+                start = line - 1, char
+                while not (kind == tokenize.DEDENT and
+                           value == '' and
+                           char == 0):
+                    kind, value, (line, char), _, _ = next(tokenGenerator)
+                end = line - 1, char
+                contexts.append(DocStyleContext(
+                    self.__source[start[0]:end[0]], start[0], keyword))
+        except StopIteration:
+            return contexts
+    
+    def __parseFunctions(self):
+        """
+        Private method to extract top-level functions.
+        
+        @return extracted function contexts (list of DocStyleContext)
+        """
+        if not self.__functionsCache:
+            self.__functionsCache = self.__parseTopLevel('def')
+        return self.__functionsCache
+    
+    def __parseClasses(self):
+        """
+        Private method to extract top-level classes.
+        
+        @return extracted class contexts (list of DocStyleContext)
+        """
+        if not self.__classesCache:
+            self.__classesCache = self.__parseTopLevel('class')
+        return self.__classesCache
+    
+    def __skipIndentedBlock(self, tokenGenerator):
+        """
+        Private method to skip over an indented block of source code.
+        
+        @param tokenGenerator token generator
+        @return last token of the indented block
+        """
+        kind, value, start, end, raw = next(tokenGenerator)
+        while kind != tokenize.INDENT:
+            kind, value, start, end, raw = next(tokenGenerator)
+        indent = 1
+        for kind, value, start, end, raw in tokenGenerator:
+            if kind == tokenize.INDENT:
+                indent += 1
+            elif kind == tokenize.DEDENT:
+                indent -= 1
+            if indent == 0:
+                return kind, value, start, end, raw
+    
+    def __parseMethods(self):
+        """
+        Private method to extract methods of all classes.
+        
+        @return extracted method contexts (list of DocStyleContext)
+        """
+        if not self.__methodsCache:
+            contexts = []
+            for classContext in self.__parseClasses():
+                tokenGenerator = tokenize.generate_tokens(
+                    StringIO(classContext.ssource()).readline)
+                kind, value, char = None, None, None
+                try:
+                    while True:
+                        start, end = None, None
+                        while not (kind == tokenize.NAME and value == 'def'):
+                            kind, value, (line, char), _, _ = \
+                                next(tokenGenerator)
+                        start = line - 1, char
+                        kind, value, (line, char), _, _ = \
+                            self.__skipIndentedBlock(tokenGenerator)
+                        end = line - 1, char
+                        startLine = classContext.start() + start[0]
+                        endLine = classContext.start() + end[0]
+                        contexts.append(
+                            DocStyleContext(self.__source[startLine:endLine],
+                                          startLine, "def"))
+                except StopIteration:
+                    pass
+            self.__methodsCache = contexts
+        
+        return self.__methodsCache
+
+    def __parseContexts(self, kind):
+        """
+        Private method to extract a context from the source.
+        
+        @param kind kind of context to extract (string)
+        @return requested contexts (list of DocStyleContext)
+        """
+        if kind == 'moduleDocstring':
+            return [DocStyleContext(self.__source, 0, "module")]
+        if kind == 'functionDocstring':
+            return self.__parseFunctions()
+        if kind == 'classDocstring':
+            return self.__parseClasses()
+        if kind == 'methodDocstring':
+            return self.__parseMethods()
+        if kind == 'defDocstring':
+            return self.__parseFunctions() + self.__parseMethods()
+        if kind == 'docstring':
+            return ([DocStyleContext(self.__source, 0, "module")] +
+                    self.__parseFunctions() +
+                    self.__parseClasses() +
+                    self.__parseMethods())
+        return []       # fall back
+    
+    ##################################################################
+    ## Checking functionality below (PEP-257)
+    ##################################################################
+
+    def __checkModulesDocstrings(self, docstringContext, context):
+        """
+        Private method to check, if the module has a docstring.
+        
+        @param docstringContext docstring context (DocStyleContext)
+        @param context context of the docstring (DocStyleContext)
+        """
+        if docstringContext is None:
+            self.__error(context.start(), 0, "D101")
+            return
+        
+        docstring = docstringContext.ssource()
+        if (not docstring or not docstring.strip() or
+                not docstring.strip('\'"')):
+            self.__error(context.start(), 0, "D101")
+    
+    def __checkFunctionDocstring(self, docstringContext, context):
+        """
+        Private method to check, that all public functions and methods
+        have a docstring.
+        
+        @param docstringContext docstring context (DocStyleContext)
+        @param context context of the docstring (DocStyleContext)
+        """
+        functionName = context.source()[0].lstrip().split()[1].split("(")[0]
+        if functionName.startswith('_') and not functionName.endswith('__'):
+            if self.__docType == "eric":
+                code = "D203"
+            else:
+                code = "D103"
+        else:
+            code = "D102"
+        
+        if docstringContext is None:
+            self.__error(context.start(), 0, code)
+            return
+        
+        docstring = docstringContext.ssource()
+        if (not docstring or not docstring.strip() or
+                not docstring.strip('\'"')):
+            self.__error(context.start(), 0, code)
+    
+    def __checkClassDocstring(self, docstringContext, context):
+        """
+        Private method to check, that all public functions and methods
+        have a docstring.
+        
+        @param docstringContext docstring context (DocStyleContext)
+        @param context context of the docstring (DocStyleContext)
+        """
+        className = context.source()[0].lstrip().split()[1].split("(")[0]
+        if className.startswith('_'):
+            if self.__docType == "eric":
+                code = "D205"
+            else:
+                code = "D105"
+        else:
+            code = "D104"
+        
+        if docstringContext is None:
+            self.__error(context.start(), 0, code)
+            return
+        
+        docstring = docstringContext.ssource()
+        if (not docstring or not docstring.strip() or
+                not docstring.strip('\'"')):
+            self.__error(context.start(), 0, code)
+    
+    def __checkTripleDoubleQuotes(self, docstringContext, context):
+        """
+        Private method to check, that all docstrings are surrounded
+        by triple double quotes.
+        
+        @param docstringContext docstring context (DocStyleContext)
+        @param context context of the docstring (DocStyleContext)
+        """
+        if docstringContext is None:
+            return
+        
+        docstring = docstringContext.ssource().strip()
+        if not docstring.startswith(('"""', 'r"""', 'u"""')):
+            self.__error(docstringContext.start(), 0, "D111")
+    
+    def __checkBackslashes(self, docstringContext, context):
+        """
+        Private method to check, that all docstrings containing
+        backslashes are surrounded by raw triple double quotes.
+        
+        @param docstringContext docstring context (DocStyleContext)
+        @param context context of the docstring (DocStyleContext)
+        """
+        if docstringContext is None:
+            return
+        
+        docstring = docstringContext.ssource().strip()
+        if "\\" in docstring and not docstring.startswith('r"""'):
+            self.__error(docstringContext.start(), 0, "D112")
+    
+    def __checkUnicode(self, docstringContext, context):
+        """
+        Private method to check, that all docstrings containing unicode
+        characters are surrounded by unicode triple double quotes.
+        
+        @param docstringContext docstring context (DocStyleContext)
+        @param context context of the docstring (DocStyleContext)
+        """
+        if docstringContext is None:
+            return
+        
+        docstring = docstringContext.ssource().strip()
+        if not docstring.startswith('u"""') and \
+                any(ord(char) > 127 for char in docstring):
+            self.__error(docstringContext.start(), 0, "D113")
+    
+    def __checkOneLiner(self, docstringContext, context):
+        """
+        Private method to check, that one-liner docstrings fit on
+        one line with quotes.
+        
+        @param docstringContext docstring context (DocStyleContext)
+        @param context context of the docstring (DocStyleContext)
+        """
+        if docstringContext is None:
+            return
+        
+        lines = docstringContext.source()
+        if len(lines) > 1:
+            nonEmptyLines = [l for l in lines if l.strip().strip('\'"')]
+            if len(nonEmptyLines) == 1:
+                modLen = len(context.indent() + '"""' +
+                             nonEmptyLines[0].strip() + '"""')
+                if context.contextType() != "module":
+                    modLen += 4
+                if not nonEmptyLines[0].strip().endswith("."):
+                    # account for a trailing dot
+                    modLen += 1
+                if modLen <= self.__maxLineLength:
+                    self.__error(docstringContext.start(), 0, "D121")
+    
+    def __checkIndent(self, docstringContext, context):
+        """
+        Private method to check, that docstrings are properly indented.
+        
+        @param docstringContext docstring context (DocStyleContext)
+        @param context context of the docstring (DocStyleContext)
+        """
+        if docstringContext is None:
+            return
+        
+        lines = docstringContext.source()
+        if len(lines) == 1:
+            return
+        
+        nonEmptyLines = [l.rstrip() for l in lines[1:] if l.strip()]
+        if not nonEmptyLines:
+            return
+        
+        indent = min([len(l) - len(l.strip()) for l in nonEmptyLines])
+        if context.contextType() == "module":
+            expectedIndent = 0
+        else:
+            expectedIndent = len(context.indent()) + 4
+        if indent != expectedIndent:
+            self.__error(docstringContext.start(), 0, "D122")
+    
+    def __checkEndsWithPeriod(self, docstringContext, context):
+        """
+        Private method to check, that docstring summaries end with a period.
+        
+        @param docstringContext docstring context (DocStyleContext)
+        @param context context of the docstring (DocStyleContext)
+        """
+        if docstringContext is None:
+            return
+        
+        summary, lineNumber = self.__getSummaryLine(docstringContext)
+        if not summary.endswith("."):
+            self.__error(docstringContext.start() + lineNumber, 0, "D131")
+    
+    def __checkImperativeMood(self, docstringContext, context):
+        """
+        Private method to check, that docstring summaries are in
+        imperative mood.
+        
+        @param docstringContext docstring context (DocStyleContext)
+        @param context context of the docstring (DocStyleContext)
+        """
+        if docstringContext is None:
+            return
+        
+        summary, lineNumber = self.__getSummaryLine(docstringContext)
+        firstWord = summary.strip().split()[0]
+        if firstWord.endswith("s") and not firstWord.endswith("ss"):
+            self.__error(docstringContext.start() + lineNumber, 0, "D132")
+    
+    def __checkNoSignature(self, docstringContext, context):
+        """
+        Private method to check, that docstring summaries don't repeat
+        the function's signature.
+        
+        @param docstringContext docstring context (DocStyleContext)
+        @param context context of the docstring (DocStyleContext)
+        """
+        if docstringContext is None:
+            return
+        
+        functionName = context.source()[0].lstrip().split()[1].split("(")[0]
+        summary, lineNumber = self.__getSummaryLine(docstringContext)
+        if functionName + "(" in summary.replace(" ", "") and \
+                not functionName + "()" in summary.replace(" ", ""):
+            # report only, if it is not an abbreviated form (i.e. function() )
+            self.__error(docstringContext.start() + lineNumber, 0, "D133")
+    
+    def __checkReturnType(self, docstringContext, context):
+        """
+        Private method to check, that docstrings mention the return value type.
+        
+        @param docstringContext docstring context (DocStyleContext)
+        @param context context of the docstring (DocStyleContext)
+        """
+        if docstringContext is None:
+            return
+        
+        if "return" not in docstringContext.ssource().lower():
+            tokens = list(
+                tokenize.generate_tokens(StringIO(context.ssource()).readline))
+            return_ = [tokens[i + 1][0] for i,  token in enumerate(tokens)
+                       if token[1] == "return"]
+            if (set(return_) -
+                    set([tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE]) !=
+                    set([])):
+                self.__error(docstringContext.end(), 0, "D134")
+    
+    def __checkNoBlankLineBefore(self, docstringContext, context):
+        """
+        Private method to check, that function/method docstrings are not
+        preceded by a blank line.
+        
+        @param docstringContext docstring context (DocStyleContext)
+        @param context context of the docstring (DocStyleContext)
+        """
+        if docstringContext is None:
+            return
+        
+        contextLines = context.source()
+        cti = 0
+        while cti < len(contextLines) and \
+                not contextLines[cti].strip().startswith(
+                ('"""', 'r"""', 'u"""', "'''", "r'''", "u'''")):
+            cti += 1
+        if cti == len(contextLines):
+            return
+        
+        if not contextLines[cti - 1].strip():
+            self.__error(docstringContext.start(), 0, "D141")
+    
+    def __checkBlankBeforeAndAfterClass(self, docstringContext, context):
+        """
+        Private method to check, that class docstrings have one
+        blank line around them.
+        
+        @param docstringContext docstring context (DocStyleContext)
+        @param context context of the docstring (DocStyleContext)
+        """
+        if docstringContext is None:
+            return
+        
+        contextLines = context.source()
+        cti = 0
+        while cti < len(contextLines) and \
+            not contextLines[cti].strip().startswith(
+                ('"""', 'r"""', 'u"""', "'''", "r'''", "u'''")):
+            cti += 1
+        if cti == len(contextLines):
+            return
+        
+        start = cti
+        if contextLines[cti].strip() in (
+                '"""', 'r"""', 'u"""', "'''", "r'''", "u'''"):
+            # it is a multi line docstring
+            cti += 1
+        
+        while cti < len(contextLines) and \
+                not contextLines[cti].strip().endswith(('"""', "'''")):
+            cti += 1
+        end = cti
+        if cti >= len(contextLines) - 1:
+            return
+        
+        if contextLines[start - 1].strip():
+            self.__error(docstringContext.start(), 0, "D142")
+        if contextLines[end + 1].strip():
+            self.__error(docstringContext.end(), 0, "D143")
+    
+    def __checkBlankAfterSummary(self, docstringContext, context):
+        """
+        Private method to check, that docstring summaries are followed
+        by a blank line.
+        
+        @param docstringContext docstring context (DocStyleContext)
+        @param context context of the docstring (DocStyleContext)
+        """
+        if docstringContext is None:
+            return
+        
+        docstrings = docstringContext.source()
+        if len(docstrings) <= 3:
+            # correct/invalid one-liner
+            return
+        
+        summary, lineNumber = self.__getSummaryLine(docstringContext)
+        if len(docstrings) > 2:
+            if docstrings[lineNumber + 1].strip():
+                self.__error(docstringContext.start() + lineNumber, 0, "D144")
+    
+    def __checkBlankAfterLastParagraph(self, docstringContext, context):
+        """
+        Private method to check, that the last paragraph of docstrings is
+        followed by a blank line.
+        
+        @param docstringContext docstring context (DocStyleContext)
+        @param context context of the docstring (DocStyleContext)
+        """
+        if docstringContext is None:
+            return
+        
+        docstrings = docstringContext.source()
+        if len(docstrings) <= 3:
+            # correct/invalid one-liner
+            return
+        
+        if docstrings[-2].strip():
+            self.__error(docstringContext.end(), 0, "D145")
+    
+    ##################################################################
+    ## Checking functionality below (eric specific ones)
+    ##################################################################
+
+    def __checkEricQuotesOnSeparateLines(self, docstringContext, context):
+        """
+        Private method to check, that leading and trailing quotes are on
+        a line by themselves.
+        
+        @param docstringContext docstring context (DocStyleContext)
+        @param context context of the docstring (DocStyleContext)
+        """
+        if docstringContext is None:
+            return
+        
+        lines = docstringContext.source()
+        if lines[0].strip().strip('ru"\''):
+            self.__error(docstringContext.start(), 0, "D221")
+        if lines[-1].strip().strip('"\''):
+            self.__error(docstringContext.end(), 0, "D222")
+    
+    def __checkEricEndsWithPeriod(self, docstringContext, context):
+        """
+        Private method to check, that docstring summaries end with a period.
+        
+        @param docstringContext docstring context (DocStyleContext)
+        @param context context of the docstring (DocStyleContext)
+        """
+        if docstringContext is None:
+            return
+        
+        summaryLines, lineNumber = self.__getSummaryLines(docstringContext)
+        if summaryLines[-1].lstrip().startswith("@"):
+            summaryLines.pop(-1)
+        summary = " ".join([s.strip() for s in summaryLines if s])
+        if not summary.endswith(".") and \
+                not summary.split(None, 1)[0].lower() == "constructor":
+            self.__error(
+                docstringContext.start() + lineNumber + len(summaryLines) - 1,
+                0, "D231")
+    
+    def __checkEricReturn(self, docstringContext, context):
+        """
+        Private method to check, that docstrings contain an &#64;return line
+        if they return anything and don't otherwise.
+        
+        @param docstringContext docstring context (DocStyleContext)
+        @param context context of the docstring (DocStyleContext)
+        """
+        if docstringContext is None:
+            return
+        
+        tokens = list(
+            tokenize.generate_tokens(StringIO(context.ssource()).readline))
+        return_ = [tokens[i + 1][0] for i,  token in enumerate(tokens)
+                   if token[1] in ("return", "yield")]
+        if "@return" not in docstringContext.ssource():
+            if (set(return_) -
+                    set([tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE]) !=
+                    set([])):
+                self.__error(docstringContext.end(), 0, "D234")
+        else:
+            if (set(return_) -
+                    set([tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE]) ==
+                    set([])):
+                self.__error(docstringContext.end(), 0, "D235")
+    
+    def __checkEricFunctionArguments(self, docstringContext, context):
+        """
+        Private method to check, that docstrings contain an &#64;param and/or
+        &#64;keyparam line for each argument.
+        
+        @param docstringContext docstring context (DocStyleContext)
+        @param context context of the docstring (DocStyleContext)
+        """
+        if docstringContext is None:
+            return
+        
+        try:
+            tree = ast.parse(context.ssource())
+        except (SyntaxError, TypeError):
+            return
+        if (isinstance(tree, ast.Module) and len(tree.body) == 1 and
+                isinstance(tree.body[0], ast.FunctionDef)):
+            functionDef = tree.body[0]
+            argNames, kwNames = self.__getArgNames(functionDef)
+            if "self" in argNames:
+                argNames.remove("self")
+            if "cls" in argNames:
+                argNames.remove("cls")
+            
+            docstring = docstringContext.ssource()
+            if (docstring.count("@param") + docstring.count("@keyparam") <
+                    len(argNames + kwNames)):
+                self.__error(docstringContext.end(), 0, "D236")
+            elif (docstring.count("@param") + docstring.count("@keyparam") >
+                    len(argNames + kwNames)):
+                self.__error(docstringContext.end(), 0, "D237")
+            else:
+                # extract @param and @keyparam from docstring
+                args = []
+                kwargs = []
+                for line in docstringContext.source():
+                    if line.strip().startswith(("@param", "@keyparam")):
+                        at, name = line.strip().split(None, 2)[:2]
+                        if at == "@keyparam":
+                            kwargs.append(name.lstrip("*"))
+                        args.append(name.lstrip("*"))
+                
+                # do the checks
+                for name in kwNames:
+                    if name not in kwargs:
+                        self.__error(docstringContext.end(), 0, "D238")
+                        return
+                if argNames + kwNames != args:
+                    self.__error(docstringContext.end(), 0, "D239")
+    
+    def __checkEricException(self, docstringContext, context):
+        """
+        Private method to check, that docstrings contain an &#64;exception line
+        if they raise an exception and don't otherwise.
+        
+        @param docstringContext docstring context (DocStyleContext)
+        @param context context of the docstring (DocStyleContext)
+        """
+        if docstringContext is None:
+            return
+        
+        tokens = list(
+            tokenize.generate_tokens(StringIO(context.ssource()).readline))
+        exception = [tokens[i + 1][0] for i,  token in enumerate(tokens)
+                     if token[1] == "raise"]
+        if "@exception" not in docstringContext.ssource() and \
+                "@throws" not in docstringContext.ssource() and \
+                "@raise" not in docstringContext.ssource():
+            if (set(exception) -
+                    set([tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE]) !=
+                    set([])):
+                self.__error(docstringContext.end(), 0, "D250")
+        else:
+            if (set(exception) -
+                    set([tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE]) ==
+                    set([])):
+                self.__error(docstringContext.end(), 0, "D251")
+    
+    def __checkEricBlankAfterSummary(self, docstringContext, context):
+        """
+        Private method to check, that docstring summaries are followed
+        by a blank line.
+        
+        @param docstringContext docstring context (DocStyleContext)
+        @param context context of the docstring (DocStyleContext)
+        """
+        if docstringContext is None:
+            return
+        
+        docstrings = docstringContext.source()
+        if len(docstrings) <= 3:
+            # correct/invalid one-liner
+            return
+        
+        summaryLines, lineNumber = self.__getSummaryLines(docstringContext)
+        if len(docstrings) - 2 > lineNumber + len(summaryLines) - 1:
+            if docstrings[lineNumber + len(summaryLines)].strip():
+                self.__error(docstringContext.start() + lineNumber, 0, "D246")
+    
+    def __checkEricNoBlankBeforeAndAfterClassOrFunction(
+            self, docstringContext, context):
+        """
+        Private method to check, that class and function/method docstrings
+        have no blank line around them.
+        
+        @param docstringContext docstring context (DocStyleContext)
+        @param context context of the docstring (DocStyleContext)
+        """
+        if docstringContext is None:
+            return
+        
+        contextLines = context.source()
+        isClassContext = contextLines[0].lstrip().startswith("class ")
+        cti = 0
+        while cti < len(contextLines) and \
+            not contextLines[cti].strip().startswith(
+                ('"""', 'r"""', 'u"""', "'''", "r'''", "u'''")):
+            cti += 1
+        if cti == len(contextLines):
+            return
+        
+        start = cti
+        if contextLines[cti].strip() in (
+                '"""', 'r"""', 'u"""', "'''", "r'''", "u'''"):
+            # it is a multi line docstring
+            cti += 1
+        
+        while cti < len(contextLines) and \
+                not contextLines[cti].strip().endswith(('"""', "'''")):
+            cti += 1
+        end = cti
+        if cti >= len(contextLines) - 1:
+            return
+        
+        if isClassContext:
+            if not contextLines[start - 1].strip():
+                self.__error(docstringContext.start(), 0, "D242")
+            if not contextLines[end + 1].strip():
+                self.__error(docstringContext.end(), 0, "D243")
+        else:
+            if not contextLines[start - 1].strip():
+                self.__error(docstringContext.start(), 0, "D244")
+            if not contextLines[end + 1].strip():
+                self.__error(docstringContext.end(), 0, "D245")
+    
+    def __checkEricNBlankAfterLastParagraph(self, docstringContext, context):
+        """
+        Private method to check, that the last paragraph of docstrings is
+        not followed by a blank line.
+        
+        @param docstringContext docstring context (DocStyleContext)
+        @param context context of the docstring (DocStyleContext)
+        """
+        if docstringContext is None:
+            return
+        
+        docstrings = docstringContext.source()
+        if len(docstrings) <= 3:
+            # correct/invalid one-liner
+            return
+        
+        if not docstrings[-2].strip():
+            self.__error(docstringContext.end(), 0, "D247")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/CheckerPlugins/CodeStyleChecker/NamingStyleChecker.py	Fri Oct 04 14:26:08 2013 +0200
@@ -0,0 +1,460 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2013 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a checker for PEP-8 naming conventions.
+"""
+
+import collections
+import ast
+import re
+import os
+
+from PyQt4.QtCore import QT_TRANSLATE_NOOP, QCoreApplication
+
+
+class NamingStyleChecker(object):
+    """
+    Class implementing a checker for PEP-8 naming conventions.
+    """
+    LowercaseRegex = re.compile(r"[_a-z][_a-z0-9]*$")
+    UppercaseRegexp = re.compile(r"[_A-Z][_A-Z0-9]*$")
+    CamelcaseRegexp = re.compile(r"_?[A-Z][a-zA-Z0-9]*$")
+    MixedcaseRegexp = re.compile(r"_?[a-z][a-zA-Z0-9]*$")
+    
+    Codes = [
+        "N801", "N802", "N803", "N804", "N805", "N806", "N807", "N808",
+        "N811", "N812", "N813", "N814", "N821", "N831"
+    ]
+    Messages = {
+        "N801": QT_TRANSLATE_NOOP("NamingStyleChecker",
+            "class names should use CapWords convention"),
+        "N802": QT_TRANSLATE_NOOP("NamingStyleChecker",
+            "function name should be lowercase"),
+        "N803": QT_TRANSLATE_NOOP("NamingStyleChecker",
+            "argument name should be lowercase"),
+        "N804": QT_TRANSLATE_NOOP("NamingStyleChecker",
+            "first argument of a class method should be named 'cls'"),
+        "N805": QT_TRANSLATE_NOOP("NamingStyleChecker",
+            "first argument of a method should be named 'self'"),
+        "N806": QT_TRANSLATE_NOOP("NamingStyleChecker",
+            "first argument of a static method should not be named"
+            " 'self' or 'cls"),
+        "N807": QT_TRANSLATE_NOOP("NamingStyleChecker",
+            "module names should be lowercase"),
+        "N808": QT_TRANSLATE_NOOP("NamingStyleChecker",
+            "package names should be lowercase"),
+        "N811": QT_TRANSLATE_NOOP("NamingStyleChecker",
+            "constant imported as non constant"),
+        "N812": QT_TRANSLATE_NOOP("NamingStyleChecker",
+            "lowercase imported as non lowercase"),
+        "N813": QT_TRANSLATE_NOOP("NamingStyleChecker",
+            "camelcase imported as lowercase"),
+        "N814": QT_TRANSLATE_NOOP("NamingStyleChecker",
+            "camelcase imported as constant"),
+        "N821": QT_TRANSLATE_NOOP("NamingStyleChecker",
+            "variable in function should be lowercase"),
+        "N831": QT_TRANSLATE_NOOP("NamingStyleChecker",
+            "names 'l', 'O' and 'I' should be avoided"),
+    }
+    
+    def __init__(self, tree, filename, options):
+        """
+        Constructor (according to 'extended' pep8.py API)
+        
+        @param tree AST tree of the source file
+        @param filename name of the source file (string)
+        @param options options as parsed by pep8.StyleGuide
+        """
+        self.__parents = collections.deque()
+        self.__tree = tree
+        self.__filename = filename
+        
+        self.__checkersWithCodes = {
+            "classdef": [
+                (self.__checkClassName, ("N801",)),
+                (self.__checkNameToBeAvoided, ("N831",)),
+            ],
+            "functiondef": [
+                (self.__checkFuntionName, ("N802",)),
+                (self.__checkFunctionArgumentNames,
+                    ("N803", "N804", "N805", "N806")),
+                (self.__checkNameToBeAvoided, ("N831",)),
+            ],
+            "assign": [
+                (self.__checkVariablesInFunction, ("N821",)),
+                (self.__checkNameToBeAvoided, ("N831",)),
+            ],
+            "importfrom": [
+                (self.__checkImportAs, ("N811", "N812", "N813", "N814")),
+            ],
+            "module": [
+                (self.__checkModule, ("N807", "N808")),
+            ],
+        }
+        
+        self.__checkers = {}
+        for key, checkers in self.__checkersWithCodes.items():
+            for checker, codes in checkers:
+                if any(not (code and options.ignore_code(code))
+                        for code in codes):
+                    if key not in self.__checkers:
+                        self.__checkers[key] = []
+                    self.__checkers[key].append(checker)
+
+    def run(self):
+        """
+        Public method run by the pep8.py checker.
+        
+        @return tuple giving line number, offset within line, code and
+            checker function
+        """
+        if self.__tree and self.__checkers:
+            return self.__visitTree(self.__tree)
+        else:
+            return ()
+    
+    @classmethod
+    def getMessage(cls, code, *args):
+        """
+        Class method to get a translated and formatted message for a
+        given code.
+        
+        @param code message code (string)
+        @param args arguments for a formatted message (list)
+        @return translated and formatted message (string)
+        """
+        if code in cls.Messages:
+            return code + " " + QCoreApplication.translate("NamingStyleChecker",
+                cls.Messages[code]).format(*args)
+        else:
+            return code + " " + QCoreApplication.translate("NamingStyleChecker",
+                "no message for this code defined")
+    
+    def __visitTree(self, node):
+        """
+        Private method to scan the given AST tree.
+        
+        @param node AST tree node to scan
+        @return tuple giving line number, offset within line, code and
+            checker function
+        """
+        for error in self.__visitNode(node):
+            yield error
+        self.__parents.append(node)
+        for child in ast.iter_child_nodes(node):
+            for error in self.__visitTree(child):
+                yield error
+        self.__parents.pop()
+    
+    def __visitNode(self, node):
+        """
+        Private method to inspect the given AST node.
+        
+        @param node AST tree node to inspect
+        @return tuple giving line number, offset within line, code and
+            checker function
+        """
+        if isinstance(node, ast.ClassDef):
+            self.__tagClassFunctions(node)
+        elif isinstance(node, ast.FunctionDef):
+            self.__findGlobalDefs(node)
+        
+        checkerName = node.__class__.__name__.lower()
+        if checkerName in self.__checkers:
+            for checker in self.__checkers[checkerName]:
+                for error in checker(node, self.__parents):
+                    yield error + (self.__checkers[checkerName],)
+    
+    def __tagClassFunctions(self, classNode):
+        """
+        Private method to tag functions if they are methods, class methods or
+        static methods.
+        
+        @param classNode AST tree node to tag
+        """
+        # try to find all 'old style decorators' like
+        # m = staticmethod(m)
+        lateDecoration = {}
+        for node in ast.iter_child_nodes(classNode):
+            if not (isinstance(node, ast.Assign) and
+                    isinstance(node.value, ast.Call) and
+                    isinstance(node.value.func, ast.Name)):
+                continue
+            funcName = node.value.func.id
+            if funcName in ("classmethod", "staticmethod"):
+                meth = (len(node.value.args) == 1 and node.value.args[0])
+                if isinstance(meth, ast.Name):
+                    lateDecoration[meth.id] = funcName
+
+        # iterate over all functions and tag them
+        for node in ast.iter_child_nodes(classNode):
+            if not isinstance(node, ast.FunctionDef):
+                continue
+            
+            node.function_type = 'method'
+            if node.name == "__new__":
+                node.function_type = "classmethod"
+            
+            if node.name in lateDecoration:
+                node.function_type = lateDecoration[node.name]
+            elif node.decorator_list:
+                names = [d.id for d in node.decorator_list
+                         if isinstance(d, ast.Name) and
+                         d.id in ("classmethod", "staticmethod")]
+                if names:
+                    node.function_type = names[0]
+
+    def __findGlobalDefs(self, functionNode):
+        """
+        Private method amend a node with global definitions information.
+        
+        @param functionNode AST tree node to amend
+        """
+        globalNames = set()
+        nodesToCheck = collections.deque(ast.iter_child_nodes(functionNode))
+        while nodesToCheck:
+            node = nodesToCheck.pop()
+            if isinstance(node, ast.Global):
+                globalNames.update(node.names)
+
+            if not isinstance(node, (ast.FunctionDef, ast.ClassDef)):
+                nodesToCheck.extend(ast.iter_child_nodes(node))
+        functionNode.global_names = globalNames
+    
+    def __getArgNames(self, node):
+        """
+        Private method to get the argument names of a function node.
+        
+        @param node AST node to extract arguments names from
+        @return list of argument names (list of string)
+        """
+        posArgs = [arg.arg for arg in node.args.args]
+        kwOnly = [arg.arg for arg in node.args.kwonlyargs]
+        return posArgs + kwOnly
+    
+    def __error(self, node, code):
+        """
+        Private method to build the error information.
+        
+        @param node AST node to report an error for
+        @param code error code to report (string)
+        @return tuple giving line number, offset within line and error code
+            (integer, integer, string)
+        """
+        if isinstance(node, ast.Module):
+            lineno = 0
+            offset = 0
+        else:
+            lineno = node.lineno
+            offset = node.col_offset
+            if isinstance(node, ast.ClassDef):
+                lineno += len(node.decorator_list)
+                offset += 6
+            elif isinstance(node, ast.FunctionDef):
+                lineno += len(node.decorator_list)
+                offset += 4
+        return (lineno, offset, code)
+    
+    def __isNameToBeAvoided(self, name):
+        """
+        Private method to check, if the given name should be avoided.
+        
+        @param name name to be checked (string)
+        @return flag indicating to avoid it (boolen)
+        """
+        return name in ("l", "O", "I")
+    
+    def __checkNameToBeAvoided(self, node, parents):
+        """
+        Private class to check the given node for a name to be avoided (N831).
+        
+        @param node AST note to check
+        @param parents list of parent nodes
+        @return tuple giving line number, offset within line and error code
+            (integer, integer, string)
+        """
+        if isinstance(node, (ast.ClassDef, ast.FunctionDef)):
+            name = node.name
+            if self.__isNameToBeAvoided(name):
+                yield self.__error(node, "N831")
+                return
+        
+        if isinstance(node, ast.FunctionDef):
+            argNames = self.__getArgNames(node)
+            for arg in argNames:
+                if self.__isNameToBeAvoided(arg):
+                    yield self.__error(node, "N831")
+                    return
+        
+        if isinstance(node, ast.Assign):
+            for target in node.targets:
+                name = isinstance(target, ast.Name) and target.id
+                if not name:
+                    return
+                
+                if self.__isNameToBeAvoided(name):
+                    yield self.__error(node, "N831")
+                    return
+    
+    def __checkClassName(self, node, parents):
+        """
+        Private class to check the given node for class name
+        conventions (N801).
+        
+        Almost without exception, class names use the CapWords convention.
+        Classes for internal use have a leading underscore in addition.
+        
+        @param node AST note to check
+        @param parents list of parent nodes
+        @return tuple giving line number, offset within line and error code
+            (integer, integer, string)
+        """
+        if not self.CamelcaseRegexp.match(node.name):
+            yield self.__error(node, "N801")
+    
+    def __checkFuntionName(self, node, parents):
+        """
+        Private class to check the given node for function name
+        conventions (N802).
+        
+        Function names should be lowercase, with words separated by underscores
+        as necessary to improve readability. Functions <b>not</b> being
+        methods '__' in front and back are not allowed. Mixed case is allowed
+        only in contexts where that's already the prevailing style
+        (e.g. threading.py), to retain backwards compatibility.
+        
+        @param node AST note to check
+        @param parents list of parent nodes
+        @return tuple giving line number, offset within line and error code
+            (integer, integer, string)
+        """
+        functionType = getattr(node, "function_type", "function")
+        name = node.name
+        if (functionType == "function" and "__" in (name[:2], name[-2:])) or \
+                not self.LowercaseRegex.match(name):
+            yield self.__error(node, "N802")
+    
+    def __checkFunctionArgumentNames(self, node, parents):
+        """
+        Private class to check the argument names of functions
+        (N803, N804, N805, N806).
+        
+        The argument names of a function should be lowercase, with words
+        separated by underscores. A class method should have 'cls' as the
+        first argument. A method should have 'self' as the first argument.
+        
+        @param node AST note to check
+        @param parents list of parent nodes
+        @return tuple giving line number, offset within line and error code
+            (integer, integer, string)
+        """
+        if node.args.kwarg is not None:
+            if not self.LowercaseRegex.match(node.args.kwarg):
+                yield self.__error(node, "N803")
+                return
+        
+        if node.args.vararg is not None:
+            if not self.LowercaseRegex.match(node.args.vararg):
+                yield self.__error(node, "N803")
+                return
+        
+        argNames = self.__getArgNames(node)
+        functionType = getattr(node, "function_type", "function")
+        
+        if not argNames:
+            if functionType == "method":
+                yield self.__error(node, "N805")
+            elif functionType == "classmethod":
+                yield self.__error(node, "N804")
+            return
+        
+        if functionType == "method":
+            if argNames[0] != "self":
+                yield self.__error(node, "N805")
+        elif functionType == "classmethod":
+            if argNames[0] != "cls":
+                yield self.__error(node, "N804")
+        elif functionType == "staticmethod":
+            if argNames[0] in ("cls", "self"):
+                yield self.__error(node, "N806")
+        for arg in argNames:
+            if not self.LowercaseRegex.match(arg):
+                yield self.__error(node, "N803")
+                return
+    
+    def __checkVariablesInFunction(self, node, parents):
+        """
+        Private method to check local variables in functions (N821).
+        
+        Local variables in functions should be lowercase.
+        
+        @param node AST note to check
+        @param parents list of parent nodes
+        @return tuple giving line number, offset within line and error code
+            (integer, integer, string)
+        """
+        for parentFunc in reversed(parents):
+            if isinstance(parentFunc, ast.ClassDef):
+                return
+            if isinstance(parentFunc, ast.FunctionDef):
+                break
+        else:
+            return
+        for target in node.targets:
+            name = isinstance(target, ast.Name) and target.id
+            if not name or name in parentFunc.global_names:
+                return
+            
+            if not self.LowercaseRegex.match(name) and name[:1] != '_':
+                yield self.__error(target, "N821")
+    
+    def __checkModule(self, node, parents):
+        """
+        Private method to check module naming conventions (N807, N808).
+        
+        Module and package names should be lowercase.
+        
+        @param node AST note to check
+        @param parents list of parent nodes
+        @return tuple giving line number, offset within line and error code
+            (integer, integer, string)
+        """
+        if self.__filename:
+            moduleName = os.path.splitext(os.path.basename(self.__filename))[0]
+            if moduleName.lower() != moduleName:
+                yield self.__error(node, "N807")
+            
+            if moduleName == "__init__":
+                # we got a package
+                packageName = \
+                    os.path.split(os.path.dirname(self.__filename))[1]
+                if packageName.lower != packageName:
+                    yield self.__error(node, "N808")
+    
+    def __checkImportAs(self, node, parents):
+        """
+        Private method to check that imports don't change the
+        naming convention (N811, N812, N813, N814).
+        
+        @param node AST note to check
+        @param parents list of parent nodes
+        @return tuple giving line number, offset within line and error code
+            (integer, integer, string)
+        """
+        for name in node.names:
+            if not name.asname:
+                continue
+            
+            if self.UppercaseRegexp.match(name.name):
+                if not self.UppercaseRegexp.match(name.asname):
+                    yield self.__error(node, "N811")
+            elif self.LowercaseRegex.match(name.name):
+                if not self.LowercaseRegex.match(name.asname):
+                    yield self.__error(node, "N812")
+            elif self.LowercaseRegex.match(name.asname):
+                yield self.__error(node, "N813")
+            elif self.UppercaseRegexp.match(name.asname):
+                yield self.__error(node, "N814")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/CheckerPlugins/CodeStyleChecker/__init__.py	Fri Oct 04 14:26:08 2013 +0200
@@ -0,0 +1,8 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2011 - 2013 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Package containing the code style checker and fixer plug-in.
+"""
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/CheckerPlugins/CodeStyleChecker/pep8.py	Fri Oct 04 14:26:08 2013 +0200
@@ -0,0 +1,2075 @@
+# -*- coding: utf-8 -*-
+
+#
+# pep8.py - Check Python source code formatting, according to PEP 8
+# Copyright (C) 2006-2009 Johann C. Rocholl <johann@rocholl.net>
+# Copyright (C) 2009-2013 Florent Xicluna <florent.xicluna@gmail.com>
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation files
+# (the "Software"), to deal in the Software without restriction,
+# including without limitation the rights to use, copy, modify, merge,
+# publish, distribute, sublicense, and/or sell copies of the Software,
+# and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+"""
+Check Python source code formatting, according to PEP 8:
+http://www.python.org/dev/peps/pep-0008/
+
+For usage and a list of options, try this:
+$ python pep8.py -h
+
+This program and its regression test suite live here:
+http://github.com/jcrocholl/pep8
+
+Groups of errors and warnings:
+E errors
+W warnings
+100 indentation
+200 whitespace
+300 blank lines
+400 imports
+500 line length
+600 deprecation
+700 statements
+900 syntax error
+"""
+
+#
+# This is a modified version to make the original pep8.py better suitable
+# for being called from within the eric5 IDE. The modifications are as
+# follows:
+#
+# - made messages translatable via Qt
+# - added code for eric5 integration
+#
+# Copyright (c) 2011 - 2013 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+__version__ = '1.4.6'
+
+import os
+import sys
+import re
+import time
+import inspect
+import keyword
+import tokenize
+from optparse import OptionParser
+from fnmatch import fnmatch
+try:
+    from configparser import RawConfigParser
+    from io import TextIOWrapper
+except ImportError:
+    from ConfigParser import RawConfigParser            # __IGNORE_WARNING__
+
+from PyQt4.QtCore import QCoreApplication, QT_TRANSLATE_NOOP
+
+DEFAULT_EXCLUDE = '.svn,CVS,.bzr,.hg,.git,__pycache__'
+DEFAULT_IGNORE = 'E123,E226,E24'
+if sys.platform == 'win32':
+    DEFAULT_CONFIG = os.path.expanduser(r'~\.pep8')
+else:
+    DEFAULT_CONFIG = os.path.join(os.getenv('XDG_CONFIG_HOME') or
+                                  os.path.expanduser('~/.config'), 'pep8')
+PROJECT_CONFIG = ('setup.cfg', 'tox.ini', '.pep8')
+TESTSUITE_PATH = os.path.join(os.path.dirname(__file__), 'testsuite')
+MAX_LINE_LENGTH = 79
+REPORT_FORMAT = {
+    'default': '%(path)s:%(row)d:%(col)d: %(code)s %(text)s',
+    'pylint': '%(path)s:%(row)d: [%(code)s] %(text)s',
+}
+
+PyCF_ONLY_AST = 1024
+SINGLETONS = frozenset(['False', 'None', 'True'])
+KEYWORDS = frozenset(keyword.kwlist + ['print']) - SINGLETONS
+UNARY_OPERATORS = frozenset(['>>', '**', '*', '+', '-'])
+ARITHMETIC_OP = frozenset(['**', '*', '/', '//', '+', '-'])
+WS_OPTIONAL_OPERATORS = ARITHMETIC_OP.union(['^', '&', '|', '<<', '>>', '%'])
+WS_NEEDED_OPERATORS = frozenset([
+    '**=', '*=', '/=', '//=', '+=', '-=', '!=', '<>', '<', '>',
+    '%=', '^=', '&=', '|=', '==', '<=', '>=', '<<=', '>>=', '='])
+WHITESPACE = frozenset(' \t')
+SKIP_TOKENS = frozenset([tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE,
+                         tokenize.INDENT, tokenize.DEDENT])
+BENCHMARK_KEYS = ['directories', 'files', 'logical lines', 'physical lines']
+
+INDENT_REGEX = re.compile(r'([ \t]*)')
+RAISE_COMMA_REGEX = re.compile(r'raise\s+\w+\s*,')
+RERAISE_COMMA_REGEX = re.compile(r'raise\s+\w+\s*,\s*\w+\s*,\s*\w+')
+ERRORCODE_REGEX = re.compile(r'\b[A-Z]\d{3}\b')
+DOCSTRING_REGEX = re.compile(r'u?r?["\']')
+EXTRANEOUS_WHITESPACE_REGEX = re.compile(r'[[({] | []}),;:]')
+WHITESPACE_AFTER_COMMA_REGEX = re.compile(r'[,;:]\s*(?:  |\t)')
+COMPARE_SINGLETON_REGEX = re.compile(r'([=!]=)\s*(None|False|True)')
+COMPARE_TYPE_REGEX = re.compile(r'(?:[=!]=|is(?:\s+not)?)\s*type(?:s.\w+Type'
+                                r'|\s*\(\s*([^)]*[^ )])\s*\))')
+KEYWORD_REGEX = re.compile(r'(\s*)\b(?:%s)\b(\s*)' % r'|'.join(KEYWORDS))
+OPERATOR_REGEX = re.compile(r'(?:[^,\s])(\s*)(?:[-+*/|!<=>%&^]+)(\s*)')
+LAMBDA_REGEX = re.compile(r'\blambda\b')
+HUNK_REGEX = re.compile(r'^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@.*$')
+
+# Work around Python < 2.6 behaviour, which does not generate NL after
+# a comment which is on a line by itself.
+COMMENT_WITH_NL = tokenize.generate_tokens(['#\n'].pop).send(None)[1] == '#\n'
+
+
+##############################################################################
+# Helper functions for translated and formatted messages
+##############################################################################
+
+
+pep8_messages = {
+    "E101": QT_TRANSLATE_NOOP("pep8",
+        "indentation contains mixed spaces and tabs"),
+    "E111": QT_TRANSLATE_NOOP("pep8",
+        "indentation is not a multiple of four"),
+    "E112": QT_TRANSLATE_NOOP("pep8",
+        "expected an indented block"),
+    "E113": QT_TRANSLATE_NOOP("pep8",
+        "unexpected indentation"),
+    "E121": QT_TRANSLATE_NOOP("pep8",
+        "continuation line indentation is not a multiple of four"),
+    "E122": QT_TRANSLATE_NOOP("pep8",
+        "continuation line missing indentation or outdented"),
+    "E123": QT_TRANSLATE_NOOP("pep8",
+        "closing bracket does not match indentation of opening bracket's line"),
+    "E124": QT_TRANSLATE_NOOP("pep8",
+        "closing bracket does not match visual indentation"),
+    "E125": QT_TRANSLATE_NOOP("pep8",
+        "continuation line does not distinguish itself from next logical line"),
+    "E126": QT_TRANSLATE_NOOP("pep8",
+        "continuation line over-indented for hanging indent"),
+    "E127": QT_TRANSLATE_NOOP("pep8",
+        "continuation line over-indented for visual indent"),
+    "E128": QT_TRANSLATE_NOOP("pep8",
+        "continuation line under-indented for visual indent"),
+    "E133": QT_TRANSLATE_NOOP("pep8",
+        "closing bracket is missing indentation"),
+    "W191": QT_TRANSLATE_NOOP("pep8",
+        "indentation contains tabs"),
+    "E201": QT_TRANSLATE_NOOP("pep8",
+        "whitespace after '{0}'"),
+    "E202": QT_TRANSLATE_NOOP("pep8",
+        "whitespace before '{0}'"),
+    "E203": QT_TRANSLATE_NOOP("pep8",
+        "whitespace before '{0}'"),
+    "E211": QT_TRANSLATE_NOOP("pep8",
+        "whitespace before '{0}'"),
+    "E221": QT_TRANSLATE_NOOP("pep8",
+        "multiple spaces before operator"),
+    "E222": QT_TRANSLATE_NOOP("pep8",
+        "multiple spaces after operator"),
+    "E223": QT_TRANSLATE_NOOP("pep8",
+        "tab before operator"),
+    "E224": QT_TRANSLATE_NOOP("pep8",
+        "tab after operator"),
+    "E225": QT_TRANSLATE_NOOP("pep8",
+        "missing whitespace around operator"),
+    "E226": QT_TRANSLATE_NOOP("pep8",
+        "missing whitespace around arithmetic operator"),
+    "E227": QT_TRANSLATE_NOOP("pep8",
+        "missing whitespace around bitwise or shift operator"),
+    "E228": QT_TRANSLATE_NOOP("pep8",
+        "missing whitespace around modulo operator"),
+    "E231": QT_TRANSLATE_NOOP("pep8",
+        "missing whitespace after '{0}'"),
+    "E241": QT_TRANSLATE_NOOP("pep8",
+        "multiple spaces after '{0}'"),
+    "E242": QT_TRANSLATE_NOOP("pep8",
+        "tab after '{0}'"),
+    "E251": QT_TRANSLATE_NOOP("pep8",
+        "unexpected spaces around keyword / parameter equals"),
+    "E261": QT_TRANSLATE_NOOP("pep8",
+        "at least two spaces before inline comment"),
+    "E262": QT_TRANSLATE_NOOP("pep8",
+        "inline comment should start with '# '"),
+    "E271": QT_TRANSLATE_NOOP("pep8",
+        "multiple spaces after keyword"),
+    "E272": QT_TRANSLATE_NOOP("pep8",
+        "multiple spaces before keyword"),
+    "E273": QT_TRANSLATE_NOOP("pep8",
+        "tab after keyword"),
+    "E274": QT_TRANSLATE_NOOP("pep8",
+        "tab before keyword"),
+    "W291": QT_TRANSLATE_NOOP("pep8",
+        "trailing whitespace"),
+    "W292": QT_TRANSLATE_NOOP("pep8",
+        "no newline at end of file"),
+    "W293": QT_TRANSLATE_NOOP("pep8",
+        "blank line contains whitespace"),
+    "E301": QT_TRANSLATE_NOOP("pep8",
+        "expected 1 blank line, found 0"),
+    "E302": QT_TRANSLATE_NOOP("pep8",
+        "expected 2 blank lines, found {0}"),
+    "E303": QT_TRANSLATE_NOOP("pep8",
+        "too many blank lines ({0})"),
+    "E304": QT_TRANSLATE_NOOP("pep8",
+        "blank lines found after function decorator"),
+    "W391": QT_TRANSLATE_NOOP("pep8",
+        "blank line at end of file"),
+    "E401": QT_TRANSLATE_NOOP("pep8",
+        "multiple imports on one line"),
+    "E501": QT_TRANSLATE_NOOP("pep8",
+        "line too long ({0} > {1} characters)"),
+    "E502": QT_TRANSLATE_NOOP("pep8",
+        "the backslash is redundant between brackets"),
+    "W601": QT_TRANSLATE_NOOP("pep8",
+        ".has_key() is deprecated, use 'in'"),
+    "W602": QT_TRANSLATE_NOOP("pep8",
+        "deprecated form of raising exception"),
+    "W603": QT_TRANSLATE_NOOP("pep8",
+        "'<>' is deprecated, use '!='"),
+    "W604": QT_TRANSLATE_NOOP("pep8",
+        "backticks are deprecated, use 'repr()'"),
+    "E701": QT_TRANSLATE_NOOP("pep8",
+        "multiple statements on one line (colon)"),
+    "E702": QT_TRANSLATE_NOOP("pep8",
+        "multiple statements on one line (semicolon)"),
+    "E703": QT_TRANSLATE_NOOP("pep8",
+        "statement ends with a semicolon"),
+    "E711": QT_TRANSLATE_NOOP("pep8",
+        "comparison to {0} should be {1}"),
+    "E712": QT_TRANSLATE_NOOP("pep8",
+        "comparison to {0} should be {1}"),
+    "E721": QT_TRANSLATE_NOOP("pep8",
+        "do not compare types, use 'isinstance()'"),
+    "E901": QT_TRANSLATE_NOOP("pep8",
+        "{0}: {1}"),
+}
+
+pep8_messages_sample_args = {
+    "E201": ["([{"],
+    "E202": ["}])"],
+    "E203": [",;:"],
+    "E211": ["(["],
+    "E231": [",;:"],
+    "E241": [",;:"],
+    "E242": [",;:"],
+    "E302": [1],
+    "E303": [3],
+    "E501": [85, 79],
+    "E711": ["None", "'if cond is None:'"],
+    "E712": ["True", "'if cond is True:' or 'if cond:'"],
+    "E901": ["SyntaxError", "Invalid Syntax"],
+}
+
+
+def getMessage(code, *args):
+    """
+    Function to get a translated and formatted message for a given code.
+    
+    @param code message code (string)
+    @param args arguments for a formatted message (list)
+    @return translated and formatted message (string)
+    """
+    if code in pep8_messages:
+        return code + " " + QCoreApplication.translate("pep8",
+            pep8_messages[code]).format(*args)
+    else:
+        return code + " " + QCoreApplication.translate("pep8",
+            "no message for this code defined")
+
+##############################################################################
+# Plugins (check functions) for physical lines
+##############################################################################
+
+
+def tabs_or_spaces(physical_line, indent_char):
+    r"""
+    Never mix tabs and spaces.
+
+    The most popular way of indenting Python is with spaces only.  The
+    second-most popular way is with tabs only.  Code indented with a mixture
+    of tabs and spaces should be converted to using spaces exclusively.  When
+    invoking the Python command line interpreter with the -t option, it issues
+    warnings about code that illegally mixes tabs and spaces.  When using -tt
+    these warnings become errors.  These options are highly recommended!
+
+    Okay: if a == 0:\n        a = 1\n        b = 1
+    E101: if a == 0:\n        a = 1\n\tb = 1
+    """
+    indent = INDENT_REGEX.match(physical_line).group(1)
+    for offset, char in enumerate(indent):
+        if char != indent_char:
+            return offset, "E101"
+
+
+def tabs_obsolete(physical_line):
+    r"""
+    For new projects, spaces-only are strongly recommended over tabs.  Most
+    editors have features that make this easy to do.
+
+    Okay: if True:\n    return
+    W191: if True:\n\treturn
+    """
+    indent = INDENT_REGEX.match(physical_line).group(1)
+    if '\t' in indent:
+        return indent.index('\t'), "W191"
+
+
+def trailing_whitespace(physical_line):
+    r"""
+    JCR: Trailing whitespace is superfluous.
+    FBM: Except when it occurs as part of a blank line (i.e. the line is
+         nothing but whitespace). According to Python docs[1] a line with only
+         whitespace is considered a blank line, and is to be ignored. However,
+         matching a blank line to its indentation level avoids mistakenly
+         terminating a multi-line statement (e.g. class declaration) when
+         pasting code into the standard Python interpreter.
+
+         [1] http://docs.python.org/reference/lexical_analysis.html#blank-lines
+
+    The warning returned varies on whether the line itself is blank, for easier
+    filtering for those who want to indent their blank lines.
+
+    Okay: spam(1)\n#
+    W291: spam(1) \n#
+    W293: class Foo(object):\n    \n    bang = 12
+    """
+    physical_line = physical_line.rstrip('\n')    # chr(10), newline
+    physical_line = physical_line.rstrip('\r')    # chr(13), carriage return
+    physical_line = physical_line.rstrip('\x0c')  # chr(12), form feed, ^L
+    stripped = physical_line.rstrip(' \t\v')
+    if physical_line != stripped:
+        if stripped:
+            return len(stripped), "W291"
+        else:
+            return 0, "W293"
+
+
+def trailing_blank_lines(physical_line, lines, line_number):
+    r"""
+    JCR: Trailing blank lines are superfluous.
+
+    Okay: spam(1)
+    W391: spam(1)\n
+    """
+    if not physical_line.rstrip() and line_number == len(lines):
+        return 0, "W391"
+
+
+def missing_newline(physical_line):
+    """
+    JCR: The last line should have a newline.
+
+    Reports warning W292.
+    """
+    if physical_line.rstrip() == physical_line:
+        return len(physical_line), "W292"
+
+
+def maximum_line_length(physical_line, max_line_length):
+    """
+    Limit all lines to a maximum of 79 characters.
+
+    There are still many devices around that are limited to 80 character
+    lines; plus, limiting windows to 80 characters makes it possible to have
+    several windows side-by-side.  The default wrapping on such devices looks
+    ugly.  Therefore, please limit all lines to a maximum of 79 characters.
+    For flowing long blocks of text (docstrings or comments), limiting the
+    length to 72 characters is recommended.
+
+    Reports error E501.
+    """
+    line = physical_line.rstrip()
+    length = len(line)
+    if length > max_line_length and not noqa(line):
+        if hasattr(line, 'decode'):   # Python 2
+            # The line could contain multi-byte characters
+            try:
+                length = len(line.decode('utf-8'))
+            except UnicodeError:
+                pass
+        if length > max_line_length:
+            return max_line_length, "E501", length, max_line_length
+
+
+##############################################################################
+# Plugins (check functions) for logical lines
+##############################################################################
+
+
+def blank_lines(logical_line, blank_lines, indent_level, line_number,
+                previous_logical, previous_indent_level):
+    r"""
+    Separate top-level function and class definitions with two blank lines.
+
+    Method definitions inside a class are separated by a single blank line.
+
+    Extra blank lines may be used (sparingly) to separate groups of related
+    functions.  Blank lines may be omitted between a bunch of related
+    one-liners (e.g. a set of dummy implementations).
+
+    Use blank lines in functions, sparingly, to indicate logical sections.
+
+    Okay: def a():\n    pass\n\n\ndef b():\n    pass
+    Okay: def a():\n    pass\n\n\n# Foo\n# Bar\n\ndef b():\n    pass
+
+    E301: class Foo:\n    b = 0\n    def bar():\n        pass
+    E302: def a():\n    pass\n\ndef b(n):\n    pass
+    E303: def a():\n    pass\n\n\n\ndef b(n):\n    pass
+    E303: def a():\n\n\n\n    pass
+    E304: @decorator\n\ndef a():\n    pass
+    """
+    if line_number < 3 and not previous_logical:
+        return  # Don't expect blank lines before the first line
+    if previous_logical.startswith('@'):
+        if blank_lines:
+            yield 0, "E304"
+    elif blank_lines > 2 or (indent_level and blank_lines == 2):
+        yield 0, "E303", blank_lines
+    elif logical_line.startswith(('def ', 'class ', '@')):
+        if indent_level:
+            if not (blank_lines or previous_indent_level < indent_level or
+                    DOCSTRING_REGEX.match(previous_logical)):
+                yield 0, "E301"
+        elif blank_lines != 2:
+            yield 0, "E302", blank_lines
+
+
+def extraneous_whitespace(logical_line):
+    """
+    Avoid extraneous whitespace in the following situations:
+
+    - Immediately inside parentheses, brackets or braces.
+
+    - Immediately before a comma, semicolon, or colon.
+
+    Okay: spam(ham[1], {eggs: 2})
+    E201: spam( ham[1], {eggs: 2})
+    E201: spam(ham[ 1], {eggs: 2})
+    E201: spam(ham[1], { eggs: 2})
+    E202: spam(ham[1], {eggs: 2} )
+    E202: spam(ham[1 ], {eggs: 2})
+    E202: spam(ham[1], {eggs: 2 })
+
+    E203: if x == 4: print x, y; x, y = y , x
+    E203: if x == 4: print x, y ; x, y = y, x
+    E203: if x == 4 : print x, y; x, y = y, x
+    """
+    line = logical_line
+    for match in EXTRANEOUS_WHITESPACE_REGEX.finditer(line):
+        text = match.group()
+        char = text.strip()
+        found = match.start()
+        if text == char + ' ':
+            # assert char in '([{'
+            yield found + 1, "E201", char
+        elif line[found - 1] != ',':
+            code = ('E202' if char in '}])' else 'E203')  # if char in ',;:'
+            yield found, code, char
+
+
+def whitespace_around_keywords(logical_line):
+    r"""
+    Avoid extraneous whitespace around keywords.
+
+    Okay: True and False
+    E271: True and  False
+    E272: True  and False
+    E273: True and\tFalse
+    E274: True\tand False
+    """
+    for match in KEYWORD_REGEX.finditer(logical_line):
+        before, after = match.groups()
+
+        if '\t' in before:
+            yield match.start(1), "E274"
+        elif len(before) > 1:
+            yield match.start(1), "E272"
+
+        if '\t' in after:
+            yield match.start(2), "E273"
+        elif len(after) > 1:
+            yield match.start(2), "E271"
+
+
+def missing_whitespace(logical_line):
+    """
+    JCR: Each comma, semicolon or colon should be followed by whitespace.
+
+    Okay: [a, b]
+    Okay: (3,)
+    Okay: a[1:4]
+    Okay: a[:4]
+    Okay: a[1:]
+    Okay: a[1:4:2]
+    E231: ['a','b']
+    E231: foo(bar,baz)
+    E231: [{'a':'b'}]
+    """
+    line = logical_line
+    for index in range(len(line) - 1):
+        char = line[index]
+        if char in ',;:' and line[index + 1] not in WHITESPACE:
+            before = line[:index]
+            if char == ':' and before.count('[') > before.count(']') and \
+                    before.rfind('{') < before.rfind('['):
+                continue  # Slice syntax, no space required
+            if char == ',' and line[index + 1] == ')':
+                continue  # Allow tuple with only one element: (3,)
+            yield index, "E231", char
+
+
+def indentation(logical_line, previous_logical, indent_char,
+                indent_level, previous_indent_level):
+    r"""
+    Use 4 spaces per indentation level.
+
+    For really old code that you don't want to mess up, you can continue to
+    use 8-space tabs.
+
+    Okay: a = 1
+    Okay: if a == 0:\n    a = 1
+    E111:   a = 1
+
+    Okay: for item in items:\n    pass
+    E112: for item in items:\npass
+
+    Okay: a = 1\nb = 2
+    E113: a = 1\n    b = 2
+    """
+    if indent_char == ' ' and indent_level % 4:
+        yield 0, "E111"
+    indent_expect = previous_logical.endswith(':')
+    if indent_expect and indent_level <= previous_indent_level:
+        yield 0, "E112"
+    if indent_level > previous_indent_level and not indent_expect:
+        yield 0, "E113"
+
+
+def continued_indentation(logical_line, tokens, indent_level, hang_closing,
+                          noqa, verbose):
+    r"""
+    Continuation lines should align wrapped elements either vertically using
+    Python's implicit line joining inside parentheses, brackets and braces, or
+    using a hanging indent.
+
+    When using a hanging indent the following considerations should be applied:
+
+    - there should be no arguments on the first line, and
+
+    - further indentation should be used to clearly distinguish itself as a
+      continuation line.
+
+    Okay: a = (\n)
+    E123: a = (\n    )
+
+    Okay: a = (\n    42)
+    E121: a = (\n   42)
+    E122: a = (\n42)
+    E123: a = (\n    42\n    )
+    E124: a = (24,\n     42\n)
+    E125: if (a or\n    b):\n    pass
+    E126: a = (\n        42)
+    E127: a = (24,\n      42)
+    E128: a = (24,\n    42)
+    """
+    first_row = tokens[0][2][0]
+    nrows = 1 + tokens[-1][2][0] - first_row
+    if noqa or nrows == 1:
+        return
+
+    # indent_next tells us whether the next block is indented; assuming
+    # that it is indented by 4 spaces, then we should not allow 4-space
+    # indents on the final continuation line; in turn, some other
+    # indents are allowed to have an extra 4 spaces.
+    indent_next = logical_line.endswith(':')
+
+    row = depth = 0
+    # remember how many brackets were opened on each line
+    parens = [0] * nrows
+    # relative indents of physical lines
+    rel_indent = [0] * nrows
+    # visual indents
+    indent_chances = {}
+    last_indent = tokens[0][2]
+    indent = [last_indent[1]]
+    if verbose >= 3:
+        print(">>> " + tokens[0][4].rstrip())
+
+    for token_type, text, start, end, line in tokens:
+
+        last_token_multiline = (start[0] != end[0])
+        newline = row < start[0] - first_row
+        if newline:
+            row = start[0] - first_row
+            newline = (not last_token_multiline and
+                       token_type not in (tokenize.NL, tokenize.NEWLINE))
+
+        if newline:
+            # this is the beginning of a continuation line.
+            last_indent = start
+            if verbose >= 3:
+                print("... " + line.rstrip())
+
+            # record the initial indent.
+            rel_indent[row] = expand_indent(line) - indent_level
+
+            if depth:
+                # a bracket expression in a continuation line.
+                # find the line that it was opened on
+                for open_row in range(row - 1, -1, -1):
+                    if parens[open_row]:
+                        break
+            else:
+                # an unbracketed continuation line (ie, backslash)
+                open_row = 0
+            hang = rel_indent[row] - rel_indent[open_row]
+            close_bracket = (token_type == tokenize.OP and text in ']})')
+            visual_indent = (not close_bracket and hang > 0 and
+                             indent_chances.get(start[1]))
+
+            if close_bracket and indent[depth]:
+                # closing bracket for visual indent
+                if start[1] != indent[depth]:
+                    yield start, "E124"
+            elif close_bracket and not hang:
+                # closing bracket matches indentation of opening bracket's line
+                if hang_closing:
+                    yield start, "E133"
+            elif visual_indent is True:
+                # visual indent is verified
+                if not indent[depth]:
+                    indent[depth] = start[1]
+            elif visual_indent in (text, str):
+                # ignore token lined up with matching one from a previous line
+                pass
+            elif indent[depth] and start[1] < indent[depth]:
+                # visual indent is broken
+                yield start, "E128"
+            elif hang == 4 or (indent_next and rel_indent[row] == 8):
+                # hanging indent is verified
+                if close_bracket and not hang_closing:
+                    yield (start, "E123")
+            else:
+                # indent is broken
+                if hang <= 0:
+                    error = "E122"
+                elif indent[depth]:
+                    error = "E127"
+                elif hang % 4:
+                    error = "E121"
+                else:
+                    error = "E126"
+                yield start, error
+
+        # look for visual indenting
+        if (parens[row] and token_type not in (tokenize.NL, tokenize.COMMENT)
+                and not indent[depth]):
+            indent[depth] = start[1]
+            indent_chances[start[1]] = True
+            if verbose >= 4:
+                print("bracket depth %s indent to %s" % (depth, start[1]))
+        # deal with implicit string concatenation
+        elif (token_type in (tokenize.STRING, tokenize.COMMENT) or
+              text in ('u', 'ur', 'b', 'br')):
+            indent_chances[start[1]] = str
+        # special case for the "if" statement because len("if (") == 4
+        elif not indent_chances and not row and not depth and text == 'if':
+            indent_chances[end[1] + 1] = True
+
+        # keep track of bracket depth
+        if token_type == tokenize.OP:
+            if text in '([{':
+                depth += 1
+                indent.append(0)
+                parens[row] += 1
+                if verbose >= 4:
+                    print("bracket depth %s seen, col %s, visual min = %s" %
+                          (depth, start[1], indent[depth]))
+            elif text in ')]}' and depth > 0:
+                # parent indents should not be more than this one
+                prev_indent = indent.pop() or last_indent[1]
+                for d in range(depth):
+                    if indent[d] > prev_indent:
+                        indent[d] = 0
+                for ind in list(indent_chances):
+                    if ind >= prev_indent:
+                        del indent_chances[ind]
+                depth -= 1
+                if depth:
+                    indent_chances[indent[depth]] = True
+                for idx in range(row, -1, -1):
+                    if parens[idx]:
+                        parens[idx] -= 1
+                        rel_indent[row] = rel_indent[idx]
+                        break
+            assert len(indent) == depth + 1
+            if start[1] not in indent_chances:
+                # allow to line up tokens
+                indent_chances[start[1]] = text
+
+    if indent_next and expand_indent(line) == indent_level + 4:
+        yield last_indent, "E125"
+
+
+def whitespace_before_parameters(logical_line, tokens):
+    """
+    Avoid extraneous whitespace in the following situations:
+
+    - Immediately before the open parenthesis that starts the argument
+      list of a function call.
+
+    - Immediately before the open parenthesis that starts an indexing or
+      slicing.
+
+    Okay: spam(1)
+    E211: spam (1)
+
+    Okay: dict['key'] = list[index]
+    E211: dict ['key'] = list[index]
+    E211: dict['key'] = list [index]
+    """
+    prev_type, prev_text, __, prev_end, __ = tokens[0]
+    for index in range(1, len(tokens)):
+        token_type, text, start, end, __ = tokens[index]
+        if (token_type == tokenize.OP and
+            text in '([' and
+            start != prev_end and
+            (prev_type == tokenize.NAME or prev_text in '}])') and
+            # Syntax "class A (B):" is allowed, but avoid it
+            (index < 2 or tokens[index - 2][1] != 'class') and
+                # Allow "return (a.foo for a in range(5))"
+                not keyword.iskeyword(prev_text)):
+            yield prev_end, "E211", text
+        prev_type = token_type
+        prev_text = text
+        prev_end = end
+
+
+def whitespace_around_operator(logical_line):
+    """
+    Avoid extraneous whitespace in the following situations:
+
+    - More than one space around an assignment (or other) operator to
+      align it with another.
+
+    Okay: a = 12 + 3
+    E221: a = 4  + 5
+    E222: a = 4 +  5
+    E223: a = 4\t+ 5
+    E224: a = 4 +\t5
+    """
+    for match in OPERATOR_REGEX.finditer(logical_line):
+        before, after = match.groups()
+
+        if '\t' in before:
+            yield match.start(1), "E223"
+        elif len(before) > 1:
+            yield match.start(1), "E221"
+
+        if '\t' in after:
+            yield match.start(2), "E224"
+        elif len(after) > 1:
+            yield match.start(2), "E222"
+
+def missing_whitespace_around_operator(logical_line, tokens):
+    r"""
+    - Always surround these binary operators with a single space on
+      either side: assignment (=), augmented assignment (+=, -= etc.),
+      comparisons (==, <, >, !=, <>, <=, >=, in, not in, is, is not),
+      Booleans (and, or, not).
+
+    - Use spaces around arithmetic operators.
+
+    Okay: i = i + 1
+    Okay: submitted += 1
+    Okay: x = x * 2 - 1
+    Okay: hypot2 = x * x + y * y
+    Okay: c = (a + b) * (a - b)
+    Okay: foo(bar, key='word', *args, **kwargs)
+    Okay: alpha[:-i]
+
+    E225: i=i+1
+    E225: submitted +=1
+    E225: x = x /2 - 1
+    E225: z = x **y
+    E226: c = (a+b) * (a-b)
+    E226: hypot2 = x*x + y*y
+    E227: c = a|b
+    E228: msg = fmt%(errno, errmsg)
+    """
+    parens = 0
+    need_space = False
+    prev_type = tokenize.OP
+    prev_text = prev_end = None
+    for token_type, text, start, end, line in tokens:
+        if token_type in (tokenize.NL, tokenize.NEWLINE, tokenize.ERRORTOKEN):
+            # ERRORTOKEN is triggered by backticks in Python 3
+            continue
+        if text in ('(', 'lambda'):
+            parens += 1
+        elif text == ')':
+            parens -= 1
+        if need_space:
+            if start != prev_end:
+                # Found a (probably) needed space
+                if need_space is not True and not need_space[1]:
+                    yield need_space[0], "E225"
+                need_space = False
+            elif text == '>' and prev_text in ('<', '-'):
+                # Tolerate the "<>" operator, even if running Python 3
+                # Deal with Python 3's annotated return value "->"
+                pass
+            else:
+                if need_space is True or need_space[1]:
+                    # A needed trailing space was not found
+                    yield prev_end, "E225"
+                else:
+                    code = 'E226'
+                    if prev_text == '%':
+                        code = 'E228'
+                    elif prev_text not in ARITHMETIC_OP:
+                        code = 'E227'
+                    yield need_space[0], code
+                need_space = False
+        elif token_type == tokenize.OP and prev_end is not None:
+            if text == '=' and parens:
+                # Allow keyword args or defaults: foo(bar=None).
+                pass
+            elif text in WS_NEEDED_OPERATORS:
+                need_space = True
+            elif text in UNARY_OPERATORS:
+                # Check if the operator is being used as a binary operator
+                # Allow unary operators: -123, -x, +1.
+                # Allow argument unpacking: foo(*args, **kwargs).
+                if prev_type == tokenize.OP:
+                    binary_usage = (prev_text in '}])')
+                elif prev_type == tokenize.NAME:
+                    binary_usage = (prev_text not in KEYWORDS)
+                else:
+                    binary_usage = (prev_type not in SKIP_TOKENS)
+
+                if binary_usage:
+                    need_space = None
+            elif text in WS_OPTIONAL_OPERATORS:
+                need_space = None
+
+            if need_space is None:
+                # Surrounding space is optional, but ensure that
+                # trailing space matches opening space
+                need_space = (prev_end, start != prev_end)
+            elif need_space and start == prev_end:
+                # A needed opening space was not found
+                yield prev_end, "E225"
+                need_space = False
+        prev_type = token_type
+        prev_text = text
+        prev_end = end
+
+
+def whitespace_around_comma(logical_line):
+    """
+    Avoid extraneous whitespace in the following situations:
+
+    - More than one space around an assignment (or other) operator to
+      align it with another.
+
+    JCR: This should also be applied around comma etc.
+    Note: these checks are disabled by default
+
+    Okay: a = (1, 2)
+    E241: a = (1,  2)
+    E242: a = (1,\t2)
+    """
+    line = logical_line
+    for m in WHITESPACE_AFTER_COMMA_REGEX.finditer(line):
+        found = m.start() + 1
+        if '\t' in m.group():
+            yield found, "E242", m.group()[0]
+        else:
+            yield found, "E241", m.group()[0]
+
+
+def whitespace_around_named_parameter_equals(logical_line, tokens):
+    """
+    Don't use spaces around the '=' sign when used to indicate a
+    keyword argument or a default parameter value.
+
+    Okay: def complex(real, imag=0.0):
+    Okay: return magic(r=real, i=imag)
+    Okay: boolean(a == b)
+    Okay: boolean(a != b)
+    Okay: boolean(a <= b)
+    Okay: boolean(a >= b)
+
+    E251: def complex(real, imag = 0.0):
+    E251: return magic(r = real, i = imag)
+    """
+    parens = 0
+    no_space = False
+    prev_end = None
+    message = "E251"
+    for token_type, text, start, end, line in tokens:
+        if no_space:
+            no_space = False
+            if start != prev_end:
+                yield prev_end, message
+        elif token_type == tokenize.OP:
+            if text == '(':
+                parens += 1
+            elif text == ')':
+                parens -= 1
+            elif parens and text == '=':
+                no_space = True
+                if start != prev_end:
+                    yield prev_end, message
+        prev_end = end
+
+
+def whitespace_before_inline_comment(logical_line, tokens):
+    """
+    Separate inline comments by at least two spaces.
+
+    An inline comment is a comment on the same line as a statement.  Inline
+    comments should be separated by at least two spaces from the statement.
+    They should start with a # and a single space.
+
+    Okay: x = x + 1  # Increment x
+    Okay: x = x + 1    # Increment x
+    E261: x = x + 1 # Increment x
+    E262: x = x + 1  #Increment x
+    E262: x = x + 1  #  Increment x
+    """
+    prev_end = (0, 0)
+    for token_type, text, start, end, line in tokens:
+        if token_type == tokenize.COMMENT:
+            if not line[:start[1]].strip():
+                continue
+            if prev_end[0] == start[0] and start[1] < prev_end[1] + 2:
+                yield prev_end, "E261"
+            symbol, sp, comment = text.partition(' ')
+            if symbol not in ('#', '#:') or comment[:1].isspace():
+                yield start, "E262"
+        elif token_type != tokenize.NL:
+            prev_end = end
+
+
+def imports_on_separate_lines(logical_line):
+    r"""
+    Imports should usually be on separate lines.
+
+    Okay: import os\nimport sys
+    E401: import sys, os
+
+    Okay: from subprocess import Popen, PIPE
+    Okay: from myclas import MyClass
+    Okay: from foo.bar.yourclass import YourClass
+    Okay: import myclass
+    Okay: import foo.bar.yourclass
+    """
+    line = logical_line
+    if line.startswith('import '):
+        found = line.find(',')
+        if -1 < found and ';' not in line[:found]:
+            yield found, "E401"
+
+
+def compound_statements(logical_line):
+    r"""
+    Compound statements (multiple statements on the same line) are
+    generally discouraged.
+
+    While sometimes it's okay to put an if/for/while with a small body
+    on the same line, never do this for multi-clause statements. Also
+    avoid folding such long lines!
+
+    Okay: if foo == 'blah':\n    do_blah_thing()
+    Okay: do_one()
+    Okay: do_two()
+    Okay: do_three()
+
+    E701: if foo == 'blah': do_blah_thing()
+    E701: for x in lst: total += x
+    E701: while t < 10: t = delay()
+    E701: if foo == 'blah': do_blah_thing()
+    E701: else: do_non_blah_thing()
+    E701: try: something()
+    E701: finally: cleanup()
+    E701: if foo == 'blah': one(); two(); three()
+
+    E702: do_one(); do_two(); do_three()
+    E703: do_four();  # useless semicolon
+    """
+    line = logical_line
+    last_char = len(line) - 1
+    found = line.find(':')
+    while -1 < found < last_char:
+        before = line[:found]
+        if (before.count('{') <= before.count('}') and  # {'a': 1} (dict)
+            before.count('[') <= before.count(']') and  # [1:2] (slice)
+            before.count('(') <= before.count(')') and  # (Python 3 annotation)
+                not LAMBDA_REGEX.search(before)):       # lambda x: x
+            yield found, "E701"
+        found = line.find(':', found + 1)
+    found = line.find(';')
+    while -1 < found:
+        if found < last_char:
+            yield found, "E702"
+        else:
+            yield found, "E703"
+        found = line.find(';', found + 1)
+
+
+def explicit_line_join(logical_line, tokens):
+    r"""
+    Avoid explicit line join between brackets.
+
+    The preferred way of wrapping long lines is by using Python's implied line
+    continuation inside parentheses, brackets and braces.  Long lines can be
+    broken over multiple lines by wrapping expressions in parentheses.  These
+    should be used in preference to using a backslash for line continuation.
+
+    E502: aaa = [123, \\n       123]
+    E502: aaa = ("bbb " \\n       "ccc")
+
+    Okay: aaa = [123,\n       123]
+    Okay: aaa = ("bbb "\n       "ccc")
+    Okay: aaa = "bbb " \\n    "ccc"
+    """
+    prev_start = prev_end = parens = 0
+    backslash = None
+    for token_type, text, start, end, line in tokens:
+        if start[0] != prev_start and parens and backslash:
+            yield backslash, "E502"
+        if end[0] != prev_end:
+            if line.rstrip('\r\n').endswith('\\'):
+                backslash = (end[0], len(line.splitlines()[-1]) - 1)
+            else:
+                backslash = None
+            prev_start = prev_end = end[0]
+        else:
+            prev_start = start[0]
+        if token_type == tokenize.OP:
+            if text in '([{':
+                parens += 1
+            elif text in ')]}':
+                parens -= 1
+
+
+def comparison_to_singleton(logical_line, noqa):
+    """
+    Comparisons to singletons like None should always be done
+    with "is" or "is not", never the equality operators.
+
+    Okay: if arg is not None:
+    E711: if arg != None:
+    E712: if arg == True:
+
+    Also, beware of writing if x when you really mean if x is not None --
+    e.g. when testing whether a variable or argument that defaults to None was
+    set to some other value.  The other value might have a type (such as a
+    container) that could be false in a boolean context!
+    """
+    match = not noqa and COMPARE_SINGLETON_REGEX.search(logical_line)
+    if match:
+        same = (match.group(1) == '==')
+        singleton = match.group(2)
+        msg = "'if cond is %s:'" % (('' if same else 'not ') + singleton)
+        if singleton in ('None',):
+            code = 'E711'
+        else:
+            code = 'E712'
+            nonzero = ((singleton == 'True' and same) or
+                       (singleton == 'False' and not same))
+            msg += " or 'if %scond:'" % ('' if nonzero else 'not ')
+        yield match.start(1), code, singleton, msg
+
+
+def comparison_type(logical_line):
+    """
+    Object type comparisons should always use isinstance() instead of
+    comparing types directly.
+
+    Okay: if isinstance(obj, int):
+    E721: if type(obj) is type(1):
+
+    When checking if an object is a string, keep in mind that it might be a
+    unicode string too! In Python 2.3, str and unicode have a common base
+    class, basestring, so you can do:
+
+    Okay: if isinstance(obj, basestring):
+    Okay: if type(a1) is type(b1):
+    """
+    match = COMPARE_TYPE_REGEX.search(logical_line)
+    if match:
+        inst = match.group(1)
+        if inst and isidentifier(inst) and inst not in SINGLETONS:
+            return  # Allow comparison for types which are not obvious
+        yield match.start(), "E721"
+
+
+def python_3000_has_key(logical_line):
+    r"""
+    The {}.has_key() method is removed in the Python 3.
+    Use the 'in' operation instead.
+
+    Okay: if "alph" in d:\n    print d["alph"]
+    W601: assert d.has_key('alph')
+    """
+    pos = logical_line.find('.has_key(')
+    if pos > -1:
+        yield pos, "W601"
+
+
+def python_3000_raise_comma(logical_line):
+    """
+    When raising an exception, use "raise ValueError('message')"
+    instead of the older form "raise ValueError, 'message'".
+
+    The paren-using form is preferred because when the exception arguments
+    are long or include string formatting, you don't need to use line
+    continuation characters thanks to the containing parentheses.  The older
+    form is removed in Python 3.
+
+    Okay: raise DummyError("Message")
+    W602: raise DummyError, "Message"
+    """
+    match = RAISE_COMMA_REGEX.match(logical_line)
+    if match and not RERAISE_COMMA_REGEX.match(logical_line):
+        yield match.end() - 1, "W602"
+
+
+def python_3000_not_equal(logical_line):
+    """
+    != can also be written <>, but this is an obsolete usage kept for
+    backwards compatibility only. New code should always use !=.
+    The older syntax is removed in Python 3.
+
+    Okay: if a != 'no':
+    W603: if a <> 'no':
+    """
+    pos = logical_line.find('<>')
+    if pos > -1:
+        yield pos, "W603"
+
+
+def python_3000_backticks(logical_line):
+    """
+    Backticks are removed in Python 3.
+    Use repr() instead.
+
+    Okay: val = repr(1 + 2)
+    W604: val = `1 + 2`
+    """
+    pos = logical_line.find('`')
+    if pos > -1:
+        yield pos, "W604"
+
+
+##############################################################################
+# Helper functions
+##############################################################################
+
+
+if '' == ''.encode():
+    # Python 2: implicit encoding.
+    def readlines(filename):
+        f = open(filename)
+        try:
+            return f.readlines()
+        finally:
+            f.close()
+    isidentifier = re.compile(r'[a-zA-Z_]\w*').match
+    stdin_get_value = sys.stdin.read
+else:
+    # Python 3
+    def readlines(filename):                            # __IGNORE_WARNING__
+        f = open(filename, 'rb')
+        try:
+            coding, lines = tokenize.detect_encoding(f.readline)
+            f = TextIOWrapper(f, coding, line_buffering=True)
+            return [l.decode(coding) for l in lines] + f.readlines()
+        except (LookupError, SyntaxError, UnicodeError):
+            f.close()
+            # Fall back if files are improperly declared
+            f = open(filename, encoding='latin-1')
+            return f.readlines()
+        finally:
+            f.close()
+    isidentifier = str.isidentifier
+
+    def stdin_get_value():
+        return TextIOWrapper(sys.stdin.buffer, errors='ignore').read()
+readlines.__doc__ = "    Read the source code."
+noqa = re.compile(r'# no(?:qa|pep8)\b', re.I).search
+
+
+def expand_indent(line):
+    r"""
+    Return the amount of indentation.
+    Tabs are expanded to the next multiple of 8.
+
+    >>> expand_indent('    ')
+    4
+    >>> expand_indent('\t')
+    8
+    >>> expand_indent('    \t')
+    8
+    >>> expand_indent('       \t')
+    8
+    >>> expand_indent('        \t')
+    16
+    """
+    if '\t' not in line:
+        return len(line) - len(line.lstrip())
+    result = 0
+    for char in line:
+        if char == '\t':
+            result = result // 8 * 8 + 8
+        elif char == ' ':
+            result += 1
+        else:
+            break
+    return result
+
+
+def mute_string(text):
+    """
+    Replace contents with 'xxx' to prevent syntax matching.
+
+    >>> mute_string('"abc"')
+    '"xxx"'
+    >>> mute_string("'''abc'''")
+    "'''xxx'''"
+    >>> mute_string("r'abc'")
+    "r'xxx'"
+    """
+    # String modifiers (e.g. u or r)
+    start = text.index(text[-1]) + 1
+    end = len(text) - 1
+    # Triple quotes
+    if text[-3:] in ('"""', "'''"):
+        start += 2
+        end -= 2
+    return text[:start] + 'x' * (end - start) + text[end:]
+
+
+def parse_udiff(diff, patterns=None, parent='.'):
+    """Return a dictionary of matching lines."""
+    # For each file of the diff, the entry key is the filename,
+    # and the value is a set of row numbers to consider.
+    rv = {}
+    path = nrows = None
+    for line in diff.splitlines():
+        if nrows:
+            if line[:1] != '-':
+                nrows -= 1
+            continue
+        if line[:3] == '@@ ':
+            hunk_match = HUNK_REGEX.match(line)
+            row, nrows = [int(g or '1') for g in hunk_match.groups()]
+            rv[path].update(range(row, row + nrows))
+        elif line[:3] == '+++':
+            path = line[4:].split('\t', 1)[0]
+            if path[:2] == 'b/':
+                path = path[2:]
+            rv[path] = set()
+    return dict([(os.path.join(parent, path), rows)
+                 for (path, rows) in rv.items()
+                 if rows and filename_match(path, patterns)])
+
+
+def filename_match(filename, patterns, default=True):
+    """
+    Check if patterns contains a pattern that matches filename.
+    If patterns is unspecified, this always returns True.
+    """
+    if not patterns:
+        return default
+    return any(fnmatch(filename, pattern) for pattern in patterns)
+
+
+##############################################################################
+# Framework to run all checks
+##############################################################################
+
+
+_checks = {'physical_line': {}, 'logical_line': {}, 'tree': {}}
+
+
+def register_check(check, codes=None):
+    """
+    Register a new check object.
+    """
+    def _add_check(check, kind, codes, args):
+        if check in _checks[kind]:
+            _checks[kind][check][0].extend(codes or [])
+        else:
+            _checks[kind][check] = (codes or [''], args)
+    if inspect.isfunction(check):
+        args = inspect.getargspec(check)[0]
+        if args and args[0] in ('physical_line', 'logical_line'):
+            if codes is None:
+                codes = ERRORCODE_REGEX.findall(check.__doc__ or '')
+            _add_check(check, args[0], codes, args)
+    elif inspect.isclass(check):
+        if inspect.getargspec(check.__init__)[0][:2] == ['self', 'tree']:
+            _add_check(check, 'tree', codes, None)
+
+
+def init_checks_registry():
+    """
+    Register all globally visible functions where the first argument name
+    is 'physical_line' or 'logical_line'.
+    """
+    mod = inspect.getmodule(register_check)
+    for (name, function) in inspect.getmembers(mod, inspect.isfunction):
+        register_check(function)
+init_checks_registry()
+
+
+class Checker(object):
+    """
+    Load a Python source file, tokenize it, check coding style.
+    """
+
+    def __init__(self, filename=None, lines=None,
+                 options=None, report=None, **kwargs):
+        if options is None:
+            options = StyleGuide(kwargs).options
+        else:
+            assert not kwargs
+        self._io_error = None
+        self._physical_checks = options.physical_checks
+        self._logical_checks = options.logical_checks
+        self._ast_checks = options.ast_checks
+        self.max_line_length = options.max_line_length
+        self.hang_closing = options.hang_closing
+        self.verbose = options.verbose
+        self.filename = filename
+        if filename is None:
+            self.filename = 'stdin'
+            self.lines = lines or []
+        elif filename == '-':
+            self.filename = 'stdin'
+            self.lines = stdin_get_value().splitlines(True)
+        elif lines is None:
+            try:
+                self.lines = readlines(filename)
+            except IOError:
+                exc_type, exc = sys.exc_info()[:2]
+                self._io_error = '%s: %s' % (exc_type.__name__, exc)
+                self.lines = []
+        else:
+            self.lines = lines
+        if self.lines:
+            ord0 = ord(self.lines[0][0])
+            if ord0 in (0xef, 0xfeff):  # Strip the UTF-8 BOM
+                if ord0 == 0xfeff:
+                    self.lines[0] = self.lines[0][1:]
+                elif self.lines[0][:3] == '\xef\xbb\xbf':
+                    self.lines[0] = self.lines[0][3:]
+        self.report = report or options.report
+        self.report_error = self.report.error
+        self.report_error_args = self.report.error_args
+        
+        # added for eric5 integration
+        self.options = options
+
+    def report_invalid_syntax(self):
+        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.report_error_args(offset[0], offset[1] or 0,
+                          'E901', self.report_invalid_syntax,
+                          exc_type.__name__, exc.args[0])
+    report_invalid_syntax.__doc__ = "    Check if the syntax is valid."
+
+    def readline(self):
+        """
+        Get the next line from the input buffer.
+        """
+        self.line_number += 1
+        if self.line_number > len(self.lines):
+            return ''
+        return self.lines[self.line_number - 1]
+
+    def readline_check_physical(self):
+        """
+        Check and return the next physical line. This method can be
+        used to feed tokenize.generate_tokens.
+        """
+        line = self.readline()
+        if line:
+            self.check_physical(line)
+        return line
+
+    def run_check(self, check, argument_names):
+        """
+        Run a check plugin.
+        """
+        arguments = []
+        for name in argument_names:
+            arguments.append(getattr(self, name))
+        return check(*arguments)
+
+    def check_physical(self, line):
+        """
+        Run all physical checks on a raw input line.
+        """
+        self.physical_line = line
+        if self.indent_char is None and line[:1] in WHITESPACE:
+            self.indent_char = line[0]
+        for name, check, argument_names in self._physical_checks:
+            result = self.run_check(check, argument_names)
+            if result is not None:
+                offset, code, *args = result
+                self.report_error_args(self.line_number, offset, code, check,
+                    *args)
+
+    def build_tokens_line(self):
+        """
+        Build a logical line from tokens.
+        """
+        self.mapping = []
+        logical = []
+        comments = []
+        length = 0
+        previous = None
+        for token in self.tokens:
+            token_type, text = token[0:2]
+            if token_type == tokenize.COMMENT:
+                comments.append(text)
+                continue
+            if token_type in SKIP_TOKENS:
+                continue
+            if token_type == tokenize.STRING:
+                text = mute_string(text)
+            if previous:
+                end_row, end = previous[3]
+                start_row, start = token[2]
+                if end_row != start_row:    # different row
+                    prev_text = self.lines[end_row - 1][end - 1]
+                    if prev_text == ',' or (prev_text not in '{[('
+                                            and text not in '}])'):
+                        logical.append(' ')
+                        length += 1
+                elif end != start:  # different column
+                    fill = self.lines[end_row - 1][end:start]
+                    logical.append(fill)
+                    length += len(fill)
+            self.mapping.append((length, token))
+            logical.append(text)
+            length += len(text)
+            previous = token
+        self.logical_line = ''.join(logical)
+        self.noqa = comments and noqa(''.join(comments))
+        # With Python 2, if the line ends with '\r\r\n' the assertion fails
+        # assert self.logical_line.strip() == self.logical_line
+
+    def check_logical(self):
+        """
+        Build a line from tokens and run all logical checks on it.
+        """
+        self.build_tokens_line()
+        self.report.increment_logical_line()
+        first_line = self.lines[self.mapping[0][1][2][0] - 1]
+        indent = first_line[:self.mapping[0][1][2][1]]
+        self.previous_indent_level = self.indent_level
+        self.indent_level = expand_indent(indent)
+        if self.verbose >= 2:
+            print(self.logical_line[:80].rstrip())
+        for name, check, argument_names in self._logical_checks:
+            if self.verbose >= 4:
+                print('   ' + name)
+            for result in self.run_check(check, argument_names):
+                offset, code, *args = result
+                if isinstance(offset, tuple):
+                    orig_number, orig_offset = offset
+                else:
+                    for token_offset, token in self.mapping:
+                        if offset >= token_offset:
+                            orig_number = token[2][0]
+                            orig_offset = (token[2][1] + offset - token_offset)
+                self.report_error_args(orig_number, orig_offset, code, check,
+                    *args)
+        self.previous_logical = self.logical_line
+
+    def check_ast(self):
+        try:
+            tree = compile(''.join(self.lines), '', 'exec', PyCF_ONLY_AST)
+        except (SyntaxError, TypeError):
+            return self.report_invalid_syntax()
+        for name, cls, _ in self._ast_checks:
+            # extended API for eric5 integration
+            checker = cls(tree, self.filename, self.options)
+            for lineno, offset, code, check, *args in checker.run():
+                if not noqa(self.lines[lineno - 1]):
+                    self.report_error_args(lineno, offset, code, check, *args)
+
+    def generate_tokens(self):
+        if self._io_error:
+            self.report_error(1, 0, 'E902 %s' % self._io_error, readlines)
+        tokengen = tokenize.generate_tokens(self.readline_check_physical)
+        try:
+            for token in tokengen:
+                yield token
+        except (SyntaxError, tokenize.TokenError):
+            self.report_invalid_syntax()
+
+    def check_all(self, expected=None, line_offset=0):
+        """
+        Run all checks on the input file.
+        """
+        self.report.init_file(self.filename, self.lines, expected, line_offset)
+        if self._ast_checks:
+            self.check_ast()
+        self.line_number = 0
+        self.indent_char = None
+        self.indent_level = 0
+        self.previous_logical = ''
+        self.tokens = []
+        self.blank_lines = blank_lines_before_comment = 0
+        parens = 0
+        for token in self.generate_tokens():
+            self.tokens.append(token)
+            token_type, text = token[0:2]
+            if self.verbose >= 3:
+                if token[2][0] == token[3][0]:
+                    pos = '[%s:%s]' % (token[2][1] or '', token[3][1])
+                else:
+                    pos = 'l.%s' % token[3][0]
+                print('l.%s\t%s\t%s\t%r' %
+                      (token[2][0], pos, tokenize.tok_name[token[0]], text))
+            if token_type == tokenize.OP:
+                if text in '([{':
+                    parens += 1
+                elif text in '}])':
+                    parens -= 1
+            elif not parens:
+                if token_type == tokenize.NEWLINE:
+                    if self.blank_lines < blank_lines_before_comment:
+                        self.blank_lines = blank_lines_before_comment
+                    self.check_logical()
+                    self.tokens = []
+                    self.blank_lines = blank_lines_before_comment = 0
+                elif token_type == tokenize.NL:
+                    if len(self.tokens) == 1:
+                        # The physical line contains only this token.
+                        self.blank_lines += 1
+                    self.tokens = []
+                elif token_type == tokenize.COMMENT and len(self.tokens) == 1:
+                    if blank_lines_before_comment < self.blank_lines:
+                        blank_lines_before_comment = self.blank_lines
+                    self.blank_lines = 0
+                    if COMMENT_WITH_NL:
+                        # The comment also ends a physical line
+                        self.tokens = []
+        return self.report.get_file_results()
+
+
+class BaseReport(object):
+    """Collect the results of the checks."""
+    print_filename = False
+
+    def __init__(self, options):
+        self._benchmark_keys = options.benchmark_keys
+        self._ignore_code = options.ignore_code
+        # Results
+        self.elapsed = 0
+        self.total_errors = 0
+        self.counters = dict.fromkeys(self._benchmark_keys, 0)
+        self.messages = {}
+
+    def start(self):
+        """Start the timer."""
+        self._start_time = time.time()
+
+    def stop(self):
+        """Stop the timer."""
+        self.elapsed = time.time() - self._start_time
+
+    def init_file(self, filename, lines, expected, line_offset):
+        """Signal a new file."""
+        self.filename = filename
+        self.lines = lines
+        self.expected = expected or ()
+        self.line_offset = line_offset
+        self.file_errors = 0
+        self.counters['files'] += 1
+        self.counters['physical lines'] += len(lines)
+
+    def increment_logical_line(self):
+        """Signal a new logical line."""
+        self.counters['logical lines'] += 1
+
+    def error(self, line_number, offset, text, check):
+        """Report an error, according to options."""
+        code = text[:4]
+        if self._ignore_code(code):
+            return
+        if code in self.counters:
+            self.counters[code] += 1
+        else:
+            self.counters[code] = 1
+            self.messages[code] = text[5:]
+        # Don't care about expected errors or warnings
+        if code in self.expected:
+            return
+        if self.print_filename and not self.file_errors:
+            print(self.filename)
+        self.file_errors += 1
+        self.total_errors += 1
+        return code
+
+    def error_args(self, line_number, offset, code, check, *args):
+        """Report an error, according to options."""
+        if self._ignore_code(code):
+            return
+        text = getMessage(code, *args)
+        if code in self.counters:
+            self.counters[code] += 1
+        else:
+            self.counters[code] = 1
+            self.messages[code] = text[5:]
+        # Don't care about expected errors or warnings
+        if code in self.expected:
+            return
+        if self.print_filename and not self.file_errors:
+            print(self.filename)
+        self.file_errors += 1
+        self.total_errors += 1
+        return code
+
+    def get_file_results(self):
+        """Return the count of errors and warnings for this file."""
+        return self.file_errors
+
+    def get_count(self, prefix=''):
+        """Return the total count of errors and warnings."""
+        return sum([self.counters[key]
+                    for key in self.messages if key.startswith(prefix)])
+
+    def get_statistics(self, prefix=''):
+        """
+        Get statistics for message codes that start with the prefix.
+
+        prefix='' matches all errors and warnings
+        prefix='E' matches all errors
+        prefix='W' matches all warnings
+        prefix='E4' matches all errors that have to do with imports
+        """
+        return ['%-7s %s %s' % (self.counters[key], key, self.messages[key])
+                for key in sorted(self.messages) if key.startswith(prefix)]
+
+    def print_statistics(self, prefix=''):
+        """Print overall statistics (number of errors and warnings)."""
+        for line in self.get_statistics(prefix):
+            print(line)
+
+    def print_benchmark(self):
+        """Print benchmark numbers."""
+        print('%-7.2f %s' % (self.elapsed, 'seconds elapsed'))
+        if self.elapsed:
+            for key in self._benchmark_keys:
+                print('%-7d %s per second (%d total)' %
+                      (self.counters[key] / self.elapsed, key,
+                       self.counters[key]))
+
+
+class FileReport(BaseReport):
+    """Collect the results of the checks and print only the filenames."""
+    print_filename = True
+
+
+class StandardReport(BaseReport):
+    """Collect and print the results of the checks."""
+
+    def __init__(self, options):
+        super(StandardReport, self).__init__(options)
+        self._fmt = REPORT_FORMAT.get(options.format.lower(),
+                                      options.format)
+        self._repeat = options.repeat
+        self._show_source = options.show_source
+        self._show_pep8 = options.show_pep8
+
+    def init_file(self, filename, lines, expected, line_offset):
+        """Signal a new file."""
+        self._deferred_print = []
+        return super(StandardReport, self).init_file(
+            filename, lines, expected, line_offset)
+
+    def error(self, line_number, offset, text, check):
+        """Report an error, according to options."""
+        code = super(StandardReport, self).error(line_number, offset,
+                                                 text, check)
+        if code and (self.counters[code] == 1 or self._repeat):
+            self._deferred_print.append(
+                (line_number, offset, code, text[5:], check.__doc__))
+        return code
+
+    def error_args(self, line_number, offset, code, check, *args):
+        """Report an error, according to options."""
+        code = super(StandardReport, self).error_args(line_number, offset,
+                                                      code, check, *args)
+        if code and (self.counters[code] == 1 or self._repeat):
+            text = getMessage(code, *args)
+            self._deferred_print.append(
+                (line_number, offset, code, text[5:], check.__doc__))
+        return code
+
+    def get_file_results(self):
+        """Print the result and return the overall count for this file."""
+        self._deferred_print.sort()
+        for line_number, offset, code, text, doc in self._deferred_print:
+            print(self._fmt % {
+                'path': self.filename,
+                'row': self.line_offset + line_number, 'col': offset + 1,
+                'code': code, 'text': text,
+            })
+            if self._show_source:
+                if line_number > len(self.lines):
+                    line = ''
+                else:
+                    line = self.lines[line_number - 1]
+                print(line.rstrip())
+                print(' ' * offset + '^')
+            if self._show_pep8 and doc:
+                print(doc.lstrip('\n').rstrip())
+        return self.file_errors
+
+
+class DiffReport(StandardReport):
+    """Collect and print the results for the changed lines only."""
+
+    def __init__(self, options):
+        super(DiffReport, self).__init__(options)
+        self._selected = options.selected_lines
+
+    def error(self, line_number, offset, text, check):
+        if line_number not in self._selected[self.filename]:
+            return
+        return super(DiffReport, self).error(line_number, offset, text, check)
+
+
+class StyleGuide(object):
+    """Initialize a PEP-8 instance with few options."""
+
+    def __init__(self, *args, **kwargs):
+        # build options from the command line
+        self.checker_class = kwargs.pop('checker_class', Checker)
+        parse_argv = kwargs.pop('parse_argv', False)
+        config_file = kwargs.pop('config_file', None)
+        parser = kwargs.pop('parser', None)
+        options, self.paths = process_options(
+            parse_argv=parse_argv, config_file=config_file, parser=parser)
+        if args or kwargs:
+            # build options from dict
+            options_dict = dict(*args, **kwargs)
+            options.__dict__.update(options_dict)
+            if 'paths' in options_dict:
+                self.paths = options_dict['paths']
+
+        self.runner = self.input_file
+        self.options = options
+
+        if not options.reporter:
+            options.reporter = BaseReport if options.quiet else StandardReport
+
+        for index, value in enumerate(options.exclude):
+            options.exclude[index] = value.rstrip('/')
+        options.select = tuple(options.select or ())
+        if not (options.select or options.ignore or
+                options.testsuite or options.doctest) and DEFAULT_IGNORE:
+            # The default choice: ignore controversial checks
+            options.ignore = tuple(DEFAULT_IGNORE.split(','))
+        else:
+            # Ignore all checks which are not explicitly selected
+            options.ignore = ('',) if options.select else tuple(options.ignore)
+        options.benchmark_keys = BENCHMARK_KEYS[:]
+        options.ignore_code = self.ignore_code
+        options.physical_checks = self.get_checks('physical_line')
+        options.logical_checks = self.get_checks('logical_line')
+        options.ast_checks = self.get_checks('tree')
+        self.init_report()
+
+    def init_report(self, reporter=None):
+        """Initialize the report instance."""
+        self.options.report = (reporter or self.options.reporter)(self.options)
+        return self.options.report
+
+    def check_files(self, paths=None):
+        """Run all checks on the paths."""
+        if paths is None:
+            paths = self.paths
+        report = self.options.report
+        runner = self.runner
+        report.start()
+        try:
+            for path in paths:
+                if os.path.isdir(path):
+                    self.input_dir(path)
+                elif not self.excluded(path):
+                    runner(path)
+        except KeyboardInterrupt:
+            print('... stopped')
+        report.stop()
+        return report
+
+    def input_file(self, filename, lines=None, expected=None, line_offset=0):
+        """Run all checks on a Python source file."""
+        if self.options.verbose:
+            print('checking %s' % filename)
+        fchecker = self.checker_class(
+            filename, lines=lines, options=self.options)
+        return fchecker.check_all(expected=expected, line_offset=line_offset)
+
+    def input_dir(self, dirname):
+        """Check all files in this directory and all subdirectories."""
+        dirname = dirname.rstrip('/')
+        if self.excluded(dirname):
+            return 0
+        counters = self.options.report.counters
+        verbose = self.options.verbose
+        filepatterns = self.options.filename
+        runner = self.runner
+        for root, dirs, files in os.walk(dirname):
+            if verbose:
+                print('directory ' + root)
+            counters['directories'] += 1
+            for subdir in sorted(dirs):
+                if self.excluded(subdir, root):
+                    dirs.remove(subdir)
+            for filename in sorted(files):
+                # contain a pattern that matches?
+                if ((filename_match(filename, filepatterns) and
+                     not self.excluded(filename, root))):
+                    runner(os.path.join(root, filename))
+
+    def excluded(self, filename, parent=None):
+        """
+        Check if options.exclude contains a pattern that matches filename.
+        """
+        if not self.options.exclude:
+            return False
+        basename = os.path.basename(filename)
+        if filename_match(basename, self.options.exclude):
+            return True
+        if parent:
+            filename = os.path.join(parent, filename)
+        return filename_match(filename, self.options.exclude)
+
+    def ignore_code(self, code):
+        """
+        Check if the error code should be ignored.
+
+        If 'options.select' contains a prefix of the error code,
+        return False.  Else, if 'options.ignore' contains a prefix of
+        the error code, return True.
+        """
+        return (code.startswith(self.options.ignore) and
+                not code.startswith(self.options.select))
+
+    def get_checks(self, argument_name):
+        """
+        Find all globally visible functions where the first argument name
+        starts with argument_name and which contain selected tests.
+        """
+        checks = []
+        for check, attrs in _checks[argument_name].items():
+            (codes, args) = attrs
+            if any(not (code and self.ignore_code(code)) for code in codes):
+                checks.append((check.__name__, check, args))
+        return sorted(checks)
+
+
+def get_parser(prog='pep8', version=__version__):
+    parser = OptionParser(prog=prog, version=version,
+                          usage="%prog [options] input ...")
+    parser.config_options = [
+        'exclude', 'filename', 'select', 'ignore', 'max-line-length',
+        'hang-closing', 'count', 'format', 'quiet', 'show-pep8',
+        'show-source', 'statistics', 'verbose']
+    parser.add_option('-v', '--verbose', default=0, action='count',
+                      help="print status messages, or debug with -vv")
+    parser.add_option('-q', '--quiet', default=0, action='count',
+                      help="report only file names, or nothing with -qq")
+    parser.add_option('-r', '--repeat', default=True, action='store_true',
+                      help="(obsolete) show all occurrences of the same error")
+    parser.add_option('--first', action='store_false', dest='repeat',
+                      help="show first occurrence of each error")
+    parser.add_option('--exclude', metavar='patterns', default=DEFAULT_EXCLUDE,
+                      help="exclude files or directories which match these "
+                           "comma separated patterns (default: %default)")
+    parser.add_option('--filename', metavar='patterns', default='*.py',
+                      help="when parsing directories, only check filenames "
+                           "matching these comma separated patterns "
+                           "(default: %default)")
+    parser.add_option('--select', metavar='errors', default='',
+                      help="select errors and warnings (e.g. E,W6)")
+    parser.add_option('--ignore', metavar='errors', default='',
+                      help="skip errors and warnings (e.g. E4,W)")
+    parser.add_option('--show-source', action='store_true',
+                      help="show source code for each error")
+    parser.add_option('--show-pep8', action='store_true',
+                      help="show text of PEP 8 for each error "
+                           "(implies --first)")
+    parser.add_option('--statistics', action='store_true',
+                      help="count errors and warnings")
+    parser.add_option('--count', action='store_true',
+                      help="print total number of errors and warnings "
+                           "to standard error and set exit code to 1 if "
+                           "total is not null")
+    parser.add_option('--max-line-length', type='int', metavar='n',
+                      default=MAX_LINE_LENGTH,
+                      help="set maximum allowed line length "
+                           "(default: %default)")
+    parser.add_option('--hang-closing', action='store_true',
+                      help="hang closing bracket instead of matching "
+                           "indentation of opening bracket's line")
+    parser.add_option('--format', metavar='format', default='default',
+                      help="set the error format [default|pylint|<custom>]")
+    parser.add_option('--diff', action='store_true',
+                      help="report only lines changed according to the "
+                           "unified diff received on STDIN")
+    group = parser.add_option_group("Testing Options")
+    if os.path.exists(TESTSUITE_PATH):
+        group.add_option('--testsuite', metavar='dir',
+                         help="run regression tests from dir")
+        group.add_option('--doctest', action='store_true',
+                         help="run doctest on myself")
+    group.add_option('--benchmark', action='store_true',
+                     help="measure processing speed")
+    return parser
+
+
+def read_config(options, args, arglist, parser):
+    """Read both user configuration and local configuration."""
+    config = RawConfigParser()
+
+    user_conf = options.config
+    if user_conf and os.path.isfile(user_conf):
+        if options.verbose:
+            print('user configuration: %s' % user_conf)
+        config.read(user_conf)
+
+    parent = tail = args and os.path.abspath(os.path.commonprefix(args))
+    while tail:
+        if config.read([os.path.join(parent, fn) for fn in PROJECT_CONFIG]):
+            if options.verbose:
+                print('local configuration: in %s' % parent)
+            break
+        parent, tail = os.path.split(parent)
+
+    pep8_section = parser.prog
+    if config.has_section(pep8_section):
+        option_list = dict([(o.dest, o.type or o.action)
+                            for o in parser.option_list])
+
+        # First, read the default values
+        new_options, _ = parser.parse_args([])
+
+        # Second, parse the configuration
+        for opt in config.options(pep8_section):
+            if options.verbose > 1:
+                print("  %s = %s" % (opt, config.get(pep8_section, opt)))
+            if opt.replace('_', '-') not in parser.config_options:
+                print("Unknown option: '%s'\n  not in [%s]" %
+                      (opt, ' '.join(parser.config_options)))
+                sys.exit(1)
+            normalized_opt = opt.replace('-', '_')
+            opt_type = option_list[normalized_opt]
+            if opt_type in ('int', 'count'):
+                value = config.getint(pep8_section, opt)
+            elif opt_type == 'string':
+                value = config.get(pep8_section, opt)
+            else:
+                assert opt_type in ('store_true', 'store_false')
+                value = config.getboolean(pep8_section, opt)
+            setattr(new_options, normalized_opt, value)
+
+        # Third, overwrite with the command-line options
+        options, _ = parser.parse_args(arglist, values=new_options)
+    options.doctest = options.testsuite = False
+    return options
+
+
+def process_options(arglist=None, parse_argv=False, config_file=None,
+                    parser=None):
+    """Process options passed either via arglist or via command line args."""
+    if not arglist and not parse_argv:
+        # Don't read the command line if the module is used as a library.
+        arglist = []
+    if not parser:
+        parser = get_parser()
+    if not parser.has_option('--config'):
+        if config_file is True:
+            config_file = DEFAULT_CONFIG
+        group = parser.add_option_group("Configuration", description=(
+            "The project options are read from the [%s] section of the "
+            "tox.ini file or the setup.cfg file located in any parent folder "
+            "of the path(s) being processed.  Allowed options are: %s." %
+            (parser.prog, ', '.join(parser.config_options))))
+        group.add_option('--config', metavar='path', default=config_file,
+                         help="user config file location (default: %default)")
+    options, args = parser.parse_args(arglist)
+    options.reporter = None
+
+    if options.ensure_value('testsuite', False):
+        args.append(options.testsuite)
+    elif not options.ensure_value('doctest', False):
+        if parse_argv and not args:
+            if options.diff or any(os.path.exists(name)
+                                   for name in PROJECT_CONFIG):
+                args = ['.']
+            else:
+                parser.error('input not specified')
+        options = read_config(options, args, arglist, parser)
+        options.reporter = parse_argv and options.quiet == 1 and FileReport
+
+    options.filename = options.filename and options.filename.split(',')
+    options.exclude = options.exclude.split(',')
+    options.select = options.select and options.select.split(',')
+    options.ignore = options.ignore and options.ignore.split(',')
+
+    if options.diff:
+        options.reporter = DiffReport
+        stdin = stdin_get_value()
+        options.selected_lines = parse_udiff(stdin, options.filename, args[0])
+        args = sorted(options.selected_lines)
+
+    return options, args
+
+
+def _main():
+    """Parse options and run checks on Python source."""
+    pep8style = StyleGuide(parse_argv=True, config_file=True)
+    options = pep8style.options
+    if options.doctest or options.testsuite:
+        from testsuite.support import run_tests
+        report = run_tests(pep8style)
+    else:
+        report = pep8style.check_files()
+    if options.statistics:
+        report.print_statistics()
+    if options.benchmark:
+        report.print_benchmark()
+    if options.testsuite and not options.quiet:
+        report.print_results()
+    if report.total_errors:
+        if options.count:
+            sys.stderr.write(str(report.total_errors) + '\n')
+        sys.exit(1)
+
+if __name__ == '__main__':
+    _main()
--- a/Plugins/CheckerPlugins/Pep8/CodeStyleChecker.py	Wed Oct 02 18:58:13 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,128 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright (c) 2011 - 2013 Detlev Offenbach <detlev@die-offenbachs.de>
-#
-
-"""
-Module implementing the code style checker.
-"""
-
-import os
-
-from PyQt4.QtCore import QProcess, QCoreApplication
-
-from . import pep8
-from .NamingStyleChecker import NamingStyleChecker
-from .DocStyleChecker import DocStyleChecker
-
-import Preferences
-import Utilities
-
-from eric5config import getConfig
-
-
-class CodeStyleCheckerPy2(object):
-    """
-    Class implementing the code style checker interface for Python 2.
-    """
-    def __init__(self, filename, lines, repeat=False,
-                 select="", ignore="", max_line_length=79,
-                 hang_closing=False, docType="pep257"):
-        """
-        Constructor
-        
-        @param filename name of the file to check (string)
-        @param lines source of the file (list of strings) (ignored)
-        @keyparam repeat flag indicating to repeat message categories (boolean)
-        @keyparam select list of message IDs to check for
-            (comma separated string)
-        @keyparam ignore list of message IDs to ignore
-            (comma separated string)
-        @keyparam max_line_length maximum allowed line length (integer)
-        @keyparam hang_closing flag indicating to allow hanging closing
-            brackets (boolean)
-        @keyparam docType type of the documentation strings
-            (string, one of 'eric' or 'pep257')
-        """
-        assert docType in ("eric", "pep257")
-        
-        self.errors = []
-        self.counters = {}
-        
-        interpreter = Preferences.getDebugger("PythonInterpreter")
-        if interpreter == "" or not Utilities.isExecutable(interpreter):
-            self.errors.append((filename, 1, 1,
-                QCoreApplication.translate("CodeStyleCheckerPy2",
-                    "Python2 interpreter not configured.")))
-            return
-        
-        checker = os.path.join(getConfig('ericDir'),
-                               "UtilitiesPython2", "Pep8Checker.py")
-        
-        args = [checker]
-        if repeat:
-            args.append("-r")
-        if select:
-            args.append("-s")
-            args.append(select)
-        if ignore:
-            args.append("-i")
-            args.append(ignore)
-        args.append("-m")
-        args.append(str(max_line_length))
-        if hang_closing:
-            args.append("-h")
-        args.append("-d")
-        args.append(docType)
-        args.append("-f")
-        args.append(filename)
-        
-        proc = QProcess()
-        proc.setProcessChannelMode(QProcess.MergedChannels)
-        proc.start(interpreter, args)
-        finished = proc.waitForFinished(15000)
-        if finished:
-            output = \
-                str(proc.readAllStandardOutput(),
-                        Preferences.getSystem("IOEncoding"),
-                        'replace').splitlines()
-            if output[0] == "ERROR":
-                self.errors.append((filename, 1, 1, output[2]))
-                return
-            
-            if output[0] == "NO_PEP8":
-                return
-            
-            index = 0
-            while index < len(output):
-                if output[index] == "PEP8_STATISTICS":
-                    index += 1
-                    break
-                
-                fname = output[index + 1]
-                lineno = int(output[index + 2])
-                position = int(output[index + 3])
-                code = output[index + 4]
-                arglen = int(output[index + 5])
-                args = []
-                argindex = 0
-                while argindex < arglen:
-                    args.append(output[index + 6 + argindex])
-                    argindex += 1
-                index += 6 + arglen
-                
-                if code in NamingStyleChecker.Codes:
-                    text = NamingStyleChecker.getMessage(code, *args)
-                elif code in DocStyleChecker.Codes:
-                    text = DocStyleChecker.getMessage(code, *args)
-                else:
-                    text = pep8.getMessage(code, *args)
-                self.errors.append((fname, lineno, position, text))
-            while index < len(output):
-                code, countStr = output[index].split(None, 1)
-                self.counters[code] = int(countStr)
-                index += 1
-        else:
-            self.errors.append((filename, 1, 1,
-                QCoreApplication.translate("CodeStyleCheckerPy2",
-                    "Python2 interpreter did not finish within 15s.")))
--- a/Plugins/CheckerPlugins/Pep8/CodeStyleCheckerDialog.py	Wed Oct 02 18:58:13 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,906 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright (c) 2011 - 2013 Detlev Offenbach <detlev@die-offenbachs.de>
-#
-
-"""
-Module implementing a dialog to show the results of the code style check.
-"""
-
-import os
-import fnmatch
-
-from PyQt4.QtCore import pyqtSlot, Qt
-from PyQt4.QtGui import QDialog, QTreeWidgetItem, QAbstractButton, \
-    QDialogButtonBox, QApplication, QHeaderView, QIcon
-
-from E5Gui.E5Application import e5App
-
-from .Ui_CodeStyleCheckerDialog import Ui_CodeStyleCheckerDialog
-
-import UI.PixmapCache
-import Preferences
-import Utilities
-
-from . import pep8
-from .NamingStyleChecker import NamingStyleChecker
-
-# register the name checker
-pep8.register_check(NamingStyleChecker, NamingStyleChecker.Codes)
-
-from .DocStyleChecker import DocStyleChecker
-
-
-class CodeStyleCheckerReport(pep8.BaseReport):
-    """
-    Class implementing a special report to be used with our dialog.
-    """
-    def __init__(self, options):
-        """
-        Constructor
-        
-        @param options options for the report (optparse.Values)
-        """
-        super().__init__(options)
-        
-        self.__repeat = options.repeat
-        self.errors = []
-    
-    def error_args(self, line_number, offset, code, check, *args):
-        """
-        Public method to collect the error messages.
-        
-        @param line_number line number of the issue (integer)
-        @param offset position within line of the issue (integer)
-        @param code message code (string)
-        @param check reference to the checker function (function)
-        @param args arguments for the message (list)
-        @return error code (string)
-        """
-        code = super().error_args(line_number, offset, code, check, *args)
-        if code and (self.counters[code] == 1 or self.__repeat):
-            if code in NamingStyleChecker.Codes:
-                text = NamingStyleChecker.getMessage(code, *args)
-            else:
-                text = pep8.getMessage(code, *args)
-            self.errors.append(
-                (self.filename, line_number, offset, text)
-            )
-        return code
-
-
-class CodeStyleCheckerDialog(QDialog, Ui_CodeStyleCheckerDialog):
-    """
-    Class implementing a dialog to show the results of the code style check.
-    """
-    filenameRole = Qt.UserRole + 1
-    lineRole = Qt.UserRole + 2
-    positionRole = Qt.UserRole + 3
-    messageRole = Qt.UserRole + 4
-    fixableRole = Qt.UserRole + 5
-    codeRole = Qt.UserRole + 6
-    
-    def __init__(self, parent=None):
-        """
-        Constructor
-        
-        @param parent reference to the parent widget (QWidget)
-        """
-        super().__init__(parent)
-        self.setupUi(self)
-        
-        self.docTypeComboBox.addItem(self.trUtf8("PEP-257"), "pep257")
-        self.docTypeComboBox.addItem(self.trUtf8("Eric"), "eric")
-        
-        self.statisticsButton = self.buttonBox.addButton(
-            self.trUtf8("Statistics..."), QDialogButtonBox.ActionRole)
-        self.statisticsButton.setToolTip(
-            self.trUtf8("Press to show some statistics for the last run"))
-        self.statisticsButton.setEnabled(False)
-        self.showButton = self.buttonBox.addButton(
-            self.trUtf8("Show"), QDialogButtonBox.ActionRole)
-        self.showButton.setToolTip(
-            self.trUtf8("Press to show all files containing an issue"))
-        self.showButton.setEnabled(False)
-        self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False)
-        self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True)
-        
-        self.resultList.headerItem().setText(self.resultList.columnCount(), "")
-        self.resultList.header().setSortIndicator(0, Qt.AscendingOrder)
-        
-        self.checkProgress.setVisible(False)
-        self.checkProgressLabel.setVisible(False)
-        self.checkProgressLabel.setMaximumWidth(600)
-        
-        self.noResults = True
-        self.cancelled = False
-        self.__lastFileItem = None
-        
-        self.__fileOrFileList = ""
-        self.__project = None
-        self.__forProject = False
-        self.__data = {}
-        self.__statistics = {}
-        
-        self.on_loadDefaultButton_clicked()
-    
-    def __resort(self):
-        """
-        Private method to resort the tree.
-        """
-        self.resultList.sortItems(self.resultList.sortColumn(),
-                                  self.resultList.header().sortIndicatorOrder()
-                                 )
-    
-    def __createResultItem(self, file, line, pos, message, fixed, autofixing):
-        """
-        Private method to create an entry in the result list.
-        
-        @param file file name of the file (string)
-        @param line line number of issue (integer or string)
-        @param pos character position of issue (integer or string)
-        @param message message text (string)
-        @param fixed flag indicating a fixed issue (boolean)
-        @param autofixing flag indicating, that we are fixing issues
-            automatically (boolean)
-        @return reference to the created item (QTreeWidgetItem)
-        """
-        from .CodeStyleFixer import FixableCodeStyleIssues
-        
-        if self.__lastFileItem is None:
-            # It's a new file
-            self.__lastFileItem = QTreeWidgetItem(self.resultList, [file])
-            self.__lastFileItem.setFirstColumnSpanned(True)
-            self.__lastFileItem.setExpanded(True)
-            self.__lastFileItem.setData(0, self.filenameRole, file)
-        
-        fixable = False
-        code, message = message.split(None, 1)
-        itm = QTreeWidgetItem(self.__lastFileItem,
-            ["{0:6}".format(line), code, message])
-        if code.startswith("W"):
-            itm.setIcon(1, UI.PixmapCache.getIcon("warning.png"))
-        elif code.startswith("N"):
-            itm.setIcon(1, UI.PixmapCache.getIcon("namingError.png"))
-        elif code.startswith("D"):
-            itm.setIcon(1, UI.PixmapCache.getIcon("docstringError.png"))
-        else:
-            itm.setIcon(1, UI.PixmapCache.getIcon("syntaxError.png"))
-        if fixed:
-            itm.setIcon(0, UI.PixmapCache.getIcon("issueFixed.png"))
-        elif code in FixableCodeStyleIssues and not autofixing:
-            itm.setIcon(0, UI.PixmapCache.getIcon("issueFixable.png"))
-            fixable = True
-        
-        itm.setTextAlignment(0, Qt.AlignRight)
-        itm.setTextAlignment(1, Qt.AlignHCenter)
-        
-        itm.setTextAlignment(0, Qt.AlignVCenter)
-        itm.setTextAlignment(1, Qt.AlignVCenter)
-        itm.setTextAlignment(2, Qt.AlignVCenter)
-        
-        itm.setData(0, self.filenameRole, file)
-        itm.setData(0, self.lineRole, int(line))
-        itm.setData(0, self.positionRole, int(pos))
-        itm.setData(0, self.messageRole, message)
-        itm.setData(0, self.fixableRole, fixable)
-        itm.setData(0, self.codeRole, code)
-        
-        return itm
-    
-    def __modifyFixedResultItem(self, itm, text, fixed):
-        """
-        Private method to modify a result list entry to show its
-        positive fixed state.
-        
-        @param itm reference to the item to modify (QTreeWidgetItem)
-        @param text text to be appended (string)
-        @param fixed flag indicating a fixed issue (boolean)
-        """
-        if fixed:
-            message = itm.data(0, self.messageRole) + text
-            itm.setText(2, message)
-            itm.setIcon(0, UI.PixmapCache.getIcon("issueFixed.png"))
-            
-            itm.setData(0, self.messageRole, message)