[3.8] 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.
(cherry picked from commit 6bf644ec82)

Co-authored-by: Terry Jan Reedy <tjreedy@udel.edu>
This commit is contained in:
Terry Jan Reedy 2019-11-26 20:13:23 -05:00 committed by GitHub
parent 191f94cca6
commit a9c86f5e1a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 68 additions and 40 deletions

View File

@ -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

View File

@ -3,6 +3,9 @@ Released on 2019-12-16?
======================================
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.

View File

@ -408,6 +408,16 @@ class Rstrip: # 'Strip Trailing Whitespace" on "Format" menu.
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()

View File

@ -4,7 +4,7 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title>IDLE &#8212; Python 3.9.0a0 documentation</title>
<title>IDLE &#8212; 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 @@
<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 @@
<li>
<a href="../index.html">3.9.0a0 Documentation</a> &#187;
<a href="../index.html">3.9.0a1 Documentation</a> &#187;
</li>
<li class="nav-item nav-item-1"><a href="index.html" >The Python Standard Library</a> &#187;</li>
@ -240,7 +240,8 @@ paragraph will be formatted to less than N columns, where N defaults to 72.</p>
</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 @@ also used for testing.</p>
</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 @@ also used for testing.</p>
<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 @@ also used for testing.</p>
<li>
<a href="../index.html">3.9.0a0 Documentation</a> &#187;
<a href="../index.html">3.9.0a1 Documentation</a> &#187;
</li>
<li class="nav-item nav-item-1"><a href="index.html" >The Python Standard Library</a> &#187;</li>
@ -959,11 +960,11 @@ also used for testing.</p>
<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>

View File

@ -40,8 +40,9 @@ class Func:
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):

View File

@ -611,37 +611,33 @@ class IndentsTest(unittest.TestCase):
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
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')
@classmethod
def tearDownClass(cls):
del cls.text, cls.do_rstrip, cls.editor
cls.root.update_idletasks()
cls.root.destroy()
del cls.root
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 @@ class RstripTest(unittest.TestCase):
" 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__':

View File

@ -0,0 +1,2 @@
'Strip Trailing Whitespace' on the Format menu removes extra newlines
at the end of non-shell files.