Started to implement a fixer for PEP 8 issues.

Sun, 16 Jan 2011 16:09:21 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sun, 16 Jan 2011 16:09:21 +0100
changeset 849
996367a89673
parent 848
e2fad77b41ba
child 850
8b9f09e7d5d9

Started to implement a fixer for PEP 8 issues.

Plugins/CheckerPlugins/Pep8/Pep8CodeSelectionDialog.py file | annotate | diff | comparison | revisions
Plugins/CheckerPlugins/Pep8/Pep8Dialog.py file | annotate | diff | comparison | revisions
Plugins/CheckerPlugins/Pep8/Pep8Dialog.ui file | annotate | diff | comparison | revisions
Plugins/CheckerPlugins/Pep8/Pep8Fixer.py file | annotate | diff | comparison | revisions
Plugins/PluginPep8Checker.py file | annotate | diff | comparison | revisions
eric5.e4p file | annotate | diff | comparison | revisions
--- a/Plugins/CheckerPlugins/Pep8/Pep8CodeSelectionDialog.py	Sat Jan 15 19:31:56 2011 +0100
+++ b/Plugins/CheckerPlugins/Pep8/Pep8CodeSelectionDialog.py	Sun Jan 16 16:09:21 2011 +0100
@@ -11,6 +11,7 @@
 from PyQt4.QtGui import QDialog, QTreeWidgetItem
 
 from . import pep8
+from .Pep8Fixer import Pep8FixableIssues
 
 from .Ui_Pep8CodeSelectionDialog import Ui_Pep8CodeSelectionDialog
 
@@ -18,11 +19,13 @@
     """
     Class implementing a dialog to select PEP 8 message codes.
     """
-    def __init__(self, codes, parent = None):
+    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)
         """
         QDialog.__init__(self, parent)
@@ -30,7 +33,11 @@
         
         codeList = [code.strip() for code in codes.split(",") if code.strip()]
         
-        for code in sorted(pep8.pep8_messages.keys(), key=lambda a: a[1:]):
+        if showFixCodes:
+            selectableCodes = Pep8FixableIssues
+        else:
+            selectableCodes = pep8.pep8_messages.keys()
+        for code in sorted(selectableCodes, key=lambda a: a[1:]):
             if code in pep8.pep8_messages_sample_args:
                 message = QCoreApplication.translate("pep8", 
                     pep8.pep8_messages[code]).format(
--- a/Plugins/CheckerPlugins/Pep8/Pep8Dialog.py	Sat Jan 15 19:31:56 2011 +0100
+++ b/Plugins/CheckerPlugins/Pep8/Pep8Dialog.py	Sun Jan 16 16:09:21 2011 +0100
@@ -21,6 +21,7 @@
 from .Pep8Checker import Pep8Checker, Pep8Py2Checker
 from .Pep8CodeSelectionDialog import Pep8CodeSelectionDialog
 from .Pep8StatisticsDialog import Pep8StatisticsDialog
+from .Pep8Fixer import Pep8Fixer
 
 from .Ui_Pep8Dialog import Ui_Pep8Dialog
 
@@ -80,6 +81,8 @@
             UI.PixmapCache.getIcon("clearLeft.png"))
         self.clearButtonIncludeMessages.setIcon(
             UI.PixmapCache.getIcon("clearLeft.png"))
+        self.clearButtonFixIssues.setIcon(
+            UI.PixmapCache.getIcon("clearLeft.png"))
         self.on_loadDefaultButton_clicked()
     
     def __resort(self):
@@ -162,27 +165,31 @@
         self.buttonBox.button(QDialogButtonBox.Close).setDefault(True)
         
         self.__data = self.__project.getData("CHECKERSPARMS", "Pep8Checker")
-        if self.__data is None or "ExcludeFiles" not in self.__data:
+        if self.__data is None or \
+           "ExcludeFiles" not in self.__data or \
+           len(self.__data) != 6:
             # initialize the data structure
             self.__data = {
                 "ExcludeFiles" : "", 
                 "ExcludeMessages" : pep8.DEFAULT_IGNORE, 
                 "IncludeMessages" : "", 
                 "RepeatMessages" : False, 
+                "FixCodes" : "", 
+                "FixIssues" : False, 
             }
         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.fixIssuesCheckBox.setChecked(self.__data["FixIssues"])
     
-    def start(self, fn, codestring = "", save = False, repeat = None):
+    def start(self, fn, save = False, repeat = None):
         """
         Public slot to start the PEP 8 check.
         
         @param fn file or list of files or directory to be checked
                 (string or list of strings)
-        @keyparam codestring string containing the code to be checked (string).
-            If this is given, file must be a single file name.
         @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
@@ -234,9 +241,7 @@
                     if f.endswith(
                         tuple(Preferences.getPython("PythonExtensions")))]
         
-        if (codestring and len(py3files) == 1) or \
-           (codestring and len(py2files) == 1) or \
-           (not codestring and len(py3files) + len(py2files) > 0):
+        if len(py3files) + len(py2files) > 0:
             self.checkProgress.setMaximum(len(py3files) + len(py2files))
             QApplication.processEvents()
             
@@ -244,6 +249,8 @@
             excludeMessages = self.excludeMessagesEdit.text()
             includeMessages = self.includeMessagesEdit.text()
             repeatMessages = self.repeatCheckBox.isChecked()
+            fixCodes = self.fixIssuesEdit.text()
+            fixIssues = self.fixIssuesCheckBox.isChecked() and repeatMessages
             
             # now go through all the files
             progress = 0
@@ -257,24 +264,24 @@
                 
                 self.__lastFileItem = None
                 
-                if codestring:
-                    source = codestring.splitlines(True)
-                else:
-                    try:
-                        source = Utilities.readEncodedFile(file)[0]
-                        # convert eols
-                        source = Utilities.convertLineEnds(source, "\n")
-                        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])
-                        progress += 1
-                        continue
+                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])
+                    progress += 1
+                    continue
                 
                 flags = Utilities.extractFlags(source)
                 ext = os.path.splitext(file)[1]
+                if fixIssues:
+                    fixer = Pep8Fixer(self.__project, file, source, 
+                                      fixCodes, True)  # always fix in place
+                else:
+                    fixer = None
                 if ("FileType" in flags and 
                     flags["FileType"] in ["Python", "Python2"]) or \
                    file in py2files or \
@@ -300,8 +307,14 @@
                     if not source[lineno - 1].strip()\
                        .endswith("__IGNORE_WARNING__"):
                         self.noResults = False
+                        if fixer:
+                            fixed, msg = fixer.fixIssue(lineno, position, text)
+                            if fixed:
+                                text += "\n" + \
+                                        self.trUtf8("Fix: {0}").format(msg)
                         self.__createResultItem(
                             fname, lineno, position, text)
+                fixer and fixer.saveFile(encoding)
                 self.__updateStatistics(checker.statistics)
                 progress += 1
             self.checkProgress.setValue(progress)
@@ -345,6 +358,8 @@
                 "ExcludeMessages" : self.excludeMessagesEdit.text(), 
                 "IncludeMessages" : self.includeMessagesEdit.text(), 
                 "RepeatMessages" : self.repeatCheckBox.isChecked(),
+                "FixCodes" : self.fixIssuesEdit.text(), 
+                "FixIssues" : self.fixIssuesCheckBox.isChecked(),
             }
             if data != self.__data:
                 self.__data = data
@@ -362,7 +377,8 @@
         Private slot to select the message codes to be excluded via a
         selection dialog.
         """
-        dlg = Pep8CodeSelectionDialog(self.excludeMessagesEdit.text(), self)
+        dlg = Pep8CodeSelectionDialog(
+            self.excludeMessagesEdit.text(), False, self)
         if dlg.exec_() == QDialog.Accepted:
             self.excludeMessagesEdit.setText(dlg.getSelectedCodes())
     
@@ -372,10 +388,22 @@
         Private slot to select the message codes to be included via a
         selection dialog.
         """
-        dlg = Pep8CodeSelectionDialog(self.includeMessagesEdit.text(), self)
+        dlg = Pep8CodeSelectionDialog(
+            self.includeMessagesEdit.text(), False, self)
         if dlg.exec_() == QDialog.Accepted:
             self.includeMessagesEdit.setText(dlg.getSelectedCodes())
     
+    @pyqtSlot()
+    def on_fixIssuesSelectButton_clicked(self):
+        """
+        Private slot to select the issue codes to be fixed via a
+        selection dialog.
+        """
+        dlg = Pep8CodeSelectionDialog(
+            self.fixIssuesEdit.text(), True, self)
+        if dlg.exec_() == QDialog.Accepted:
+            self.fixIssuesEdit.setText(dlg.getSelectedCodes())
+    
     @pyqtSlot(QTreeWidgetItem, int)
     def on_resultList_itemActivated(self, item, column):
         """
@@ -458,6 +486,10 @@
             "PEP8/IncludeMessages"))
 ##        self.repeatCheckBox.setChecked(Preferences.toBool(
 ##            Preferences.Prefs.settings.value("PEP8/RepeatMessages")))
+        self.fixIssuesEdit.setText(Preferences.Prefs.settings.value(
+            "PEP8/FixCodes"))
+        self.fixIssuesCheckBox.setChecked(Preferences.toBool(
+            Preferences.Prefs.settings.value("PEP8/FixIssues")))
     
     @pyqtSlot()
     def on_storeDefaultButton_clicked(self):
@@ -473,6 +505,10 @@
             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/FixIssues",
+            self.fixIssuesCheckBox.isChecked())
     
     @pyqtSlot(QAbstractButton)
     def on_buttonBox_clicked(self, button):
--- a/Plugins/CheckerPlugins/Pep8/Pep8Dialog.ui	Sat Jan 15 19:31:56 2011 +0100
+++ b/Plugins/CheckerPlugins/Pep8/Pep8Dialog.ui	Sun Jan 16 16:09:21 2011 +0100
@@ -7,7 +7,7 @@
     <x>0</x>
     <y>0</y>
     <width>650</width>
-    <height>600</height>
+    <height>700</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -52,7 +52,7 @@
         </property>
        </widget>
       </item>
-      <item row="0" column="4" rowspan="4">
+      <item row="0" column="4" rowspan="5">
        <widget class="Line" name="line">
         <property name="lineWidth">
          <number>2</number>
@@ -62,7 +62,7 @@
         </property>
        </widget>
       </item>
-      <item row="0" column="5" rowspan="4">
+      <item row="0" column="5" rowspan="5">
        <layout class="QVBoxLayout" name="verticalLayout_2">
         <item>
          <widget class="QPushButton" name="startButton">
@@ -136,7 +136,7 @@
       <item row="1" column="3">
        <widget class="QToolButton" name="excludeMessagesSelectButton">
         <property name="toolTip">
-         <string>Press to select the messages from a list</string>
+         <string>Press to select the message codes from a list</string>
         </property>
         <property name="text">
          <string>...</string>
@@ -170,23 +170,87 @@
       <item row="2" column="3">
        <widget class="QToolButton" name="includeMessagesSelectButton">
         <property name="toolTip">
-         <string>Press to select the messages from a list</string>
+         <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" colspan="4">
-       <widget class="QCheckBox" name="repeatCheckBox">
+      <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="QLineEdit" name="fixIssuesEdit">
         <property name="toolTip">
-         <string>Select to repeat each message type</string>
+         <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="clearButtonFixIssues">
+        <property name="toolTip">
+         <string>Press to clear the fix issues edit</string>
+        </property>
+        <property name="text">
+         <string/>
+        </property>
+       </widget>
+      </item>
+      <item row="3" column="3">
+       <widget class="QToolButton" name="fixIssuesSelectButton">
+        <property name="toolTip">
+         <string>Press to select the message codes from a list</string>
         </property>
         <property name="text">
-         <string>Repeat messages</string>
+         <string>...</string>
         </property>
        </widget>
       </item>
+      <item row="4" column="0" colspan="4">
+       <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>
     </widget>
    </item>
@@ -262,7 +326,11 @@
   <tabstop>includeMessagesEdit</tabstop>
   <tabstop>clearButtonIncludeMessages</tabstop>
   <tabstop>includeMessagesSelectButton</tabstop>
+  <tabstop>fixIssuesEdit</tabstop>
+  <tabstop>clearButtonFixIssues</tabstop>
+  <tabstop>fixIssuesSelectButton</tabstop>
   <tabstop>repeatCheckBox</tabstop>
+  <tabstop>fixIssuesCheckBox</tabstop>
   <tabstop>storeDefaultButton</tabstop>
   <tabstop>resultList</tabstop>
   <tabstop>buttonBox</tabstop>
@@ -276,11 +344,11 @@
    <slot>clear()</slot>
    <hints>
     <hint type="sourcelabel">
-     <x>505</x>
-     <y>40</y>
+     <x>493</x>
+     <y>42</y>
     </hint>
     <hint type="destinationlabel">
-     <x>472</x>
+     <x>460</x>
      <y>39</y>
     </hint>
    </hints>
@@ -308,8 +376,8 @@
    <slot>clear()</slot>
    <hints>
     <hint type="sourcelabel">
-     <x>494</x>
-     <y>100</y>
+     <x>493</x>
+     <y>106</y>
     </hint>
     <hint type="destinationlabel">
      <x>458</x>
@@ -317,5 +385,37 @@
     </hint>
    </hints>
   </connection>
+  <connection>
+   <sender>clearButtonFixIssues</sender>
+   <signal>clicked()</signal>
+   <receiver>fixIssuesEdit</receiver>
+   <slot>clear()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>478</x>
+     <y>122</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>445</x>
+     <y>122</y>
+    </hint>
+   </hints>
+  </connection>
+  <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/Pep8/Pep8Fixer.py	Sun Jan 16 16:09:21 2011 +0100
@@ -0,0 +1,279 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2011 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a class to fix certain PEP 8 issues.
+"""
+
+import os
+import re
+
+from PyQt4.QtCore import QObject
+
+from E5Gui import E5MessageBox
+
+import Utilities
+
+Pep8FixableIssues = ["W191", "W291", "W292", "W293", "E301", "E303", "E304", "W391", "W603"]
+
+class Pep8Fixer(QObject):
+    """
+    Class implementing a fixer for certain PEP 8 issues.
+    """
+    def __init__(self, project, filename, sourceLines, fixCodes, 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 inPlace flag indicating to modify the file in place (boolean)
+        """
+        QObject.__init__(self)
+        
+        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()]
+        
+        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 = {
+            "W191" : self.__fixTabs, 
+            "W291" : self.__fixWhitespace, 
+            "W292" : self.__fixNewline, 
+            "W293" : self.__fixWhitespace,
+            "E301" : self.__fixOneBlankLine, 
+            "E303" : self.__fixTooManyBlankLines, 
+            "E304" : self.__fixBlankLinesAfterDecorator, 
+            "W391" : self.__fixTrailingBlankLines, 
+            "W603" : self.__fixNotEqual, 
+        }
+        self.__modified = False
+        self.__stack = []   # these need to be fixed before the file is saved
+                            # but after all inline fixes
+    
+    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
+        
+        # apply deferred fixes
+        self.__finalize()
+        
+        txt = "".join(self.__source)
+        try:
+            Utilities.writeEncodedFile(self.__filename, txt, encoding)
+        except (IOError, Utilities.CodingError, UnicodeError) as err:
+            E5MessageBox.critical(self,
+                self.trUtf8("Fix PEP 8 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 fixIssue(self, line, pos, message):
+        """
+        Public method to fix the fixable issues.
+        
+        @param line line number of issue (integer or string)
+        @param pos character position of issue (integer or string)
+        @param message message text (string)
+        @return flag indicating an applied fix (boolean) and a message for
+            the fix (string)
+        """
+        code = message.split(None, 1)[0].strip()
+        
+        if (code in self.__fixCodes or len(self.__fixCodes) == 0) and \
+           code in self.__fixes:
+            res = self.__fixes[code](code, line, pos)
+            if res[0]:
+                self.__modified = True
+        else:
+            res = (False, "")
+        
+        return res
+    
+    def __finalize(self):
+        """
+        Private method to apply all deferred fixes.
+        """
+        for code, line, pos in reversed(self.__stack):
+            self.__fixes[code](code, line, pos, apply=True)
+    
+    def __getEol(self):
+        """
+        Private method to get the applicable eol string.
+        
+        @return eol string (string)
+        """
+        if self.__origName:
+            fn = self.__origName
+        else:
+            fn = self.__filename
+        
+        if self.__project.isOpen() and self.__project.isProjectFile(fn):
+            eol = self.__project.getLineSeparator()
+        else:
+            eol = Utilities.linesep()
+        return eol
+    
+    def __fixTabs(self, code, line, pos):
+        """
+        Private method to fix obsolete tab usage.
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @return flag indicating an applied fix (boolean) and a message for
+            the fix (string)
+        """
+        self.__source[line - 1] = self.__source[line - 1].replace("\t", "    ")
+        return (True, self.trUtf8("Tab converted to 4 spaces."))
+    
+    def __fixWhitespace(self, code, line, pos):
+        """
+        Private method to fix trailing whitespace.
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @return flag indicating an applied fix (boolean) and a message for
+            the fix (string)
+        """
+        self.__source[line - 1] = re.sub(r'[\t ]*$', "", 
+                                         self.__source[line - 1])
+        return (True, self.trUtf8("Whitespace stripped from end of line."))
+    
+    def __fixNewline(self, code, line, pos):
+        """
+        Private method to fix a missing newline at the end of file.
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @return flag indicating an applied fix (boolean) and a message for
+            the fix (string)
+        """
+        self.__source[line - 1] += self.__getEol()
+        return (True, self.trUtf8("newline added to end of file."))
+    
+    def __fixTrailingBlankLines(self, code, line, pos):
+        """
+        Private method to fix trailing blank lines.
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @return flag indicating an applied fix (boolean) and a message for
+            the fix (string)
+        """
+        index = line - 1
+        while index:
+            if self.__source[index].strip() == "":
+                del self.__source[index]
+                index -= 1
+            else:
+                break
+        return (True, self.trUtf8(
+            "Superfluous trailing blank lines removed from end of file."))
+    
+    def __fixNotEqual(self, code, line, pos):
+        """
+        Private method to fix the not equal notation.
+        
+        @param code code of the issue (string)
+        @param line line number of the issue (integer)
+        @param pos position inside line (integer)
+        @return flag indicating an applied fix (boolean) and a message for
+            the fix (string)
+        """
+        self.__source[line - 1] = self.__source[line - 1].replace("<>", "!=")
+        return (True, self.trUtf8("'<>' replaced by '!='."))
+    
+    def __fixBlankLinesAfterDecorator(self, code, line, pos, apply=False):
+        """
+        Private method to fix superfluous blank lines after a function
+        decorator.
+        
+        @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 flag indicating an applied fix (boolean) and a message for
+            the fix (string)
+        """
+        if apply:
+            index = line - 2
+            while index:
+                if self.__source[index].strip() == "":
+                    del self.__source[index]
+                    index -= 1
+                else:
+                    break
+        else:
+            self.__stack.append((code, line, pos))
+        return (True, self.trUtf8(
+            "Superfluous blank lines after function decorator removed."))
+    
+    def __fixTooManyBlankLines(self, code, line, pos, apply=False):
+        """
+        Private method to fix superfluous blank lines.
+        
+        @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 flag indicating an applied fix (boolean) and a message for
+            the fix (string)
+        """
+        if apply:
+            index = line - 3
+            while index:
+                if self.__source[index].strip() == "":
+                    del self.__source[index]
+                    index -= 1
+                else:
+                    break
+        else:
+            self.__stack.append((code, line, pos))
+        return (True, self.trUtf8("Superfluous blank lines removed."))
+    
+    def __fixOneBlankLine(self, code, line, pos, apply=False):
+        """
+        Private method to fix the need for one blank line.
+        
+        @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 flag indicating an applied fix (boolean) and a message for
+            the fix (string)
+        """
+        if apply:
+            self.__source.insert(line - 1, self.__getEol())
+        else:
+            self.__stack.append((code, line, pos))
+        return (True, self.trUtf8("One blank line inserted."))
--- a/Plugins/PluginPep8Checker.py	Sat Jan 15 19:31:56 2011 +0100
+++ b/Plugins/PluginPep8Checker.py	Sun Jan 16 16:09:21 2011 +0100
@@ -265,10 +265,10 @@
         """
         editor = e5App().getObject("ViewManager").activeWindow()
         if editor is not None:
-            self.__editorPep8CheckerDialog = Pep8Dialog()
-            self.__editorPep8CheckerDialog.show()
-            self.__editorPep8CheckerDialog.start(
-                editor.getFileName(), 
-                codestring = editor.text(), 
-                save = True, 
-                repeat = True)
+            if editor.checkDirty():
+                self.__editorPep8CheckerDialog = Pep8Dialog()
+                self.__editorPep8CheckerDialog.show()
+                self.__editorPep8CheckerDialog.start(
+                    editor.getFileName(), 
+                    save = True, 
+                    repeat = True)
--- a/eric5.e4p	Sat Jan 15 19:31:56 2011 +0100
+++ b/eric5.e4p	Sun Jan 16 16:09:21 2011 +0100
@@ -852,6 +852,7 @@
     <Source>UtilitiesPython2/pep8.py</Source>
     <Source>UtilitiesPython2/Pep8Checker.py</Source>
     <Source>Plugins/CheckerPlugins/Pep8/Pep8StatisticsDialog.py</Source>
+    <Source>Plugins/CheckerPlugins/Pep8/Pep8Fixer.py</Source>
   </Sources>
   <Forms>
     <Form>PyUnit/UnittestDialog.ui</Form>

eric ide

mercurial