[Python-checkins] bpo-38862: IDLE Strip Trailing Whitespace fixes end newlines (GH-17366)

Terry Jan Reedy webhook-mailer at python.org
Sun Nov 24 16:29:33 EST 2019


https://github.com/python/cpython/commit/6bf644ec82f14cceae68278dc35bafb00875efae
commit: 6bf644ec82f14cceae68278dc35bafb00875efae
branch: master
author: Terry Jan Reedy <tjreedy at udel.edu>
committer: GitHub <noreply at github.com>
date: 2019-11-24T16:29:29-05:00
summary:

 bpo-38862: IDLE Strip Trailing Whitespace fixes end newlines  (GH-17366)

Extra newlines are removed at the end of non-shell files. If the file only has newlines after stripping other trailing whitespace, all are removed, as is done by patchcheck.py.

files:
A Misc/NEWS.d/next/IDLE/2019-11-23-21-50-57.bpo-38862.KQ9A0m.rst
M Doc/library/idle.rst
M Lib/idlelib/NEWS.txt
M Lib/idlelib/format.py
M Lib/idlelib/help.html
M Lib/idlelib/idle_test/mock_idle.py
M Lib/idlelib/idle_test/test_format.py

diff --git a/Doc/library/idle.rst b/Doc/library/idle.rst
index 0bd248c22b182..273b5830e4293 100644
--- a/Doc/library/idle.rst
+++ b/Doc/library/idle.rst
@@ -199,7 +199,8 @@ Format Paragraph
 Strip trailing whitespace
    Remove trailing space and other whitespace characters after the last
    non-whitespace character of a line by applying str.rstrip to each line,
-   including lines within multiline strings.
+   including lines within multiline strings.  Except for Shell windows,
+   remove extra newlines at the end of the file.
 
 .. index::
    single: Run script
diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt
index c6aa00d0d54b3..5eb77398d95e6 100644
--- a/Lib/idlelib/NEWS.txt
+++ b/Lib/idlelib/NEWS.txt
@@ -3,6 +3,9 @@ Released on 2020-10-05?
 ======================================
 
 
+bpo-38862: 'Strip Trailing Whitespace' on the Format menu removes extra
+newlines at the end of non-shell files.
+
 bpo-38636: Fix IDLE Format menu tab toggle and file indent width. These
 functions (default shortcuts Alt-T and Alt-U) were mistakenly disabled
 in 3.7.5 and 3.8.0.
diff --git a/Lib/idlelib/format.py b/Lib/idlelib/format.py
index 2b0980565734a..4b57a182c9a49 100644
--- a/Lib/idlelib/format.py
+++ b/Lib/idlelib/format.py
@@ -408,6 +408,16 @@ def do_rstrip(self, event=None):
             if cut < raw:
                 text.delete('%i.%i' % (cur, cut), '%i.end' % cur)
 
+        if (text.get('end-2c') == '\n'  # File ends with at least 1 newline;
+            and not hasattr(self.editwin, 'interp')):  # & is not Shell.
+            # Delete extra user endlines.
+            while (text.index('end-1c') > '1.0'  # Stop if file empty.
+                   and text.get('end-3c') == '\n'):
+                text.delete('end-3c')
+            # Because tk indexes are slice indexes and never raise,
+            # a file with only newlines will be emptied.
+            # patchcheck.py does the same.
+
         undo.undo_block_stop()
 
 
diff --git a/Lib/idlelib/help.html b/Lib/idlelib/help.html
index 0754f2453baf6..09dc4c57bcdc0 100644
--- a/Lib/idlelib/help.html
+++ b/Lib/idlelib/help.html
@@ -4,7 +4,7 @@
 <html xmlns="http://www.w3.org/1999/xhtml">
   <head>
     <meta charset="utf-8" />
-    <title>IDLE — Python 3.9.0a0 documentation</title>
+    <title>IDLE — Python 3.9.0a1 documentation</title>
     <link rel="stylesheet" href="../_static/pydoctheme.css" type="text/css" />
     <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 
@@ -17,14 +17,14 @@
     <script type="text/javascript" src="../_static/sidebar.js"></script>
 
     <link rel="search" type="application/opensearchdescription+xml"
-          title="Search within Python 3.9.0a0 documentation"
+          title="Search within Python 3.9.0a1 documentation"
           href="../_static/opensearch.xml"/>
     <link rel="author" title="About these documents" href="../about.html" />
     <link rel="index" title="Index" href="../genindex.html" />
     <link rel="search" title="Search" href="../search.html" />
     <link rel="copyright" title="Copyright" href="../copyright.html" />
     <link rel="next" title="Other Graphical User Interface Packages" href="othergui.html" />
-    <link rel="prev" title="tkinter.scrolledtext — Scrolled Text Widget" href="tkinter.scrolledtext.html" />
+    <link rel="prev" title="tkinter.tix — Extension widgets for Tk" href="tkinter.tix.html" />
     <link rel="canonical" href="https://docs.python.org/3/library/idle.html" />
 
 
@@ -62,7 +62,7 @@ <h3>Navigation</h3>
           <a href="othergui.html" title="Other Graphical User Interface Packages"
              accesskey="N">next</a> |</li>
         <li class="right" >
-          <a href="tkinter.scrolledtext.html" title="tkinter.scrolledtext — Scrolled Text Widget"
+          <a href="tkinter.tix.html" title="tkinter.tix — Extension widgets for Tk"
              accesskey="P">previous</a> |</li>
 
     <li><img src="../_static/py.png" alt=""
@@ -71,7 +71,7 @@ <h3>Navigation</h3>
 
 
     <li>
-      <a href="../index.html">3.9.0a0 Documentation</a> »
+      <a href="../index.html">3.9.0a1 Documentation</a> »
     </li>
 
           <li class="nav-item nav-item-1"><a href="index.html" >The Python Standard Library</a> »</li>
@@ -240,7 +240,8 @@ <h3>Edit menu (Shell and Editor)<a class="headerlink" href="#edit-menu-shell-and
 </dd>
 <dt>Strip trailing whitespace</dt><dd><p>Remove trailing space and other whitespace characters after the last
 non-whitespace character of a line by applying str.rstrip to each line,
-including lines within multiline strings.</p>
+including lines within multiline strings.  Except for Shell windows,
+remove extra newlines at the end of the file.</p>
 </dd>
 </dl>
 </div>
@@ -886,8 +887,8 @@ <h3><a href="../contents.html">Table of Contents</a></h3>
 </ul>
 
   <h4>Previous topic</h4>
-  <p class="topless"><a href="tkinter.scrolledtext.html"
-                        title="previous chapter"><code class="xref py py-mod docutils literal notranslate"><span class="pre">tkinter.scrolledtext</span></code> — Scrolled Text Widget</a></p>
+  <p class="topless"><a href="tkinter.tix.html"
+                        title="previous chapter"><code class="xref py py-mod docutils literal notranslate"><span class="pre">tkinter.tix</span></code> — Extension widgets for Tk</a></p>
   <h4>Next topic</h4>
   <p class="topless"><a href="othergui.html"
                         title="next chapter">Other Graphical User Interface Packages</a></p>
@@ -919,7 +920,7 @@ <h3>Navigation</h3>
           <a href="othergui.html" title="Other Graphical User Interface Packages"
              >next</a> |</li>
         <li class="right" >
-          <a href="tkinter.scrolledtext.html" title="tkinter.scrolledtext — Scrolled Text Widget"
+          <a href="tkinter.tix.html" title="tkinter.tix — Extension widgets for Tk"
              >previous</a> |</li>
 
     <li><img src="../_static/py.png" alt=""
@@ -928,7 +929,7 @@ <h3>Navigation</h3>
 
 
     <li>
-      <a href="../index.html">3.9.0a0 Documentation</a> »
+      <a href="../index.html">3.9.0a1 Documentation</a> »
     </li>
 
           <li class="nav-item nav-item-1"><a href="index.html" >The Python Standard Library</a> »</li>
@@ -959,11 +960,11 @@ <h3>Navigation</h3>
 <br />
     <br />
 
-    Last updated on Sep 01, 2019.
+    Last updated on Nov 24, 2019.
     <a href="https://docs.python.org/3/bugs.html">Found a bug</a>?
     <br />
 
-    Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 2.1.2.
+    Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 2.1.1.
     </div>
 
   </body>
diff --git a/Lib/idlelib/idle_test/mock_idle.py b/Lib/idlelib/idle_test/mock_idle.py
index f279a52fd511f..71fa480ce4d05 100644
--- a/Lib/idlelib/idle_test/mock_idle.py
+++ b/Lib/idlelib/idle_test/mock_idle.py
@@ -40,8 +40,9 @@ def __call__(self, *args, **kwds):
 class Editor:
     '''Minimally imitate editor.EditorWindow class.
     '''
-    def __init__(self, flist=None, filename=None, key=None, root=None):
-        self.text = Text()
+    def __init__(self, flist=None, filename=None, key=None, root=None,
+                 text=None):  # Allow real Text with mock Editor.
+        self.text = text or Text()
         self.undo = UndoDelegator()
 
     def get_selection_indices(self):
diff --git a/Lib/idlelib/idle_test/test_format.py b/Lib/idlelib/idle_test/test_format.py
index 20b5970f4982d..a79bb515089e7 100644
--- a/Lib/idlelib/idle_test/test_format.py
+++ b/Lib/idlelib/idle_test/test_format.py
@@ -611,37 +611,33 @@ def test_change_indentwidth(self, askinteger):
 
 class RstripTest(unittest.TestCase):
 
-    def test_rstrip_line(self):
-        editor = MockEditor()
-        text = editor.text
-        do_rstrip = ft.Rstrip(editor).do_rstrip
-        eq = self.assertEqual
+    @classmethod
+    def setUpClass(cls):
+        requires('gui')
+        cls.root = Tk()
+        cls.root.withdraw()
+        cls.text = Text(cls.root)
+        cls.editor = MockEditor(text=cls.text)
+        cls.do_rstrip = ft.Rstrip(cls.editor).do_rstrip
+
+    @classmethod
+    def tearDownClass(cls):
+        del cls.text, cls.do_rstrip, cls.editor
+        cls.root.update_idletasks()
+        cls.root.destroy()
+        del cls.root
 
-        do_rstrip()
-        eq(text.get('1.0', 'insert'), '')
-        text.insert('1.0', '     ')
-        do_rstrip()
-        eq(text.get('1.0', 'insert'), '')
-        text.insert('1.0', '     \n')
-        do_rstrip()
-        eq(text.get('1.0', 'insert'), '\n')
-
-    def test_rstrip_multiple(self):
-        editor = MockEditor()
-        #  Comment above, uncomment 3 below to test with real Editor & Text.
-        #from idlelib.editor import EditorWindow as Editor
-        #from tkinter import Tk
-        #editor = Editor(root=Tk())
-        text = editor.text
-        do_rstrip = ft.Rstrip(editor).do_rstrip
+    def tearDown(self):
+        self.text.delete('1.0', 'end-1c')
 
+    def test_rstrip_lines(self):
         original = (
             "Line with an ending tab    \n"
             "Line ending in 5 spaces     \n"
             "Linewithnospaces\n"
             "    indented line\n"
             "    indented line with trailing space \n"
-            "    ")
+            "    \n")
         stripped = (
             "Line with an ending tab\n"
             "Line ending in 5 spaces\n"
@@ -649,9 +645,23 @@ def test_rstrip_multiple(self):
             "    indented line\n"
             "    indented line with trailing space\n")
 
-        text.insert('1.0', original)
-        do_rstrip()
-        self.assertEqual(text.get('1.0', 'insert'), stripped)
+        self.text.insert('1.0', original)
+        self.do_rstrip()
+        self.assertEqual(self.text.get('1.0', 'insert'), stripped)
+
+    def test_rstrip_end(self):
+        text = self.text
+        for code in ('', '\n', '\n\n\n'):
+            with self.subTest(code=code):
+                text.insert('1.0', code)
+                self.do_rstrip()
+                self.assertEqual(text.get('1.0','end-1c'), '')
+        for code in ('a\n', 'a\n\n', 'a\n\n\n'):
+            with self.subTest(code=code):
+                text.delete('1.0', 'end-1c')
+                text.insert('1.0', code)
+                self.do_rstrip()
+                self.assertEqual(text.get('1.0','end-1c'), 'a\n')
 
 
 if __name__ == '__main__':
diff --git a/Misc/NEWS.d/next/IDLE/2019-11-23-21-50-57.bpo-38862.KQ9A0m.rst b/Misc/NEWS.d/next/IDLE/2019-11-23-21-50-57.bpo-38862.KQ9A0m.rst
new file mode 100644
index 0000000000000..14bab9e854bdc
--- /dev/null
+++ b/Misc/NEWS.d/next/IDLE/2019-11-23-21-50-57.bpo-38862.KQ9A0m.rst
@@ -0,0 +1,2 @@
+'Strip Trailing Whitespace' on the Format menu removes extra newlines
+at the end of non-shell files.



More information about the Python-checkins mailing list