From 3046441727e4ad248e792d965bdd3ac1bbc4dbac Mon Sep 17 00:00:00 2001 From: Aidan Melen Date: Mon, 24 Apr 2023 12:26:11 -0600 Subject: [PATCH 01/10] fix-60436 update curses textbox to handle backspace key using `curses.ascii.DEL` --- Lib/curses/textpad.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/curses/textpad.py b/Lib/curses/textpad.py index 2079953a06614b..3a4da3fb36258d 100644 --- a/Lib/curses/textpad.py +++ b/Lib/curses/textpad.py @@ -102,7 +102,7 @@ def do_command(self, ch): self._insert_printable_char(ch) elif ch == curses.ascii.SOH: # ^a self.win.move(y, 0) - elif ch in (curses.ascii.STX,curses.KEY_LEFT, curses.ascii.BS,curses.KEY_BACKSPACE): + elif ch in (curses.ascii.STX,curses.KEY_LEFT, curses.ascii.BS, curses.KEY_BACKSPACE, curses.ascii.DEL): if x > 0: self.win.move(y, x-1) elif y == 0: @@ -111,7 +111,7 @@ def do_command(self, ch): self.win.move(y-1, self._end_of_line(y-1)) else: self.win.move(y-1, self.maxx) - if ch in (curses.ascii.BS, curses.KEY_BACKSPACE): + if ch in (curses.ascii.BS, curses.KEY_BACKSPACE, curses.ascii.DEL): self.win.delch() elif ch == curses.ascii.EOT: # ^d self.win.delch() From 8d68e70083a28d893220698b4b57cdf4b53989a1 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Mon, 24 Apr 2023 18:37:49 +0000 Subject: [PATCH 02/10] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20b?= =?UTF-8?q?lurb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/macOS/2023-04-24-18-37-48.gh-issue-60436.in-IyF.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/macOS/2023-04-24-18-37-48.gh-issue-60436.in-IyF.rst diff --git a/Misc/NEWS.d/next/macOS/2023-04-24-18-37-48.gh-issue-60436.in-IyF.rst b/Misc/NEWS.d/next/macOS/2023-04-24-18-37-48.gh-issue-60436.in-IyF.rst new file mode 100644 index 00000000000000..1013276c280ab6 --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2023-04-24-18-37-48.gh-issue-60436.in-IyF.rst @@ -0,0 +1 @@ +update curses textbox to additionally handle backspace using the `curses.ascii.DEL` key press. From d17df827a16b9c10b9f00f90e86a7de39c59d9c1 Mon Sep 17 00:00:00 2001 From: Aidan Melen Date: Mon, 24 Apr 2023 12:46:37 -0600 Subject: [PATCH 03/10] Update 2023-04-24-18-37-48.gh-issue-60436.in-IyF.rst --- .../next/macOS/2023-04-24-18-37-48.gh-issue-60436.in-IyF.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/macOS/2023-04-24-18-37-48.gh-issue-60436.in-IyF.rst b/Misc/NEWS.d/next/macOS/2023-04-24-18-37-48.gh-issue-60436.in-IyF.rst index 1013276c280ab6..f274d3b898f15d 100644 --- a/Misc/NEWS.d/next/macOS/2023-04-24-18-37-48.gh-issue-60436.in-IyF.rst +++ b/Misc/NEWS.d/next/macOS/2023-04-24-18-37-48.gh-issue-60436.in-IyF.rst @@ -1 +1 @@ -update curses textbox to additionally handle backspace using the `curses.ascii.DEL` key press. +update curses textbox to additionally handle backspace using the ``curses.ascii.DEL`` key press. From 10a06ef1173f3236d195d67e6692bc859875eab7 Mon Sep 17 00:00:00 2001 From: Aidan Melen Date: Mon, 24 Apr 2023 21:21:01 -0600 Subject: [PATCH 04/10] Update test_curses.py --- Lib/test/test_curses.py | 76 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index b550f4af555ce4..533e95bef3a0f5 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -1319,5 +1319,81 @@ def lorem_ipsum(win): for y, line in enumerate(text[:maxy]): win.addstr(y, 0, line[:maxx - (y == maxy - 1)]) + from curses.textpad import Textbox +from unittest.mock import MagicMock, call +import curses +import curses.ascii +import unittest + +class TextboxTest(unittest.TestCase): + def setUp(self): + self.mock_win = MagicMock(spec=curses.window) + self.mock_win.getyx.return_value = (1, 1) + self.mock_win.getmaxyx.return_value = (10, 20) + self.textbox = Textbox(self.mock_win) + + def test_init(self): + """Test textbox initialization.""" + self.mock_win.reset_mock() + tb = Textbox(self.mock_win) + self.mock_win.assert_has_calls([call.getmaxyx(), call.keypad(1)]) + self.assertEqual(tb.insert_mode, False) + self.assertEqual(tb.stripspaces, 1) + self.assertIsNone(tb.lastcmd) + self.mock_win.reset_mock() + + def test_do_command_insert(self): + """Test inserting a printable character.""" + self.mock_win.reset_mock() + self.textbox.do_command(ord('a')) + self.mock_win.addch.assert_called_with(ord('a')) + self.textbox.do_command(ord('b')) + self.mock_win.addch.assert_called_with(ord('b')) + self.textbox.do_command(ord('c')) + self.mock_win.addch.assert_called_with(ord('c')) + self.mock_win.reset_mock() + + def test_do_command_delete(self): + """Test deleting a character.""" + self.mock_win.reset_mock() + self.textbox.do_command(curses.ascii.BS) + self.textbox.do_command(curses.KEY_BACKSPACE) + self.textbox.do_command(curses.ascii.DEL) + assert self.mock_win.delch.call_count == 3 + self.mock_win.reset_mock() + + def test_do_command_move_left(self): + """Test moving the cursor left.""" + self.mock_win.reset_mock() + self.textbox.do_command(curses.KEY_LEFT) + self.mock_win.move.assert_called_with(1, 0) + self.textbox.do_command(curses.KEY_RIGHT) + self.mock_win.move.assert_called_with(1, 2) + self.mock_win.reset_mock() + + def test_do_command_left(self): + """Test moving the cursor left.""" + self.mock_win.reset_mock() + self.textbox.do_command(curses.KEY_RIGHT) + self.mock_win.move.assert_called_with(1, 2) + self.mock_win.reset_mock() + + def test_do_command_move_up(self): + """Test moving the cursor left.""" + self.mock_win.reset_mock() + self.textbox.do_command(curses.KEY_UP) + self.mock_win.move.assert_called_with(0, 1) + self.mock_win.reset_mock() + + def test_do_command_move_down(self): + """Test moving the cursor left.""" + self.mock_win.reset_mock() + self.textbox.do_command(curses.KEY_DOWN) + self.mock_win.move.assert_called_with(2, 1) + self.mock_win.reset_mock() + +if __name__ == '__main__': + unittest.main() + if __name__ == '__main__': unittest.main() From b4cd426b6303242afefb3a84acc3e346631bc3d9 Mon Sep 17 00:00:00 2001 From: Aidan Melen Date: Mon, 24 Apr 2023 21:31:22 -0600 Subject: [PATCH 05/10] Update test_curses.py --- Lib/test/test_curses.py | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index 533e95bef3a0f5..f80d63a1553ffe 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -6,6 +6,7 @@ import tempfile import unittest +from unittest.mock import MagicMock from test.support import (requires, verbose, SaveSignals, cpython_only, check_disallow_instantiation) from test.support.import_helper import import_module @@ -1319,30 +1320,29 @@ def lorem_ipsum(win): for y, line in enumerate(text[:maxy]): win.addstr(y, 0, line[:maxx - (y == maxy - 1)]) - from curses.textpad import Textbox -from unittest.mock import MagicMock, call -import curses -import curses.ascii -import unittest class TextboxTest(unittest.TestCase): def setUp(self): - self.mock_win = MagicMock(spec=curses.window) + import curses + import curses.textpad + + self.mock_win = unittest.mock.MagicMock(spec=curses.window) self.mock_win.getyx.return_value = (1, 1) self.mock_win.getmaxyx.return_value = (10, 20) - self.textbox = Textbox(self.mock_win) + self.textbox = curses.textpad.Textbox(self.mock_win) def test_init(self): """Test textbox initialization.""" self.mock_win.reset_mock() - tb = Textbox(self.mock_win) - self.mock_win.assert_has_calls([call.getmaxyx(), call.keypad(1)]) + tb = curses.textpad.Textbox(self.mock_win) + self.mock_win.getmaxyx.assert_called_once_with() + self.mock_win.keypad.assert_called_once_with(1) self.assertEqual(tb.insert_mode, False) self.assertEqual(tb.stripspaces, 1) self.assertIsNone(tb.lastcmd) self.mock_win.reset_mock() - def test_do_command_insert(self): + def test_insert(self): """Test inserting a printable character.""" self.mock_win.reset_mock() self.textbox.do_command(ord('a')) @@ -1353,16 +1353,16 @@ def test_do_command_insert(self): self.mock_win.addch.assert_called_with(ord('c')) self.mock_win.reset_mock() - def test_do_command_delete(self): + def test_delete(self): """Test deleting a character.""" self.mock_win.reset_mock() self.textbox.do_command(curses.ascii.BS) self.textbox.do_command(curses.KEY_BACKSPACE) self.textbox.do_command(curses.ascii.DEL) - assert self.mock_win.delch.call_count == 3 + assert self.mock_win.delch.call_count == 2 self.mock_win.reset_mock() - def test_do_command_move_left(self): + def test_move_left(self): """Test moving the cursor left.""" self.mock_win.reset_mock() self.textbox.do_command(curses.KEY_LEFT) @@ -1371,29 +1371,27 @@ def test_do_command_move_left(self): self.mock_win.move.assert_called_with(1, 2) self.mock_win.reset_mock() - def test_do_command_left(self): + def test_move_left(self): """Test moving the cursor left.""" self.mock_win.reset_mock() self.textbox.do_command(curses.KEY_RIGHT) self.mock_win.move.assert_called_with(1, 2) self.mock_win.reset_mock() - def test_do_command_move_up(self): + def test_move_up(self): """Test moving the cursor left.""" self.mock_win.reset_mock() self.textbox.do_command(curses.KEY_UP) self.mock_win.move.assert_called_with(0, 1) self.mock_win.reset_mock() - def test_do_command_move_down(self): + def test_move_down(self): """Test moving the cursor left.""" self.mock_win.reset_mock() self.textbox.do_command(curses.KEY_DOWN) self.mock_win.move.assert_called_with(2, 1) self.mock_win.reset_mock() -if __name__ == '__main__': - unittest.main() - + if __name__ == '__main__': unittest.main() From 1705b5dbeb71e365c095f60f3e0adb5a7c56df5e Mon Sep 17 00:00:00 2001 From: Aidan Melen Date: Mon, 24 Apr 2023 21:31:43 -0600 Subject: [PATCH 06/10] Update test_curses.py --- Lib/test/test_curses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index f80d63a1553ffe..261ed9f4da5f25 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -1359,7 +1359,7 @@ def test_delete(self): self.textbox.do_command(curses.ascii.BS) self.textbox.do_command(curses.KEY_BACKSPACE) self.textbox.do_command(curses.ascii.DEL) - assert self.mock_win.delch.call_count == 2 + assert self.mock_win.delch.call_count == 3 self.mock_win.reset_mock() def test_move_left(self): From c3d4e08ec6d816e16200f14c82558baae2ee5b64 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Mon, 24 Apr 2023 23:19:17 -0600 Subject: [PATCH 07/10] Fix trailing whitespace issues --- Lib/test/test_curses.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index 261ed9f4da5f25..b1836d16aa8ca8 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -1370,7 +1370,7 @@ def test_move_left(self): self.textbox.do_command(curses.KEY_RIGHT) self.mock_win.move.assert_called_with(1, 2) self.mock_win.reset_mock() - + def test_move_left(self): """Test moving the cursor left.""" self.mock_win.reset_mock() @@ -1392,6 +1392,6 @@ def test_move_down(self): self.mock_win.move.assert_called_with(2, 1) self.mock_win.reset_mock() - + if __name__ == '__main__': unittest.main() From 353084db2b5cbc2c114dbea663fbab1075011499 Mon Sep 17 00:00:00 2001 From: Aidan Melen Date: Tue, 25 Apr 2023 10:02:32 -0600 Subject: [PATCH 08/10] fixed test_curses assertion but now the test is failing. --- Lib/test/test_curses.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index b1836d16aa8ca8..d13eeb571c4975 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -1323,9 +1323,6 @@ def lorem_ipsum(win): class TextboxTest(unittest.TestCase): def setUp(self): - import curses - import curses.textpad - self.mock_win = unittest.mock.MagicMock(spec=curses.window) self.mock_win.getyx.return_value = (1, 1) self.mock_win.getmaxyx.return_value = (10, 20) From 966d1c261a90f36c2fd727891f0c89ca0f416c50 Mon Sep 17 00:00:00 2001 From: Aidan Melen Date: Wed, 26 Apr 2023 12:46:57 -0600 Subject: [PATCH 09/10] fixed suggested changes. lint and removed unused import. --- Lib/curses/textpad.py | 5 ++++- Lib/test/test_curses.py | 1 - 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Lib/curses/textpad.py b/Lib/curses/textpad.py index 3a4da3fb36258d..aa87061b8d749e 100644 --- a/Lib/curses/textpad.py +++ b/Lib/curses/textpad.py @@ -102,7 +102,10 @@ def do_command(self, ch): self._insert_printable_char(ch) elif ch == curses.ascii.SOH: # ^a self.win.move(y, 0) - elif ch in (curses.ascii.STX,curses.KEY_LEFT, curses.ascii.BS, curses.KEY_BACKSPACE, curses.ascii.DEL): + elif ch in (curses.ascii.STX,curses.KEY_LEFT, + curses.ascii.BS, + curses.KEY_BACKSPACE, + curses.ascii.DEL): if x > 0: self.win.move(y, x-1) elif y == 0: diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index d13eeb571c4975..26b8b01806fb14 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -6,7 +6,6 @@ import tempfile import unittest -from unittest.mock import MagicMock from test.support import (requires, verbose, SaveSignals, cpython_only, check_disallow_instantiation) from test.support.import_helper import import_module From fa69eb94ea6d4be545a703dae3049fbe6857efea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= Date: Wed, 26 Apr 2023 21:59:31 +0200 Subject: [PATCH 10/10] Fix import --- Lib/test/test_curses.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index 26b8b01806fb14..3ab837e4f95681 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -5,6 +5,7 @@ import sys import tempfile import unittest +from unittest.mock import MagicMock from test.support import (requires, verbose, SaveSignals, cpython_only, check_disallow_instantiation) @@ -1322,7 +1323,7 @@ def lorem_ipsum(win): class TextboxTest(unittest.TestCase): def setUp(self): - self.mock_win = unittest.mock.MagicMock(spec=curses.window) + self.mock_win = MagicMock(spec=curses.window) self.mock_win.getyx.return_value = (1, 1) self.mock_win.getmaxyx.return_value = (10, 20) self.textbox = curses.textpad.Textbox(self.mock_win)