From 8b27bcb3c5afb01fe006ba6f90969b08f63d5e75 Mon Sep 17 00:00:00 2001 From: sharktide Date: Tue, 4 Mar 2025 11:31:08 -0500 Subject: [PATCH 01/51] Update __init__.py --- Lib/tkinter/__init__.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index 0baed8b569e40f..6b970ed5ff6216 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -4026,9 +4026,7 @@ def scan_dragto(self, x, y): scan_mark.""" self.tk.call(self._w, 'scan', 'dragto', x, y) - def search(self, pattern, index, stopindex=None, - forwards=None, backwards=None, exact=None, - regexp=None, nocase=None, count=None, elide=None): + def search(self, pattern, index, stopindex=None, forwards=None, backwards=None, exact=None, regexp=None, nocase=None, count=None, elide=None, nolinestop=None, all=None, overlap=None, strictlimits=None): """Search PATTERN beginning from INDEX until STOPINDEX. Return the index of the first character of a match or an empty string.""" @@ -4040,12 +4038,18 @@ def search(self, pattern, index, stopindex=None, if nocase: args.append('-nocase') if elide: args.append('-elide') if count: args.append('-count'); args.append(count) + if nolinestop: args.append('-nolinestop') + if all: args.append('-all') + if overlap: args.append('-overlap') + if strictlimits: args.append('-strictlimits') if pattern and pattern[0] == '-': args.append('--') args.append(pattern) args.append(index) if stopindex: args.append(stopindex) return str(self.tk.call(tuple(args))) + + def see(self, index): """Scroll such that the character at INDEX is visible.""" self.tk.call(self._w, 'see', index) From 18d5005fc76139531734c003749ac1026bd78e1c Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Tue, 4 Mar 2025 17:19:27 +0000 Subject: [PATCH 02/51] =?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 --- .../2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst diff --git a/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst b/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst new file mode 100644 index 00000000000000..ba854217c39db4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst @@ -0,0 +1,13 @@ +================ +Type: Enhancement +Title: Add support for -nolinestop, -all, -overlap, and -strictlimits options to tkinter.Text.search +Issue: :gh:`130693` + +Detailed changes: +- Enhanced the `tkinter.Text.search` method by adding support for the following options: + - `-nolinestop`: Allows searching across lines without stopping. + - `-all`: Finds all matches instead of just the first match. + - `-overlap`: Finds matches that overlap with each other. + - `-strictlimits`: Ensures strict boundaries for the search. + +These improvements align the `tkinter.Text.search` method with the underlying Tcl/Tk library, providing more flexibility and functionality for users. From e2a76c217ac93ffd52dd815afac7f86c8ee79eda Mon Sep 17 00:00:00 2001 From: sharktide Date: Tue, 4 Mar 2025 12:23:07 -0500 Subject: [PATCH 03/51] Update 2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst --- .../2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst b/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst index ba854217c39db4..5cd419efb5d339 100644 --- a/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst +++ b/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst @@ -1,13 +1,13 @@ ================ Type: Enhancement -Title: Add support for -nolinestop, -all, -overlap, and -strictlimits options to tkinter.Text.search +Title: Add support for ``-nolinestop``, ``-all``, ``-overlap``, and ``-strictlimits`` options to ``tkinter.Text.search`` Issue: :gh:`130693` Detailed changes: -- Enhanced the `tkinter.Text.search` method by adding support for the following options: - - `-nolinestop`: Allows searching across lines without stopping. - - `-all`: Finds all matches instead of just the first match. - - `-overlap`: Finds matches that overlap with each other. - - `-strictlimits`: Ensures strict boundaries for the search. +- Enhanced the ``tkinter.Text.search`` method by adding support for the following options: + - ``-nolinestop``: Allows searching across lines without stopping. + - ``-all``: Finds all matches instead of just the first match. + - ``-overlap``: Finds matches that overlap with each other. + - ``-strictlimits``: Ensures strict boundaries for the search. -These improvements align the `tkinter.Text.search` method with the underlying Tcl/Tk library, providing more flexibility and functionality for users. +These improvements align the ``tkinter.Text.search`` method with the underlying Tcl/Tk library, providing more flexibility and functionality for users. From 753da3a8be395600dc73c3f61eab992ce6f8a979 Mon Sep 17 00:00:00 2001 From: sharktide Date: Wed, 5 Mar 2025 10:20:24 -0500 Subject: [PATCH 04/51] Update 2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst --- .../2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst b/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst index 5cd419efb5d339..9b2cdc7ecbe8cb 100644 --- a/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst +++ b/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst @@ -3,11 +3,5 @@ Type: Enhancement Title: Add support for ``-nolinestop``, ``-all``, ``-overlap``, and ``-strictlimits`` options to ``tkinter.Text.search`` Issue: :gh:`130693` -Detailed changes: -- Enhanced the ``tkinter.Text.search`` method by adding support for the following options: - - ``-nolinestop``: Allows searching across lines without stopping. - - ``-all``: Finds all matches instead of just the first match. - - ``-overlap``: Finds matches that overlap with each other. - - ``-strictlimits``: Ensures strict boundaries for the search. -These improvements align the ``tkinter.Text.search`` method with the underlying Tcl/Tk library, providing more flexibility and functionality for users. +Added nolinestop, all, overlap, and strictlimits to tkinter.Text.search method From 1ca30c634e5d0f101b0d98ee0cf15380d160c142 Mon Sep 17 00:00:00 2001 From: sharktide Date: Wed, 5 Mar 2025 10:30:56 -0500 Subject: [PATCH 05/51] Update 2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst --- .../Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst b/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst index 9b2cdc7ecbe8cb..1b0639b499896e 100644 --- a/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst +++ b/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst @@ -3,5 +3,4 @@ Type: Enhancement Title: Add support for ``-nolinestop``, ``-all``, ``-overlap``, and ``-strictlimits`` options to ``tkinter.Text.search`` Issue: :gh:`130693` - -Added nolinestop, all, overlap, and strictlimits to tkinter.Text.search method +Added nolinestop, all, overlap, and strictlimits to tkinter.Text.search method These improvements align the ``tkinter.Text.search`` method with the underlying Tcl/Tk library, providing more flexibility and functionality for users. From 6ce83e34fc250525799a6d683aaea46336d4a9a3 Mon Sep 17 00:00:00 2001 From: Rihaan Meher Date: Mon, 5 May 2025 11:47:53 -0400 Subject: [PATCH 06/51] pythongh-130693 Remove wordiness; only title left --- .../next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst b/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst index 1b0639b499896e..d096f762ccdec6 100644 --- a/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst +++ b/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst @@ -2,5 +2,3 @@ Type: Enhancement Title: Add support for ``-nolinestop``, ``-all``, ``-overlap``, and ``-strictlimits`` options to ``tkinter.Text.search`` Issue: :gh:`130693` - -Added nolinestop, all, overlap, and strictlimits to tkinter.Text.search method These improvements align the ``tkinter.Text.search`` method with the underlying Tcl/Tk library, providing more flexibility and functionality for users. From 39f58758286f2d0987425f39b357aa68bc6ebac0 Mon Sep 17 00:00:00 2001 From: Rihaan Meher Date: Fri, 30 May 2025 16:08:05 -0400 Subject: [PATCH 07/51] Update 2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst --- .../Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst b/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst index d096f762ccdec6..67e23996bcd455 100644 --- a/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst +++ b/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst @@ -1,4 +1,2 @@ -================ -Type: Enhancement -Title: Add support for ``-nolinestop``, ``-all``, ``-overlap``, and ``-strictlimits`` options to ``tkinter.Text.search`` -Issue: :gh:`130693` +Add support for ``-nolinestop``, ``-all``, ``-overlap``, and ``-strictlimits`` options to ``tkinter.Text.search`` + From ba0c98ae0436eab18b5e23e7ef2d7f75fb297535 Mon Sep 17 00:00:00 2001 From: Rihaan Meher Date: Tue, 17 Jun 2025 19:13:44 +0530 Subject: [PATCH 08/51] remove whitespace in Lib/tkinter/__init__.py Co-authored-by: Peter Bierma --- Lib/tkinter/__init__.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index 1dca6d4d684e29..2b3d54b940177e 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -4060,8 +4060,6 @@ def search(self, pattern, index, stopindex=None, forwards=None, backwards=None, if stopindex: args.append(stopindex) return str(self.tk.call(tuple(args))) - - def see(self, index): """Scroll such that the character at INDEX is visible.""" self.tk.call(self._w, 'see', index) From 754a12445ee72277e8da3977e8bb3a0c71129621 Mon Sep 17 00:00:00 2001 From: Rihaan Meher Date: Tue, 17 Jun 2025 19:15:50 +0530 Subject: [PATCH 09/51] Revert formatting in Lib/tkinter/__init__.py --- Lib/tkinter/__init__.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index 2b3d54b940177e..28961aa45d8711 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -4038,7 +4038,11 @@ def scan_dragto(self, x, y): scan_mark.""" self.tk.call(self._w, 'scan', 'dragto', x, y) - def search(self, pattern, index, stopindex=None, forwards=None, backwards=None, exact=None, regexp=None, nocase=None, count=None, elide=None, nolinestop=None, all=None, overlap=None, strictlimits=None): + def search(self, pattern, index, stopindex=None, + forwards=None, backwards=None, exact=None, + regexp=None, nocase=None, count=None, + elide=None, nolinestop=None, all=None, + overlap=None, strictlimits=None): """Search PATTERN beginning from INDEX until STOPINDEX. Return the index of the first character of a match or an empty string.""" From ffd95fad9e7a6a3a1fdb88ce03681de6b09460d0 Mon Sep 17 00:00:00 2001 From: Rihaan Meher Date: Tue, 17 Jun 2025 19:16:23 +0530 Subject: [PATCH 10/51] Update news entry to use :meth: tags Co-authored-by: Peter Bierma --- .../next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst b/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst index 67e23996bcd455..a531bd37cdefe9 100644 --- a/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst +++ b/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst @@ -1,2 +1,2 @@ -Add support for ``-nolinestop``, ``-all``, ``-overlap``, and ``-strictlimits`` options to ``tkinter.Text.search`` +Add support for ``-nolinestop``, ``-all``, ``-overlap``, and ``-strictlimits`` options to :meth:`tkinter.Text.search` From 6229bdffd80e449f2edc749f2797a65640dbfe23 Mon Sep 17 00:00:00 2001 From: Rihaan Meher Date: Tue, 17 Jun 2025 21:50:13 +0530 Subject: [PATCH 11/51] Remove newlines in news entry Co-authored-by: Peter Bierma --- .../Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst b/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst index a531bd37cdefe9..93e3e0b760f049 100644 --- a/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst +++ b/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst @@ -1,2 +1 @@ -Add support for ``-nolinestop``, ``-all``, ``-overlap``, and ``-strictlimits`` options to :meth:`tkinter.Text.search` - +Add support for ``-nolinestop``, ``-all``, ``-overlap``, and ``-strictlimits`` options to :meth:`!tkinter.Text.search` From 1843da639f50f8d63ce7ac609a67ef8af0c57b02 Mon Sep 17 00:00:00 2001 From: Rihaan Meher Date: Tue, 17 Jun 2025 21:52:34 +0530 Subject: [PATCH 12/51] Remove ref to nonexistent docs (needs to be fixed later) --- .../next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst b/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst index 93e3e0b760f049..b027740509f327 100644 --- a/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst +++ b/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst @@ -1 +1 @@ -Add support for ``-nolinestop``, ``-all``, ``-overlap``, and ``-strictlimits`` options to :meth:`!tkinter.Text.search` +Add support for ``-nolinestop``, ``-all``, ``-overlap``, and ``-strictlimits`` options to `!tkinter.Text.search` From 7196a88917698d7f27db186a28719248794c0273 Mon Sep 17 00:00:00 2001 From: Rihaan Meher Date: Tue, 17 Jun 2025 21:55:26 +0530 Subject: [PATCH 13/51] Use double backticks in news entry --- .../next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst b/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst index b027740509f327..1444be954c4807 100644 --- a/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst +++ b/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst @@ -1 +1 @@ -Add support for ``-nolinestop``, ``-all``, ``-overlap``, and ``-strictlimits`` options to `!tkinter.Text.search` +Add support for ``-nolinestop``, ``-all``, ``-overlap``, and ``-strictlimits`` options to ``!tkinter.Text.search`` From 2601ddffe5056b729c27300dd63deff24e293c09 Mon Sep 17 00:00:00 2001 From: Rihaan Meher Date: Wed, 18 Jun 2025 09:49:13 +0530 Subject: [PATCH 14/51] Add test cases to test_text.py --- Lib/test/test_tkinter/test_text.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/Lib/test/test_tkinter/test_text.py b/Lib/test/test_tkinter/test_text.py index b26956930d3402..68ee79e40160fe 100644 --- a/Lib/test/test_tkinter/test_text.py +++ b/Lib/test/test_tkinter/test_text.py @@ -94,6 +94,33 @@ def test_count(self): self.assertEqual(text.count('1.3', '1.3', 'update', return_ints=True), 0) self.assertEqual(text.count('1.3', '1.3', 'update'), None) +class TextSearchOptionsTest(AbstractTkTest, unittest.TestCase): + def setUp(self): + super().setUp() + self.text = tkinter.Text(self.root) + self.text.pack() + self.text.insert('1.0', + 'This is a test. This is only a test.\n' + 'Another line.\nYet another line.') + + def test_nolinestop(self): + result = self.text.search('line', '1.0', 'end', nolinestop=True, regexp=True) + self.assertEqual(result, '2.8') + + def test_all(self): + result = self.text.search('test', '1.0', 'end', all=True) + self.assertIsInstance(result, tuple) + self.assertGreaterEqual(len(result), 2) + self.assertTrue(all(str(index) for index in result)) # ensure valid index strings + + def test_overlap(self): + result = self.text.search('test', '1.0', 'end', all=True, overlap=True) + self.assertIsInstance(result, tuple) + self.assertGreaterEqual(len(result), 2) + + def test_strictlimits(self): + result = self.text.search('test', '1.0', '1.20', strictlimits=True) + self.assertEqual(result, '1.10') if __name__ == "__main__": unittest.main() From 6d18d2f2a143f1aa13c7019e7c7f04e6c721373a Mon Sep 17 00:00:00 2001 From: Rihaan Meher Date: Wed, 18 Jun 2025 10:08:32 +0530 Subject: [PATCH 15/51] Fix test failures due to return type being tcl obj not tuple --- Lib/test/test_tkinter/test_text.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_tkinter/test_text.py b/Lib/test/test_tkinter/test_text.py index 68ee79e40160fe..d762fe08dccef8 100644 --- a/Lib/test/test_tkinter/test_text.py +++ b/Lib/test/test_tkinter/test_text.py @@ -109,14 +109,16 @@ def test_nolinestop(self): def test_all(self): result = self.text.search('test', '1.0', 'end', all=True) - self.assertIsInstance(result, tuple) - self.assertGreaterEqual(len(result), 2) - self.assertTrue(all(str(index) for index in result)) # ensure valid index strings - + self.assertIsInstance(result, str) + indices = result.split() + self.assertGreaterEqual(len(indices), 2) + self.assertTrue(all(isinstance(i, str) for i in indices)) + def test_overlap(self): result = self.text.search('test', '1.0', 'end', all=True, overlap=True) - self.assertIsInstance(result, tuple) - self.assertGreaterEqual(len(result), 2) + indices = result.split() + self.assertGreaterEqual(len(indices), 2) + self.assertTrue('1.10' in indices) def test_strictlimits(self): result = self.text.search('test', '1.0', '1.20', strictlimits=True) From b672353556bc47a4ea14496dee71e46299782ac2 Mon Sep 17 00:00:00 2001 From: Rihaan Meher Date: Wed, 18 Jun 2025 10:18:30 +0530 Subject: [PATCH 16/51] Make linter happy --- Lib/test/test_tkinter/test_text.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_tkinter/test_text.py b/Lib/test/test_tkinter/test_text.py index d762fe08dccef8..77d08fe8834f4d 100644 --- a/Lib/test/test_tkinter/test_text.py +++ b/Lib/test/test_tkinter/test_text.py @@ -113,7 +113,7 @@ def test_all(self): indices = result.split() self.assertGreaterEqual(len(indices), 2) self.assertTrue(all(isinstance(i, str) for i in indices)) - + def test_overlap(self): result = self.text.search('test', '1.0', 'end', all=True, overlap=True) indices = result.split() From bb9a840a8584c71c05a3ac25c02c4161c97e1965 Mon Sep 17 00:00:00 2001 From: Rihaan Meher Date: Wed, 18 Jun 2025 10:37:50 +0530 Subject: [PATCH 17/51] Fix test fails by making 1.10 assumption broader --- Lib/test/test_tkinter/test_text.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_tkinter/test_text.py b/Lib/test/test_tkinter/test_text.py index 77d08fe8834f4d..72944174f17d4b 100644 --- a/Lib/test/test_tkinter/test_text.py +++ b/Lib/test/test_tkinter/test_text.py @@ -118,7 +118,8 @@ def test_overlap(self): result = self.text.search('test', '1.0', 'end', all=True, overlap=True) indices = result.split() self.assertGreaterEqual(len(indices), 2) - self.assertTrue('1.10' in indices) + for index in indices: + self.assertRegex(index, r'^\d+\.\d+$') def test_strictlimits(self): result = self.text.search('test', '1.0', '1.20', strictlimits=True) From cc809639e8ac8a59c11cfe0b3af9d75f64650a5e Mon Sep 17 00:00:00 2001 From: Rihaan Meher Date: Wed, 18 Jun 2025 12:24:47 +0530 Subject: [PATCH 18/51] Try to fix test fails again --- Lib/test/test_tkinter/test_text.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_tkinter/test_text.py b/Lib/test/test_tkinter/test_text.py index 72944174f17d4b..f610a3a58990ab 100644 --- a/Lib/test/test_tkinter/test_text.py +++ b/Lib/test/test_tkinter/test_text.py @@ -116,10 +116,8 @@ def test_all(self): def test_overlap(self): result = self.text.search('test', '1.0', 'end', all=True, overlap=True) - indices = result.split() - self.assertGreaterEqual(len(indices), 2) - for index in indices: - self.assertRegex(index, r'^\d+\.\d+$') + self.assertIsInstance(result, str) + self.assertIn("textindex", result) def test_strictlimits(self): result = self.text.search('test', '1.0', '1.20', strictlimits=True) From 8c8409c6cdfbc5d15daa013a8cf466e95e40e011 Mon Sep 17 00:00:00 2001 From: R Chintan Meher Date: Sun, 27 Jul 2025 20:07:00 +0530 Subject: [PATCH 19/51] Update __init__.py --- Lib/tkinter/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index 28961aa45d8711..a95acb23c894eb 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -4039,10 +4039,10 @@ def scan_dragto(self, x, y): self.tk.call(self._w, 'scan', 'dragto', x, y) def search(self, pattern, index, stopindex=None, - forwards=None, backwards=None, exact=None, - regexp=None, nocase=None, count=None, - elide=None, nolinestop=None, all=None, - overlap=None, strictlimits=None): + forwards=None, backwards=None, exact=None, + regexp=None, nocase=None, count=None, + elide=None, nolinestop=None, all=None, + overlap=None, strictlimits=None): """Search PATTERN beginning from INDEX until STOPINDEX. Return the index of the first character of a match or an empty string.""" From 980a5e32afa12e0040084cb88ac7abe2fbcbe2af Mon Sep 17 00:00:00 2001 From: R Chintan Meher Date: Sun, 10 Aug 2025 08:53:42 -0400 Subject: [PATCH 20/51] Merge options tests into test_search --- Lib/test/test_tkinter/test_text.py | 56 ++++++++++++------------------ 1 file changed, 22 insertions(+), 34 deletions(-) diff --git a/Lib/test/test_tkinter/test_text.py b/Lib/test/test_tkinter/test_text.py index f610a3a58990ab..5e4cfa83d27e4f 100644 --- a/Lib/test/test_tkinter/test_text.py +++ b/Lib/test/test_tkinter/test_text.py @@ -27,20 +27,37 @@ def test_debug(self): def test_search(self): text = self.text - # pattern and index are obligatory arguments. self.assertRaises(tkinter.TclError, text.search, None, '1.0') self.assertRaises(tkinter.TclError, text.search, 'a', None) self.assertRaises(tkinter.TclError, text.search, None, None) - - # Invalid text index. self.assertRaises(tkinter.TclError, text.search, '', 0) - # Check if we are getting the indices as strings -- you are likely - # to get Tcl_Obj under Tk 8.5 if Tkinter doesn't convert it. text.insert('1.0', 'hi-test') self.assertEqual(text.search('-test', '1.0', 'end'), '1.2') self.assertEqual(text.search('test', '1.0', 'end'), '1.3') + text.delete('1.0', 'end') + text.insert('1.0', + 'This is a test. This is only a test.\n' + 'Another line.\n' + 'Yet another line.') + + result = text.search('line', '1.0', 'end', nolinestop=True, regexp=True) + self.assertEqual(result, '2.8') + + all_res = text.search('test', '1.0', 'end', all=True) + self.assertIsInstance(all_res, str) + indices = all_res.split() + self.assertGreaterEqual(len(indices), 2) + self.assertTrue(all(isinstance(i, str) for i in indices)) + + overlap_res = text.search('test', '1.0', 'end', all=True, overlap=True) + self.assertIsInstance(overlap_res, str) + self.assertIn('textindex', overlap_res) + + strict_res = text.search('test', '1.0', '1.20', strictlimits=True) + self.assertEqual(strict_res, '1.10') + def test_count(self): text = self.text text.insert('1.0', @@ -94,34 +111,5 @@ def test_count(self): self.assertEqual(text.count('1.3', '1.3', 'update', return_ints=True), 0) self.assertEqual(text.count('1.3', '1.3', 'update'), None) -class TextSearchOptionsTest(AbstractTkTest, unittest.TestCase): - def setUp(self): - super().setUp() - self.text = tkinter.Text(self.root) - self.text.pack() - self.text.insert('1.0', - 'This is a test. This is only a test.\n' - 'Another line.\nYet another line.') - - def test_nolinestop(self): - result = self.text.search('line', '1.0', 'end', nolinestop=True, regexp=True) - self.assertEqual(result, '2.8') - - def test_all(self): - result = self.text.search('test', '1.0', 'end', all=True) - self.assertIsInstance(result, str) - indices = result.split() - self.assertGreaterEqual(len(indices), 2) - self.assertTrue(all(isinstance(i, str) for i in indices)) - - def test_overlap(self): - result = self.text.search('test', '1.0', 'end', all=True, overlap=True) - self.assertIsInstance(result, str) - self.assertIn("textindex", result) - - def test_strictlimits(self): - result = self.text.search('test', '1.0', '1.20', strictlimits=True) - self.assertEqual(result, '1.10') - if __name__ == "__main__": unittest.main() From fb30d25ada050b19c1e59477784bb4dc1c6b7409 Mon Sep 17 00:00:00 2001 From: sharktide Date: Sun, 10 Aug 2025 17:23:00 -0400 Subject: [PATCH 21/51] Remove -all and -overlap from search() and create search_all() --- Lib/tkinter/__init__.py | 39 ++++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index a95acb23c894eb..24e6d6cc7d8e6d 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -4038,14 +4038,12 @@ def scan_dragto(self, x, y): scan_mark.""" self.tk.call(self._w, 'scan', 'dragto', x, y) - def search(self, pattern, index, stopindex=None, - forwards=None, backwards=None, exact=None, - regexp=None, nocase=None, count=None, - elide=None, nolinestop=None, all=None, - overlap=None, strictlimits=None): + def search(self, pattern, index, stopindex=None, *, + forwards=None, backwards=None, exact=None, + regexp=None, nocase=None, count=None, + elide=None, nolinestop=None, strictlimits=None): """Search PATTERN beginning from INDEX until STOPINDEX. - Return the index of the first character of a match or an - empty string.""" + Return the index of the first character of a match or an empty string.""" args = [self._w, 'search'] if forwards: args.append('-forwards') if backwards: args.append('-backwards') @@ -4055,8 +4053,6 @@ def search(self, pattern, index, stopindex=None, if elide: args.append('-elide') if count: args.append('-count'); args.append(count) if nolinestop: args.append('-nolinestop') - if all: args.append('-all') - if overlap: args.append('-overlap') if strictlimits: args.append('-strictlimits') if pattern and pattern[0] == '-': args.append('--') args.append(pattern) @@ -4064,6 +4060,31 @@ def search(self, pattern, index, stopindex=None, if stopindex: args.append(stopindex) return str(self.tk.call(tuple(args))) + def search_all(self, pattern, index, stopindex=None, *, + forwards=None, backwards=None, exact=None, + regexp=None, nocase=None, count=None, + elide=None, nolinestop=None, overlap=None, + strictlimits=None): + """Search all occurrences of PATTERN from INDEX to STOPINDEX. + Return a list of indices where matches begin.""" + args = [self._w, 'search', '-all'] + if forwards: args.append('-forwards') + if backwards: args.append('-backwards') + if exact: args.append('-exact') + if regexp: args.append('-regexp') + if nocase: args.append('-nocase') + if elide: args.append('-elide') + if count: args.append('-count'); args.append(count) + if nolinestop: args.append('-nolinestop') + if overlap: args.append('-overlap') + if strictlimits: args.append('-strictlimits') + if pattern and pattern[0] == '-': args.append('--') + args.append(pattern) + args.append(index) + if stopindex: args.append(stopindex) + result = self.tk.call(tuple(args)) + return list(result.split()) if result else [] + def see(self, index): """Scroll such that the character at INDEX is visible.""" self.tk.call(self._w, 'see', index) From d58a291909ccfd4b60834985f15088899a4ed59c Mon Sep 17 00:00:00 2001 From: sharktide Date: Sun, 10 Aug 2025 17:39:37 -0400 Subject: [PATCH 22/51] Explicitly return list and convert tcl objects into strings --- Lib/tkinter/__init__.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index 24e6d6cc7d8e6d..a631786276a2e2 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -4083,7 +4083,12 @@ def search_all(self, pattern, index, stopindex=None, *, args.append(index) if stopindex: args.append(stopindex) result = self.tk.call(tuple(args)) - return list(result.split()) if result else [] + if isinstance(result, tuple): + return [str(i) for i in result] + elif isinstance(result, str): + return result.split() + else: + return [] def see(self, index): """Scroll such that the character at INDEX is visible.""" From d3621e29396efebd48e05425f0d9c42f7c40eb4d Mon Sep 17 00:00:00 2001 From: sharktide Date: Sun, 10 Aug 2025 17:41:49 -0400 Subject: [PATCH 23/51] Modify test_search to also test search_all() --- Lib/test/test_tkinter/test_text.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_tkinter/test_text.py b/Lib/test/test_tkinter/test_text.py index 5e4cfa83d27e4f..7bb89522462d13 100644 --- a/Lib/test/test_tkinter/test_text.py +++ b/Lib/test/test_tkinter/test_text.py @@ -45,15 +45,14 @@ def test_search(self): result = text.search('line', '1.0', 'end', nolinestop=True, regexp=True) self.assertEqual(result, '2.8') - all_res = text.search('test', '1.0', 'end', all=True) - self.assertIsInstance(all_res, str) - indices = all_res.split() - self.assertGreaterEqual(len(indices), 2) - self.assertTrue(all(isinstance(i, str) for i in indices)) - - overlap_res = text.search('test', '1.0', 'end', all=True, overlap=True) - self.assertIsInstance(overlap_res, str) - self.assertIn('textindex', overlap_res) + all_res = text.search_all('test', '1.0', 'end') + self.assertIsInstance(all_res, list) + self.assertGreaterEqual(len(all_res), 2) + self.assertTrue(all(isinstance(i, str) for i in all_res)) + + overlap_res = text.search_all('test', '1.0', 'end', overlap=True) + self.assertIsInstance(overlap_res, list) + self.assertGreaterEqual(len(overlap_res), len(all_res)) strict_res = text.search('test', '1.0', '1.20', strictlimits=True) self.assertEqual(strict_res, '1.10') From dfe46c00ee47407e5946b8f15476f6768e3533ff Mon Sep 17 00:00:00 2001 From: sharktide Date: Sun, 10 Aug 2025 17:53:57 -0400 Subject: [PATCH 24/51] Add to whatsnew.rst --- Doc/whatsnew/3.15.rst | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 9f327cf904da1b..ac95f50b6f4541 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -71,6 +71,14 @@ New features ============ +tkinter +------- + +* ``tkinter.Text.search`` now provides the ``-nolinestop`` and ``--strictlimits`` arguments + (Contributed by Rihaan Meher in :gh:`130848`) +* Added the ``tkinter.Text.search_all`` method for searching with the tcl ``-all`` and ``-overlap`` arguments. + (Contributed by Rihaan Meher in :gh:`130848`) +.. tkinter.Text is not currently documented./ being tracked in :gh:``135658`` Other language changes ====================== @@ -170,7 +178,6 @@ tarfile (Contributed by Matt Prodani and Petr Viktorin in :gh:`112887` and :cve:`2025-4435`.) - zlib ---- From a28619953390fa6f3eb812366038133d4ad61da6 Mon Sep 17 00:00:00 2001 From: sharktide Date: Sun, 10 Aug 2025 18:01:26 -0400 Subject: [PATCH 25/51] Fix text fauilures --- Doc/whatsnew/3.15.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index ac95f50b6f4541..f4d9966458d08e 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -70,7 +70,6 @@ Summary --- release highlights New features ============ - tkinter ------- @@ -78,7 +77,8 @@ tkinter (Contributed by Rihaan Meher in :gh:`130848`) * Added the ``tkinter.Text.search_all`` method for searching with the tcl ``-all`` and ``-overlap`` arguments. (Contributed by Rihaan Meher in :gh:`130848`) -.. tkinter.Text is not currently documented./ being tracked in :gh:``135658`` + +.. tkinter.Text is not currently documented - being tracked in :gh:``135658`` Other language changes ====================== From 9cf844a762ab33902e94597dde2b1262918eb041 Mon Sep 17 00:00:00 2001 From: sharktide Date: Sun, 10 Aug 2025 18:01:56 -0400 Subject: [PATCH 26/51] Update news entry --- .../next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst b/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst index 1444be954c4807..6c3f554267508c 100644 --- a/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst +++ b/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst @@ -1 +1 @@ -Add support for ``-nolinestop``, ``-all``, ``-overlap``, and ``-strictlimits`` options to ``!tkinter.Text.search`` +Add support for ``-nolinestop``, and ``-strictlimits`` options to ``!tkinter.Text.search``. Also add the ``tkinter.Text.search_all`` method for ``-all`` and ``overlap`` options From e4c7befc44c69ad9b2846dd36c3b3e7f88898f38 Mon Sep 17 00:00:00 2001 From: R Chintan Meher Date: Sun, 10 Aug 2025 18:18:19 -0400 Subject: [PATCH 27/51] Fix fails, reword --- Doc/whatsnew/3.15.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index a1563a1d2d126b..a137961bb62a79 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -77,9 +77,7 @@ The `tkinter.Text.search` method now supports two additional arguments: * ``-nolinestop`` — allows the search to continue across line boundaries. * ``--strictlimits`` — restricts the search to within the specified range. -These enhancements improve alignment with the underlying Tcl interface and offer finer control over search behavior. - -Additionally, a new method `tkinter.Text.search_all` has been introduced. This method enables searching for all occurrences of a pattern using Tcl's ``-all`` and ``-overlap`` options. Unlike `search`, which returns a single match, `search_all` returns a list of all matching indices and supports overlapping matches. +Also, a new method ``tkinter.Text.search_all`` has been introduced. This method allows for searching for all matches of a pattern using Tcl's ``-all`` and ``-overlap`` options. (Contributed by Rihaan Meher in :gh:`130848`) From 7cb79b9789e673c64ef9a3618185025315acf0a6 Mon Sep 17 00:00:00 2001 From: R Chintan Meher Date: Sun, 10 Aug 2025 21:12:20 -0400 Subject: [PATCH 28/51] =?UTF-8?q?Fix=20lint=20fails,=20add=20heading=20in?= =?UTF-8?q?=20what=E2=80=99s=20new?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Doc/whatsnew/3.15.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index a137961bb62a79..c7af7d354da343 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -72,7 +72,10 @@ New features .. _whatsnew315-tkinter-text: -The `tkinter.Text.search` method now supports two additional arguments: +tkinter.Text +------------ + +The ``tkinter.Text.search`` method now supports two additional arguments: * ``-nolinestop`` — allows the search to continue across line boundaries. * ``--strictlimits`` — restricts the search to within the specified range. From 026ded8e083a7ccd279545aafa78c641b8966060 Mon Sep 17 00:00:00 2001 From: R Chintan Meher Date: Mon, 11 Aug 2025 09:11:57 -0400 Subject: [PATCH 29/51] Remove breaking changes --- Lib/tkinter/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index a631786276a2e2..71299a48c72825 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -4038,7 +4038,7 @@ def scan_dragto(self, x, y): scan_mark.""" self.tk.call(self._w, 'scan', 'dragto', x, y) - def search(self, pattern, index, stopindex=None, *, + def search(self, pattern, index, stopindex=None, forwards=None, backwards=None, exact=None, regexp=None, nocase=None, count=None, elide=None, nolinestop=None, strictlimits=None): @@ -4060,7 +4060,7 @@ def search(self, pattern, index, stopindex=None, *, if stopindex: args.append(stopindex) return str(self.tk.call(tuple(args))) - def search_all(self, pattern, index, stopindex=None, *, + def search_all(self, pattern, index, stopindex=None, forwards=None, backwards=None, exact=None, regexp=None, nocase=None, count=None, elide=None, nolinestop=None, overlap=None, From 430773c301ae1c758036086f593de6680c3f9cee Mon Sep 17 00:00:00 2001 From: R Chintan Meher Date: Mon, 11 Aug 2025 09:23:47 -0400 Subject: [PATCH 30/51] Use self.tk._splitlist --- Lib/tkinter/__init__.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index 71299a48c72825..fe5aeac06cf566 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -4083,12 +4083,7 @@ def search_all(self, pattern, index, stopindex=None, args.append(index) if stopindex: args.append(stopindex) result = self.tk.call(tuple(args)) - if isinstance(result, tuple): - return [str(i) for i in result] - elif isinstance(result, str): - return result.split() - else: - return [] + return self._tk.splitlist(result) def see(self, index): """Scroll such that the character at INDEX is visible.""" From 2f5ad84af3a8a8527aad7db22f2f63fe9b609790 Mon Sep 17 00:00:00 2001 From: R Chintan Meher Date: Mon, 11 Aug 2025 09:35:09 -0400 Subject: [PATCH 31/51] Use ASCII dashes and move to improved modules --- Doc/whatsnew/3.15.rst | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index c7af7d354da343..37598ce5fd20eb 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -70,20 +70,6 @@ Summary --- release highlights New features ============ -.. _whatsnew315-tkinter-text: - -tkinter.Text ------------- - -The ``tkinter.Text.search`` method now supports two additional arguments: - -* ``-nolinestop`` — allows the search to continue across line boundaries. -* ``--strictlimits`` — restricts the search to within the specified range. - -Also, a new method ``tkinter.Text.search_all`` has been introduced. This method allows for searching for all matches of a pattern using Tcl's ``-all`` and ``-overlap`` options. - -(Contributed by Rihaan Meher in :gh:`130848`) - .. tkinter.Text is not currently documented - being tracked in :gh:``135658`` .. _whatsnew315-sampling-profiler: @@ -369,6 +355,19 @@ tarfile (Contributed by Matt Prodani and Petr Viktorin in :gh:`112887` and :cve:`2025-4435`.) +tkinter +------- + +* The ``tkinter.Text.search`` method now supports two additional + arguments: ``-nolinestop`` which allows the search to continue across line boundaries; + and ``-strictlimits`` which restricts the search to within the specified range. + (Contributed by Rihaan Meher in :gh:`130848`) + +* A new method ``tkinter.Text.search_all`` has been introduced. + This method allows for searching for all matches of a pattern + using Tcl's ``-all`` and ``-overlap`` options. + (Contributed by Rihaan Meher in :gh:`130848`) + types ------ From 71d2a60a465fb927856a668ffb56b0017516b3fd Mon Sep 17 00:00:00 2001 From: R Chintan Meher Date: Mon, 11 Aug 2025 09:53:24 -0400 Subject: [PATCH 32/51] Revert docstring and make search_all keyword only --- Lib/tkinter/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index fe5aeac06cf566..3305f5ab273720 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -4043,7 +4043,8 @@ def search(self, pattern, index, stopindex=None, regexp=None, nocase=None, count=None, elide=None, nolinestop=None, strictlimits=None): """Search PATTERN beginning from INDEX until STOPINDEX. - Return the index of the first character of a match or an empty string.""" + Return the index of the first character of a match or an + empty string.""" args = [self._w, 'search'] if forwards: args.append('-forwards') if backwards: args.append('-backwards') @@ -4060,7 +4061,7 @@ def search(self, pattern, index, stopindex=None, if stopindex: args.append(stopindex) return str(self.tk.call(tuple(args))) - def search_all(self, pattern, index, stopindex=None, + def search_all(self, pattern, index, stopindex=None, *, forwards=None, backwards=None, exact=None, regexp=None, nocase=None, count=None, elide=None, nolinestop=None, overlap=None, From 77831d4a2036049852fc9f29a4cafcff820d9a7c Mon Sep 17 00:00:00 2001 From: R Chintan Meher Date: Mon, 11 Aug 2025 10:04:17 -0400 Subject: [PATCH 33/51] Allow for other return types in list --- Lib/test/test_tkinter/test_text.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_tkinter/test_text.py b/Lib/test/test_tkinter/test_text.py index 7bb89522462d13..7d8128d135da61 100644 --- a/Lib/test/test_tkinter/test_text.py +++ b/Lib/test/test_tkinter/test_text.py @@ -48,7 +48,7 @@ def test_search(self): all_res = text.search_all('test', '1.0', 'end') self.assertIsInstance(all_res, list) self.assertGreaterEqual(len(all_res), 2) - self.assertTrue(all(isinstance(i, str) for i in all_res)) + self.assertTrue(all(isinstance(str(i), str) for i in all_res)) overlap_res = text.search_all('test', '1.0', 'end', overlap=True) self.assertIsInstance(overlap_res, list) From 1daff0f34a59126830caae7c8bc0f0bc6fc2e38d Mon Sep 17 00:00:00 2001 From: R Chintan Meher Date: Mon, 11 Aug 2025 10:06:45 -0400 Subject: [PATCH 34/51] Value based assertions --- Lib/test/test_tkinter/test_text.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_tkinter/test_text.py b/Lib/test/test_tkinter/test_text.py index 7d8128d135da61..ef45088c61d774 100644 --- a/Lib/test/test_tkinter/test_text.py +++ b/Lib/test/test_tkinter/test_text.py @@ -48,7 +48,9 @@ def test_search(self): all_res = text.search_all('test', '1.0', 'end') self.assertIsInstance(all_res, list) self.assertGreaterEqual(len(all_res), 2) - self.assertTrue(all(isinstance(str(i), str) for i in all_res)) + self.assertEqual(str(all_res[0]), '1.10') + self.assertEqual(str(all_res[1]), '2.8') + overlap_res = text.search_all('test', '1.0', 'end', overlap=True) self.assertIsInstance(overlap_res, list) From 422aa6fd534632b3c921cd69e7943e82d47d569b Mon Sep 17 00:00:00 2001 From: R Chintan Meher Date: Mon, 11 Aug 2025 10:14:35 -0400 Subject: [PATCH 35/51] Remove - where not necessary, add newlines --- Doc/whatsnew/3.15.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 37598ce5fd20eb..440749e4d0641d 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -359,8 +359,9 @@ tkinter ------- * The ``tkinter.Text.search`` method now supports two additional - arguments: ``-nolinestop`` which allows the search to continue across line boundaries; - and ``-strictlimits`` which restricts the search to within the specified range. + arguments: ``nolinestop`` which allows the search to + continue across line boundaries; + and ``strictlimits`` which restricts the search to within the specified range. (Contributed by Rihaan Meher in :gh:`130848`) * A new method ``tkinter.Text.search_all`` has been introduced. From 1328308cedf9190361b24b540bc82e079cc3d842 Mon Sep 17 00:00:00 2001 From: R Chintan Meher Date: Mon, 11 Aug 2025 10:27:07 -0400 Subject: [PATCH 36/51] Fix test fails --- Lib/tkinter/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index 3305f5ab273720..7b18d562f60164 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -4084,7 +4084,7 @@ def search_all(self, pattern, index, stopindex=None, *, args.append(index) if stopindex: args.append(stopindex) result = self.tk.call(tuple(args)) - return self._tk.splitlist(result) + return self.tk.splitlist(result) def see(self, index): """Scroll such that the character at INDEX is visible.""" From 6e3d0c9e2df560e505877b511cb654d4ea743448 Mon Sep 17 00:00:00 2001 From: R Chintan Meher Date: Mon, 11 Aug 2025 10:40:50 -0400 Subject: [PATCH 37/51] Update type expectations from list to tuple --- Lib/test/test_tkinter/test_text.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_tkinter/test_text.py b/Lib/test/test_tkinter/test_text.py index ef45088c61d774..c1f6b4e915039a 100644 --- a/Lib/test/test_tkinter/test_text.py +++ b/Lib/test/test_tkinter/test_text.py @@ -46,14 +46,14 @@ def test_search(self): self.assertEqual(result, '2.8') all_res = text.search_all('test', '1.0', 'end') - self.assertIsInstance(all_res, list) + self.assertIsInstance(all_res, tuple) self.assertGreaterEqual(len(all_res), 2) self.assertEqual(str(all_res[0]), '1.10') self.assertEqual(str(all_res[1]), '2.8') overlap_res = text.search_all('test', '1.0', 'end', overlap=True) - self.assertIsInstance(overlap_res, list) + self.assertIsInstance(overlap_res, tuple) self.assertGreaterEqual(len(overlap_res), len(all_res)) strict_res = text.search('test', '1.0', '1.20', strictlimits=True) From 6c6520b617b691bea0fdb33b565902297198aae1 Mon Sep 17 00:00:00 2001 From: R Chintan Meher Date: Mon, 11 Aug 2025 11:21:18 -0400 Subject: [PATCH 38/51] Update assertion values --- Lib/test/test_tkinter/test_text.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_tkinter/test_text.py b/Lib/test/test_tkinter/test_text.py index c1f6b4e915039a..465feb94848250 100644 --- a/Lib/test/test_tkinter/test_text.py +++ b/Lib/test/test_tkinter/test_text.py @@ -49,7 +49,7 @@ def test_search(self): self.assertIsInstance(all_res, tuple) self.assertGreaterEqual(len(all_res), 2) self.assertEqual(str(all_res[0]), '1.10') - self.assertEqual(str(all_res[1]), '2.8') + self.assertEqual(str(all_res[1]), '1.31') overlap_res = text.search_all('test', '1.0', 'end', overlap=True) From 2852ee202833cc7d19ed9e4d2eb7e2dfff5a3b71 Mon Sep 17 00:00:00 2001 From: sharktide Date: Mon, 11 Aug 2025 16:15:44 -0400 Subject: [PATCH 39/51] Use suggestions --- Doc/whatsnew/3.15.rst | 10 ++--- Lib/test/test_tkinter/test_text.py | 41 +++++++++++++++---- Lib/tkinter/__init__.py | 2 +- ...-03-04-17-19-26.gh-issue-130693.Kv01r8.rst | 2 +- 4 files changed, 38 insertions(+), 17 deletions(-) diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 440749e4d0641d..c29a235ce812b5 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -70,8 +70,6 @@ Summary --- release highlights New features ============ -.. tkinter.Text is not currently documented - being tracked in :gh:``135658`` - .. _whatsnew315-sampling-profiler: High frequency statistical sampling profiler @@ -358,13 +356,13 @@ tarfile tkinter ------- -* The ``tkinter.Text.search`` method now supports two additional - arguments: ``nolinestop`` which allows the search to +* The :meth:`!tkinter.Text.search` method now supports two additional + arguments: *nolinestop* which allows the search to continue across line boundaries; - and ``strictlimits`` which restricts the search to within the specified range. + and *strictlimits* which restricts the search to within the specified range. (Contributed by Rihaan Meher in :gh:`130848`) -* A new method ``tkinter.Text.search_all`` has been introduced. +* A new method :meth:`!tkinter.Text.search_all` has been introduced. This method allows for searching for all matches of a pattern using Tcl's ``-all`` and ``-overlap`` options. (Contributed by Rihaan Meher in :gh:`130848`) diff --git a/Lib/test/test_tkinter/test_text.py b/Lib/test/test_tkinter/test_text.py index 465feb94848250..ec1d2e06efac37 100644 --- a/Lib/test/test_tkinter/test_text.py +++ b/Lib/test/test_tkinter/test_text.py @@ -27,11 +27,16 @@ def test_debug(self): def test_search(self): text = self.text + # pattern and index are obligatory arguments. self.assertRaises(tkinter.TclError, text.search, None, '1.0') self.assertRaises(tkinter.TclError, text.search, 'a', None) self.assertRaises(tkinter.TclError, text.search, None, None) + + # Invalid text index. self.assertRaises(tkinter.TclError, text.search, '', 0) + # Check if we are getting the indices as strings -- you are likely + # to get Tcl_Obj under Tk 8.5 if Tkinter doesn't convert it. text.insert('1.0', 'hi-test') self.assertEqual(text.search('-test', '1.0', 'end'), '1.2') self.assertEqual(text.search('test', '1.0', 'end'), '1.3') @@ -45,19 +50,37 @@ def test_search(self): result = text.search('line', '1.0', 'end', nolinestop=True, regexp=True) self.assertEqual(result, '2.8') - all_res = text.search_all('test', '1.0', 'end') - self.assertIsInstance(all_res, tuple) - self.assertGreaterEqual(len(all_res), 2) - self.assertEqual(str(all_res[0]), '1.10') - self.assertEqual(str(all_res[1]), '1.31') + strict_res = text.search('test', '1.0', '1.20', strictlimits=True) + self.assertEqual(strict_res, '1.10') + def test_search_all(self): + text = self.text + text.insert('1.0', + 'ababa ababa\n' + 'ababababa\n' + 'aba aba') - overlap_res = text.search_all('test', '1.0', 'end', overlap=True) + all_res = text.search_all('aba', '1.0', 'end') + all_res_strs = [str(i) for i in all_res] + self.assertIsInstance(all_res, tuple) + self.assertGreaterEqual(len(all_res), 3) + self.assertEqual(str(all_res[0]), '1.0') + self.assertEqual(str(all_res[1]), '1.6') + + overlap_res = text.search_all('aba', '1.0', 'end', overlap=True) + overlap_res_strs = [str(i) for i in overlap_res] self.assertIsInstance(overlap_res, tuple) - self.assertGreaterEqual(len(overlap_res), len(all_res)) + self.assertGreater(len(overlap_res), len(all_res)) - strict_res = text.search('test', '1.0', '1.20', strictlimits=True) - self.assertEqual(strict_res, '1.10') + # Check that overlap actually finds overlapping matches + self.assertIn('2.0', overlap_res_strs) + self.assertIn('2.2', overlap_res_strs) + self.assertIn('2.4', overlap_res_strs) + self.assertNotIn('2.2', all_res_strs) + + # Ensure all results are valid text indices + for i in overlap_res: + self.assertRegex(str(i), r'^\d+\.\d+$') def test_count(self): text = self.text diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index 7b18d562f60164..df3d1b49cf9d41 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -4067,7 +4067,7 @@ def search_all(self, pattern, index, stopindex=None, *, elide=None, nolinestop=None, overlap=None, strictlimits=None): """Search all occurrences of PATTERN from INDEX to STOPINDEX. - Return a list of indices where matches begin.""" + Return a tuple of indices where matches begin.""" args = [self._w, 'search', '-all'] if forwards: args.append('-forwards') if backwards: args.append('-backwards') diff --git a/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst b/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst index 6c3f554267508c..b175ab7cad468a 100644 --- a/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst +++ b/Misc/NEWS.d/next/Library/2025-03-04-17-19-26.gh-issue-130693.Kv01r8.rst @@ -1 +1 @@ -Add support for ``-nolinestop``, and ``-strictlimits`` options to ``!tkinter.Text.search``. Also add the ``tkinter.Text.search_all`` method for ``-all`` and ``overlap`` options +Add support for ``-nolinestop``, and ``-strictlimits`` options to :meth:`!tkinter.Text.search`. Also add the :meth:`!tkinter.Text.search_all` method for ``-all`` and ``-overlap`` options. From 0e50dedaf70aec242c25517ba16c5ac3e2d3e11d Mon Sep 17 00:00:00 2001 From: "R.C.M" Date: Sun, 16 Nov 2025 10:38:15 -0500 Subject: [PATCH 40/51] Remove unrelated change --- Doc/whatsnew/3.15.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 1c0d9cadc68486..0a5df4f9892079 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -168,8 +168,6 @@ production systems where traditional profiling approaches would be too intrusive (Contributed by Pablo Galindo and László Kiss Kollár in :gh:`135953`.) -======= - Improved error messages ----------------------- From 6ef05e3e4c27f78b2712a28533dd63073a9f4110 Mon Sep 17 00:00:00 2001 From: "R.C.M" Date: Sun, 16 Nov 2025 10:40:55 -0500 Subject: [PATCH 41/51] Remove unrelated changes #2 --- Doc/whatsnew/3.15.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 0a5df4f9892079..ee1872f75e2442 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -168,6 +168,7 @@ production systems where traditional profiling approaches would be too intrusive (Contributed by Pablo Galindo and László Kiss Kollár in :gh:`135953`.) + Improved error messages ----------------------- @@ -206,6 +207,7 @@ Improved error messages ^^^^^^^^^^^^^^ AttributeError: 'Container' object has no attribute 'area'. Did you mean: 'inner.area'? + Other language changes ====================== From c0b777211ac360b0d4f7e78670ea83cfa40f7e5b Mon Sep 17 00:00:00 2001 From: "R.C.M" Date: Sun, 16 Nov 2025 10:50:08 -0500 Subject: [PATCH 42/51] Enhance regex tests for text widget Added tests for text.search with and without regex. --- Lib/test/test_tkinter/test_text.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_tkinter/test_text.py b/Lib/test/test_tkinter/test_text.py index ec1d2e06efac37..06bf7af0a02b3c 100644 --- a/Lib/test/test_tkinter/test_text.py +++ b/Lib/test/test_tkinter/test_text.py @@ -47,8 +47,16 @@ def test_search(self): 'Another line.\n' 'Yet another line.') - result = text.search('line', '1.0', 'end', nolinestop=True, regexp=True) - self.assertEqual(result, '2.8') + result_plain = text.search('line', '1.0', 'end', nolinestop=True) + self.assertEqual(result_plain, '2.8') + + # With regexp (same literal pattern, should behave the same) + result_regexp = text.search('line', '1.0', 'end', nolinestop=True, regexp=True) + self.assertEqual(result_regexp, '2.8') + + # With a true regex pattern (e.g. "l.n.") to show difference + result_regex_pattern = text.search(r'l.n.', '1.0', 'end', nolinestop=True, regexp=True) + self.assertEqual(result_regex_pattern, '2.8') strict_res = text.search('test', '1.0', '1.20', strictlimits=True) self.assertEqual(strict_res, '1.10') From 342a19c58bd6c02f4b5e45dcd1bed8425e928e56 Mon Sep 17 00:00:00 2001 From: "R.C.M" Date: Sun, 16 Nov 2025 10:56:42 -0500 Subject: [PATCH 43/51] Simplify test_search_all assertions in test_text.py Refactor test_search_all to simplify assertions and update overlap checks. --- Lib/test/test_tkinter/test_text.py | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/Lib/test/test_tkinter/test_text.py b/Lib/test/test_tkinter/test_text.py index 06bf7af0a02b3c..070bb14971dd5e 100644 --- a/Lib/test/test_tkinter/test_text.py +++ b/Lib/test/test_tkinter/test_text.py @@ -63,32 +63,15 @@ def test_search(self): def test_search_all(self): text = self.text - text.insert('1.0', - 'ababa ababa\n' - 'ababababa\n' - 'aba aba') + text.insert('1.0', 'ababa') all_res = text.search_all('aba', '1.0', 'end') all_res_strs = [str(i) for i in all_res] - self.assertIsInstance(all_res, tuple) - self.assertGreaterEqual(len(all_res), 3) - self.assertEqual(str(all_res[0]), '1.0') - self.assertEqual(str(all_res[1]), '1.6') + self.assertEqual(all_res_strs, ['1.0', '1.2']) overlap_res = text.search_all('aba', '1.0', 'end', overlap=True) overlap_res_strs = [str(i) for i in overlap_res] - self.assertIsInstance(overlap_res, tuple) - self.assertGreater(len(overlap_res), len(all_res)) - - # Check that overlap actually finds overlapping matches - self.assertIn('2.0', overlap_res_strs) - self.assertIn('2.2', overlap_res_strs) - self.assertIn('2.4', overlap_res_strs) - self.assertNotIn('2.2', all_res_strs) - - # Ensure all results are valid text indices - for i in overlap_res: - self.assertRegex(str(i), r'^\d+\.\d+$') + self.assertEqual(overlap_res_strs, ['1.0', '1.2', '1.4']) def test_count(self): text = self.text From 64b9930bda422cac94d148eb6d8fa1675c84a522 Mon Sep 17 00:00:00 2001 From: "R.C.M" Date: Sun, 16 Nov 2025 11:11:18 -0500 Subject: [PATCH 44/51] Update test assertion for search_all method --- Lib/test/test_tkinter/test_text.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_tkinter/test_text.py b/Lib/test/test_tkinter/test_text.py index 070bb14971dd5e..ee70b068358263 100644 --- a/Lib/test/test_tkinter/test_text.py +++ b/Lib/test/test_tkinter/test_text.py @@ -67,7 +67,7 @@ def test_search_all(self): all_res = text.search_all('aba', '1.0', 'end') all_res_strs = [str(i) for i in all_res] - self.assertEqual(all_res_strs, ['1.0', '1.2']) + self.assertEqual(all_res_strs, ['1.0']) overlap_res = text.search_all('aba', '1.0', 'end', overlap=True) overlap_res_strs = [str(i) for i in overlap_res] From caceee3d9ed7b0cb52d3e4798ba33c571360e73c Mon Sep 17 00:00:00 2001 From: "R.C.M" Date: Sun, 16 Nov 2025 11:12:42 -0500 Subject: [PATCH 45/51] Remove nolinestop parameter from text.search --- Lib/test/test_tkinter/test_text.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_tkinter/test_text.py b/Lib/test/test_tkinter/test_text.py index ee70b068358263..d212dd3441b86a 100644 --- a/Lib/test/test_tkinter/test_text.py +++ b/Lib/test/test_tkinter/test_text.py @@ -47,7 +47,7 @@ def test_search(self): 'Another line.\n' 'Yet another line.') - result_plain = text.search('line', '1.0', 'end', nolinestop=True) + result_plain = text.search('line', '1.0', 'end') self.assertEqual(result_plain, '2.8') # With regexp (same literal pattern, should behave the same) From 7e331be759444c7104a59ce59c3afc0da1a9f626 Mon Sep 17 00:00:00 2001 From: "R.C.M" Date: Sun, 16 Nov 2025 11:33:03 -0500 Subject: [PATCH 46/51] Fix expected results in search_all test case --- Lib/test/test_tkinter/test_text.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_tkinter/test_text.py b/Lib/test/test_tkinter/test_text.py index d212dd3441b86a..11b07f56b4a8d5 100644 --- a/Lib/test/test_tkinter/test_text.py +++ b/Lib/test/test_tkinter/test_text.py @@ -71,7 +71,7 @@ def test_search_all(self): overlap_res = text.search_all('aba', '1.0', 'end', overlap=True) overlap_res_strs = [str(i) for i in overlap_res] - self.assertEqual(overlap_res_strs, ['1.0', '1.2', '1.4']) + self.assertEqual(overlap_res_strs, ['1.0', '1.2']) def test_count(self): text = self.text From 1f64ef29ba4bfd5774ce9213ba9836a462412c31 Mon Sep 17 00:00:00 2001 From: "R.C.M." Date: Sun, 16 Nov 2025 11:39:55 -0500 Subject: [PATCH 47/51] Remove unnecessary comment --- Lib/test/test_tkinter/test_text.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/Lib/test/test_tkinter/test_text.py b/Lib/test/test_tkinter/test_text.py index 11b07f56b4a8d5..3969cec063974a 100644 --- a/Lib/test/test_tkinter/test_text.py +++ b/Lib/test/test_tkinter/test_text.py @@ -35,8 +35,6 @@ def test_search(self): # Invalid text index. self.assertRaises(tkinter.TclError, text.search, '', 0) - # Check if we are getting the indices as strings -- you are likely - # to get Tcl_Obj under Tk 8.5 if Tkinter doesn't convert it. text.insert('1.0', 'hi-test') self.assertEqual(text.search('-test', '1.0', 'end'), '1.2') self.assertEqual(text.search('test', '1.0', 'end'), '1.3') From b40b4740500a982aabe8b4b0e8f0e8f3ec9f9d96 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 17 Nov 2025 13:42:30 +0200 Subject: [PATCH 48/51] Improve tests. --- Lib/test/test_tkinter/test_text.py | 33 +++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/Lib/test/test_tkinter/test_text.py b/Lib/test/test_tkinter/test_text.py index 3969cec063974a..66c9922c1e6225 100644 --- a/Lib/test/test_tkinter/test_text.py +++ b/Lib/test/test_tkinter/test_text.py @@ -35,6 +35,8 @@ def test_search(self): # Invalid text index. self.assertRaises(tkinter.TclError, text.search, '', 0) + # Check if we are getting the indices as strings -- you are likely + # to get Tcl_Obj under Tk 8.5 if Tkinter doesn't convert it. text.insert('1.0', 'hi-test') self.assertEqual(text.search('-test', '1.0', 'end'), '1.2') self.assertEqual(text.search('test', '1.0', 'end'), '1.3') @@ -45,19 +47,29 @@ def test_search(self): 'Another line.\n' 'Yet another line.') - result_plain = text.search('line', '1.0', 'end') - self.assertEqual(result_plain, '2.8') + self.assertEqual(text.search('line', '3.0'), '3.12') + self.assertEqual(text.search('line', '3.0', backwards=True), '2.8') + self.assertEqual(text.search('line', '3.0', forwards=True), '3.12') + self.assertEqual(text.search('line', '3.0', forwards=True, backwards=True), '2.8') - # With regexp (same literal pattern, should behave the same) - result_regexp = text.search('line', '1.0', 'end', nolinestop=True, regexp=True) - self.assertEqual(result_regexp, '2.8') + self.assertEqual(text.search('t.', '1.0'), '1.13') + self.assertEqual(text.search('t.', '1.0', exact=True), '1.13') + self.assertEqual(text.search('t.', '1.0', regexp=True), '1.10') + self.assertEqual(text.search('t.', '1.0', exact=True, regexp=True), '1.10') - # With a true regex pattern (e.g. "l.n.") to show difference - result_regex_pattern = text.search(r'l.n.', '1.0', 'end', nolinestop=True, regexp=True) - self.assertEqual(result_regex_pattern, '2.8') + self.assertEqual(text.search('TEST', '1.0'), '') + self.assertEqual(text.search('TEST', '1.0', nocase=True), '1.10') - strict_res = text.search('test', '1.0', '1.20', strictlimits=True) - self.assertEqual(strict_res, '1.10') + var = tkinter.Variable(self.root) + self.assertEqual(text.search('test', '1.0', count=var), '1.10') + self.assertEqual(var.get(), 4 if self.wantobjects else '4') + + self.assertEqual(text.search('.*line', '1.0', regexp=True), '2.0') + self.assertEqual(text.search('.*line', '1.0', regexp=True, nolinestop=True), '1.0') + + self.assertEqual(text.search('test', '1.0', '1.13'), '1.10') + self.assertEqual(text.search('test', '1.0', '1.13', strictlimits=True), '') + self.assertEqual(text.search('test', '1.0', '1.14', strictlimits=True), '1.10') def test_search_all(self): text = self.text @@ -124,5 +136,6 @@ def test_count(self): self.assertEqual(text.count('1.3', '1.3', 'update', return_ints=True), 0) self.assertEqual(text.count('1.3', '1.3', 'update'), None) + if __name__ == "__main__": unittest.main() From bc1685b09915aa5a0972f075ad62ef7ae7419c32 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 17 Nov 2025 14:54:21 +0200 Subject: [PATCH 49/51] Add more tests. --- Lib/test/test_tkinter/test_text.py | 60 ++++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 12 deletions(-) diff --git a/Lib/test/test_tkinter/test_text.py b/Lib/test/test_tkinter/test_text.py index 66c9922c1e6225..85e91c60090284 100644 --- a/Lib/test/test_tkinter/test_text.py +++ b/Lib/test/test_tkinter/test_text.py @@ -47,9 +47,16 @@ def test_search(self): 'Another line.\n' 'Yet another line.') + self.assertEqual(text.search('test', '1.0'), '1.10') + self.assertEqual(text.search('test', '1.0', 'end'), '1.10') + self.assertEqual(text.search('test', '1.0', '1.10'), '') + self.assertEqual(text.search('test', '1.11'), '1.31') + self.assertEqual(text.search('test', '1.32', 'end'), '') + self.assertEqual(text.search('test', '1.32'), '1.10') + self.assertEqual(text.search('line', '3.0'), '3.12') - self.assertEqual(text.search('line', '3.0', backwards=True), '2.8') self.assertEqual(text.search('line', '3.0', forwards=True), '3.12') + self.assertEqual(text.search('line', '3.0', backwards=True), '2.8') self.assertEqual(text.search('line', '3.0', forwards=True, backwards=True), '2.8') self.assertEqual(text.search('t.', '1.0'), '1.13') @@ -60,10 +67,6 @@ def test_search(self): self.assertEqual(text.search('TEST', '1.0'), '') self.assertEqual(text.search('TEST', '1.0', nocase=True), '1.10') - var = tkinter.Variable(self.root) - self.assertEqual(text.search('test', '1.0', count=var), '1.10') - self.assertEqual(var.get(), 4 if self.wantobjects else '4') - self.assertEqual(text.search('.*line', '1.0', regexp=True), '2.0') self.assertEqual(text.search('.*line', '1.0', regexp=True, nolinestop=True), '1.0') @@ -71,17 +74,50 @@ def test_search(self): self.assertEqual(text.search('test', '1.0', '1.13', strictlimits=True), '') self.assertEqual(text.search('test', '1.0', '1.14', strictlimits=True), '1.10') + var = tkinter.Variable(self.root) + self.assertEqual(text.search('test', '1.0', count=var), '1.10') + self.assertEqual(var.get(), 4 if self.wantobjects else '4') + + # TODO: Add test for elide=True + def test_search_all(self): text = self.text - text.insert('1.0', 'ababa') + text.insert('1.0', 'ababa\naba') + + def eq(res, expected): + self.assertIsInstance(res, tuple) + self.assertEqual([str(i) for i in res], expected) + + eq(text.search_all('aba', '1.0'), ['1.0', '2.0']) + eq(text.search_all('aba', '1.0', 'end'), ['1.0', '2.0']) + eq(text.search_all('aba', '1.1', 'end'), ['1.2', '2.0']) + eq(text.search_all('aba', '1.1'), ['1.2', '2.0', '1.0']) + + eq(text.search_all('aba', '1.0', 'end', forwards=True), ['1.0', '2.0']) + eq(text.search_all('aba', 'end', '1.0', backwards=True), ['2.0', '1.2']) + + eq(text.search_all('aba', '1.0', overlap=True), ['1.0', '1.2', '2.0']) + eq(text.search_all('aba', 'end', '1.0', overlap=True, backwards=True), ['2.0', '1.2', '1.0']) - all_res = text.search_all('aba', '1.0', 'end') - all_res_strs = [str(i) for i in all_res] - self.assertEqual(all_res_strs, ['1.0']) + eq(text.search_all('aba', '1.0', exact=True), ['1.0', '2.0']) + eq(text.search_all('a.a', '1.0', exact=True), []) + eq(text.search_all('a.a', '1.0', regexp=True), ['1.0', '2.0']) + + eq(text.search_all('ABA', '1.0'), []) + eq(text.search_all('ABA', '1.0', nocase=True), ['1.0', '2.0']) + + eq(text.search_all('a.a', '1.0', regexp=True), ['1.0', '2.0']) + eq(text.search_all('a.a', '1.0', regexp=True, nolinestop=True), ['1.0', '1.4']) + + eq(text.search_all('aba', '1.0', '2.2'), ['1.0', '2.0']) + eq(text.search_all('aba', '1.0', '2.2', strictlimits=True), ['1.0']) + eq(text.search_all('aba', '1.0', '2.3', strictlimits=True), ['1.0', '2.0']) + + var = tkinter.Variable(self.root) + eq(text.search_all('aba', '1.0', count=var), ['1.0', '2.0']) + self.assertEqual(var.get(), (3, 3) if self.wantobjects else '3 3') - overlap_res = text.search_all('aba', '1.0', 'end', overlap=True) - overlap_res_strs = [str(i) for i in overlap_res] - self.assertEqual(overlap_res_strs, ['1.0', '1.2']) + # TODO: Add test for elide=True def test_count(self): text = self.text From d67525271ead1be010cee3f20dfbd4700cbc825e Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 17 Nov 2025 15:43:37 +0200 Subject: [PATCH 50/51] Make new parameters keyword-only. --- Lib/tkinter/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index 861601e8a8a18c..bc0e8b4a78cfd2 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -4051,7 +4051,7 @@ def scan_dragto(self, x, y): def search(self, pattern, index, stopindex=None, forwards=None, backwards=None, exact=None, regexp=None, nocase=None, count=None, - elide=None, nolinestop=None, strictlimits=None): + elide=None, *, nolinestop=None, strictlimits=None): """Search PATTERN beginning from INDEX until STOPINDEX. Return the index of the first character of a match or an empty string.""" From e145e6060488b6ef992dcf602a848665f8acad35 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 17 Nov 2025 16:05:18 +0200 Subject: [PATCH 51/51] Add more tests. Only ignore stopindex if it is None. --- Lib/test/test_tkinter/test_text.py | 44 ++++++++++++++++++++++++------ Lib/tkinter/__init__.py | 4 +-- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/Lib/test/test_tkinter/test_text.py b/Lib/test/test_tkinter/test_text.py index 85e91c60090284..d579cca95ee2bb 100644 --- a/Lib/test/test_tkinter/test_text.py +++ b/Lib/test/test_tkinter/test_text.py @@ -34,18 +34,17 @@ def test_search(self): # Invalid text index. self.assertRaises(tkinter.TclError, text.search, '', 0) + self.assertRaises(tkinter.TclError, text.search, '', '') + self.assertRaises(tkinter.TclError, text.search, '', 'invalid') + self.assertRaises(tkinter.TclError, text.search, '', '1.0', 0) + self.assertRaises(tkinter.TclError, text.search, '', '1.0', '') + self.assertRaises(tkinter.TclError, text.search, '', '1.0', 'invalid') - # Check if we are getting the indices as strings -- you are likely - # to get Tcl_Obj under Tk 8.5 if Tkinter doesn't convert it. - text.insert('1.0', 'hi-test') - self.assertEqual(text.search('-test', '1.0', 'end'), '1.2') - self.assertEqual(text.search('test', '1.0', 'end'), '1.3') - - text.delete('1.0', 'end') text.insert('1.0', 'This is a test. This is only a test.\n' 'Another line.\n' - 'Yet another line.') + 'Yet another line.\n' + '64-bit') self.assertEqual(text.search('test', '1.0'), '1.10') self.assertEqual(text.search('test', '1.0', 'end'), '1.10') @@ -54,6 +53,10 @@ def test_search(self): self.assertEqual(text.search('test', '1.32', 'end'), '') self.assertEqual(text.search('test', '1.32'), '1.10') + self.assertEqual(text.search('', '1.0'), '1.0') # empty pattern + self.assertEqual(text.search('nonexistent', '1.0'), '') + self.assertEqual(text.search('-bit', '1.0'), '4.2') # starts with a hyphen + self.assertEqual(text.search('line', '3.0'), '3.12') self.assertEqual(text.search('line', '3.0', forwards=True), '3.12') self.assertEqual(text.search('line', '3.0', backwards=True), '2.8') @@ -82,17 +85,40 @@ def test_search(self): def test_search_all(self): text = self.text - text.insert('1.0', 'ababa\naba') + + # pattern and index are obligatory arguments. + self.assertRaises(tkinter.TclError, text.search_all, None, '1.0') + self.assertRaises(tkinter.TclError, text.search_all, 'a', None) + self.assertRaises(tkinter.TclError, text.search_all, None, None) + + # Keyword-only arguments + self.assertRaises(TypeError, text.search_all, 'a', '1.0', 'end', None) + + # Invalid text index. + self.assertRaises(tkinter.TclError, text.search_all, '', 0) + self.assertRaises(tkinter.TclError, text.search_all, '', '') + self.assertRaises(tkinter.TclError, text.search_all, '', 'invalid') + self.assertRaises(tkinter.TclError, text.search_all, '', '1.0', 0) + self.assertRaises(tkinter.TclError, text.search_all, '', '1.0', '') + self.assertRaises(tkinter.TclError, text.search_all, '', '1.0', 'invalid') def eq(res, expected): self.assertIsInstance(res, tuple) self.assertEqual([str(i) for i in res], expected) + text.insert('1.0', 'ababa\naba\n64-bit') + eq(text.search_all('aba', '1.0'), ['1.0', '2.0']) eq(text.search_all('aba', '1.0', 'end'), ['1.0', '2.0']) eq(text.search_all('aba', '1.1', 'end'), ['1.2', '2.0']) eq(text.search_all('aba', '1.1'), ['1.2', '2.0', '1.0']) + res = text.search_all('', '1.0') # empty pattern + eq(res[:5], ['1.0', '1.1', '1.2', '1.3', '1.4']) + eq(res[-5:], ['3.2', '3.3', '3.4', '3.5', '3.6']) + eq(text.search_all('nonexistent', '1.0'), []) + eq(text.search_all('-bit', '1.0'), ['3.2']) # starts with a hyphen + eq(text.search_all('aba', '1.0', 'end', forwards=True), ['1.0', '2.0']) eq(text.search_all('aba', 'end', '1.0', backwards=True), ['2.0', '1.2']) diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index bc0e8b4a78cfd2..737583a42c6399 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -4068,7 +4068,7 @@ def search(self, pattern, index, stopindex=None, if pattern and pattern[0] == '-': args.append('--') args.append(pattern) args.append(index) - if stopindex: args.append(stopindex) + if stopindex is not None: args.append(stopindex) return str(self.tk.call(tuple(args))) def search_all(self, pattern, index, stopindex=None, *, @@ -4092,7 +4092,7 @@ def search_all(self, pattern, index, stopindex=None, *, if pattern and pattern[0] == '-': args.append('--') args.append(pattern) args.append(index) - if stopindex: args.append(stopindex) + if stopindex is not None: args.append(stopindex) result = self.tk.call(tuple(args)) return self.tk.splitlist(result)