[Python-checkins] bpo-36390: Gather IDLE Format menu functions into format.py (GH-14827) (GH-14829)

Terry Jan Reedy webhook-mailer at python.org
Wed Jul 17 21:21:12 EDT 2019


https://github.com/python/cpython/commit/028f1d2479a9a508e1f0bfcff42c20c348244549
commit: 028f1d2479a9a508e1f0bfcff42c20c348244549
branch: 3.8
author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com>
committer: Terry Jan Reedy <tjreedy at udel.edu>
date: 2019-07-17T21:21:08-04:00
summary:

bpo-36390: Gather IDLE Format menu functions into format.py (GH-14827) (GH-14829)

Add two indent spec methods from editor and Rstrip to existing file.
Tests are not added for indent methods because they need change
in lights of 3.x's prohibition on mixing tabs and spaces.
(cherry picked from commit 1b3892243433da7eae7f5f3a4f98f13d309c8926)

Co-authored-by: Terry Jan Reedy <tjreedy at udel.edu>

files:
D Lib/idlelib/idle_test/test_rstrip.py
D Lib/idlelib/rstrip.py
M Lib/idlelib/editor.py
M Lib/idlelib/format.py
M Lib/idlelib/idle_test/test_format.py
M Misc/NEWS.d/next/IDLE/2019-03-21-08-35-00.bpo-36390.OdDCGk.rst

diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py
index f02498da3521..24b1ffc67975 100644
--- a/Lib/idlelib/editor.py
+++ b/Lib/idlelib/editor.py
@@ -53,9 +53,8 @@ class EditorWindow(object):
     from idlelib.autoexpand import AutoExpand
     from idlelib.calltip import Calltip
     from idlelib.codecontext import CodeContext
-    from idlelib.format import FormatParagraph, FormatRegion
+    from idlelib.format import FormatParagraph, FormatRegion, Indents, Rstrip
     from idlelib.parenmatch import ParenMatch
-    from idlelib.rstrip import Rstrip
     from idlelib.squeezer import Squeezer
     from idlelib.zoomheight import ZoomHeight
 
@@ -173,14 +172,15 @@ def __init__(self, flist=None, filename=None, key=None, root=None):
         text.bind("<<newline-and-indent>>",self.newline_and_indent_event)
         text.bind("<<smart-indent>>",self.smart_indent_event)
         self.fregion = fregion = self.FormatRegion(self)
+        # self.fregion used in smart_indent_event to access indent_region.
         text.bind("<<indent-region>>", fregion.indent_region_event)
         text.bind("<<dedent-region>>", fregion.dedent_region_event)
         text.bind("<<comment-region>>", fregion.comment_region_event)
         text.bind("<<uncomment-region>>", fregion.uncomment_region_event)
         text.bind("<<tabify-region>>", fregion.tabify_region_event)
         text.bind("<<untabify-region>>", fregion.untabify_region_event)
-        text.bind("<<toggle-tabs>>", self.toggle_tabs_event)
-        text.bind("<<change-indentwidth>>",self.change_indentwidth_event)
+        text.bind("<<toggle-tabs>>", self.Indents.toggle_tabs_event)
+        text.bind("<<change-indentwidth>>", self.Indents.change_indentwidth_event)
         text.bind("<Left>", self.move_at_edge_if_selection(0))
         text.bind("<Right>", self.move_at_edge_if_selection(1))
         text.bind("<<del-word-left>>", self.del_word_left)
@@ -1424,20 +1424,6 @@ def inner(offset, _startindex=startindex,
             return _icis(_startindex + "+%dc" % offset)
         return inner
 
-    def toggle_tabs_event(self, event):
-        if self.askyesno(
-              "Toggle tabs",
-              "Turn tabs " + ("on", "off")[self.usetabs] +
-              "?\nIndent width " +
-              ("will be", "remains at")[self.usetabs] + " 8." +
-              "\n Note: a tab is always 8 columns",
-              parent=self.text):
-            self.usetabs = not self.usetabs
-            # Try to prevent inconsistent indentation.
-            # User must change indent width manually after using tabs.
-            self.indentwidth = 8
-        return "break"
-
     # XXX this isn't bound to anything -- see tabwidth comments
 ##     def change_tabwidth_event(self, event):
 ##         new = self._asktabwidth()
@@ -1446,18 +1432,6 @@ def toggle_tabs_event(self, event):
 ##             self.set_indentation_params(0, guess=0)
 ##         return "break"
 
-    def change_indentwidth_event(self, event):
-        new = self.askinteger(
-                  "Indent width",
-                  "New indent width (2-16)\n(Always use 8 when using tabs)",
-                  parent=self.text,
-                  initialvalue=self.indentwidth,
-                  minvalue=2,
-                  maxvalue=16)
-        if new and new != self.indentwidth and not self.usetabs:
-            self.indentwidth = new
-        return "break"
-
     # Make string that displays as n leading blanks.
 
     def _make_blanks(self, n):
diff --git a/Lib/idlelib/format.py b/Lib/idlelib/format.py
index e11ca3a9d26f..bced4c1770eb 100644
--- a/Lib/idlelib/format.py
+++ b/Lib/idlelib/format.py
@@ -6,6 +6,7 @@
 File renamed from paragraph.py with functions added from editor.py.
 """
 import re
+from tkinter.messagebox import askyesno
 from tkinter.simpledialog import askinteger
 from idlelib.config import idleConf
 
@@ -195,7 +196,7 @@ def get_comment_header(line):
     return m.group(1)
 
 
-# Copy from editor.py; importing it would cause an import cycle.
+# Copied from editor.py; importing it would cause an import cycle.
 _line_indent_re = re.compile(r'[ \t]*')
 
 def get_line_indent(line, tabwidth):
@@ -209,7 +210,7 @@ def get_line_indent(line, tabwidth):
 
 
 class FormatRegion:
-    "Format selected text."
+    "Format selected text (region)."
 
     def __init__(self, editwin):
         self.editwin = editwin
@@ -352,6 +353,65 @@ def _asktabwidth(self):
             maxvalue=16)
 
 
+# With mixed indents not allowed, these are semi-useless and not unittested.
+class Indents:  # pragma: no cover
+    "Change future indents."
+
+    def __init__(self, editwin):
+        self.editwin = editwin
+
+    def toggle_tabs_event(self, event):
+        editwin = self.editwin
+        usetabs = editwin.usetabs
+        if askyesno(
+              "Toggle tabs",
+              "Turn tabs " + ("on", "off")[usetabs] +
+              "?\nIndent width " +
+              ("will be", "remains at")[usetabs] + " 8." +
+              "\n Note: a tab is always 8 columns",
+              parent=editwin.text):
+            editwin.usetabs = not usetabs
+            # Try to prevent inconsistent indentation.
+            # User must change indent width manually after using tabs.
+            editwin.indentwidth = 8
+        return "break"
+
+    def change_indentwidth_event(self, event):
+        editwin = self.editwin
+        new = askinteger(
+                  "Indent width",
+                  "New indent width (2-16)\n(Always use 8 when using tabs)",
+                  parent=editwin.text,
+                  initialvalue=editwin.indentwidth,
+                  minvalue=2,
+                  maxvalue=16)
+        if new and new != editwin.indentwidth and not editwin.usetabs:
+            editwin.indentwidth = new
+        return "break"
+
+
+class Rstrip:  # 'Strip Trailing Whitespace" on "Format" menu.
+    def __init__(self, editwin):
+        self.editwin = editwin
+
+    def do_rstrip(self, event=None):
+        text = self.editwin.text
+        undo = self.editwin.undo
+        undo.undo_block_start()
+
+        end_line = int(float(text.index('end')))
+        for cur in range(1, end_line):
+            txt = text.get('%i.0' % cur, '%i.end' % cur)
+            raw = len(txt)
+            cut = len(txt.rstrip())
+            # Since text.delete() marks file as changed, even if not,
+            # only call it when needed to actually delete something.
+            if cut < raw:
+                text.delete('%i.%i' % (cur, cut), '%i.end' % cur)
+
+        undo.undo_block_stop()
+
+
 if __name__ == "__main__":
     from unittest import main
     main('idlelib.idle_test.test_format', verbosity=2, exit=False)
diff --git a/Lib/idlelib/idle_test/test_format.py b/Lib/idlelib/idle_test/test_format.py
index a2d27ed69dd1..c7b123e9d513 100644
--- a/Lib/idlelib/idle_test/test_format.py
+++ b/Lib/idlelib/idle_test/test_format.py
@@ -6,6 +6,7 @@
 from test.support import requires
 from tkinter import Tk, Text
 from idlelib.editor import EditorWindow
+from idlelib.idle_test.mock_idle import Editor as MockEditor
 
 
 class Is_Get_Test(unittest.TestCase):
@@ -573,5 +574,50 @@ def test_ask_tabwidth(self, askinteger):
         self.assertEqual(ask(), 10)
 
 
+class rstripTest(unittest.TestCase):
+
+    def test_rstrip_line(self):
+        editor = MockEditor()
+        text = editor.text
+        do_rstrip = ft.Rstrip(editor).do_rstrip
+        eq = self.assertEqual
+
+        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
+
+        original = (
+            "Line with an ending tab    \n"
+            "Line ending in 5 spaces     \n"
+            "Linewithnospaces\n"
+            "    indented line\n"
+            "    indented line with trailing space \n"
+            "    ")
+        stripped = (
+            "Line with an ending tab\n"
+            "Line ending in 5 spaces\n"
+            "Linewithnospaces\n"
+            "    indented line\n"
+            "    indented line with trailing space\n")
+
+        text.insert('1.0', original)
+        do_rstrip()
+        self.assertEqual(text.get('1.0', 'insert'), stripped)
+
+
 if __name__ == '__main__':
     unittest.main(verbosity=2, exit=2)
diff --git a/Lib/idlelib/idle_test/test_rstrip.py b/Lib/idlelib/idle_test/test_rstrip.py
deleted file mode 100644
index 2bc7c6f035e9..000000000000
--- a/Lib/idlelib/idle_test/test_rstrip.py
+++ /dev/null
@@ -1,53 +0,0 @@
-"Test rstrip, coverage 100%."
-
-from idlelib import rstrip
-import unittest
-from idlelib.idle_test.mock_idle import Editor
-
-class rstripTest(unittest.TestCase):
-
-    def test_rstrip_line(self):
-        editor = Editor()
-        text = editor.text
-        do_rstrip = rstrip.Rstrip(editor).do_rstrip
-
-        do_rstrip()
-        self.assertEqual(text.get('1.0', 'insert'), '')
-        text.insert('1.0', '     ')
-        do_rstrip()
-        self.assertEqual(text.get('1.0', 'insert'), '')
-        text.insert('1.0', '     \n')
-        do_rstrip()
-        self.assertEqual(text.get('1.0', 'insert'), '\n')
-
-    def test_rstrip_multiple(self):
-        editor = Editor()
-        #  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 = rstrip.Rstrip(editor).do_rstrip
-
-        original = (
-            "Line with an ending tab    \n"
-            "Line ending in 5 spaces     \n"
-            "Linewithnospaces\n"
-            "    indented line\n"
-            "    indented line with trailing space \n"
-            "    ")
-        stripped = (
-            "Line with an ending tab\n"
-            "Line ending in 5 spaces\n"
-            "Linewithnospaces\n"
-            "    indented line\n"
-            "    indented line with trailing space\n")
-
-        text.insert('1.0', original)
-        do_rstrip()
-        self.assertEqual(text.get('1.0', 'insert'), stripped)
-
-
-
-if __name__ == '__main__':
-    unittest.main(verbosity=2)
diff --git a/Lib/idlelib/rstrip.py b/Lib/idlelib/rstrip.py
deleted file mode 100644
index f93b5e8fc200..000000000000
--- a/Lib/idlelib/rstrip.py
+++ /dev/null
@@ -1,29 +0,0 @@
-'Provides "Strip trailing whitespace" under the "Format" menu.'
-
-class Rstrip:
-
-    def __init__(self, editwin):
-        self.editwin = editwin
-
-    def do_rstrip(self, event=None):
-
-        text = self.editwin.text
-        undo = self.editwin.undo
-
-        undo.undo_block_start()
-
-        end_line = int(float(text.index('end')))
-        for cur in range(1, end_line):
-            txt = text.get('%i.0' % cur, '%i.end' % cur)
-            raw = len(txt)
-            cut = len(txt.rstrip())
-            # Since text.delete() marks file as changed, even if not,
-            # only call it when needed to actually delete something.
-            if cut < raw:
-                text.delete('%i.%i' % (cur, cut), '%i.end' % cur)
-
-        undo.undo_block_stop()
-
-if __name__ == "__main__":
-    from unittest import main
-    main('idlelib.idle_test.test_rstrip', verbosity=2,)
diff --git a/Misc/NEWS.d/next/IDLE/2019-03-21-08-35-00.bpo-36390.OdDCGk.rst b/Misc/NEWS.d/next/IDLE/2019-03-21-08-35-00.bpo-36390.OdDCGk.rst
index fabc75fd1c6e..74bbda340249 100644
--- a/Misc/NEWS.d/next/IDLE/2019-03-21-08-35-00.bpo-36390.OdDCGk.rst
+++ b/Misc/NEWS.d/next/IDLE/2019-03-21-08-35-00.bpo-36390.OdDCGk.rst
@@ -1,2 +1,2 @@
-Rename paragraph.py to format.py and add region formatting methods
-from editor.py.  Add tests for the latter.
+Gather Format menu functions into format.py.  Combine
+paragraph.py, rstrip.py, and format methods from editor.py.



More information about the Python-checkins mailing list