mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	gh-97928: Change the behavior of tkinter.Text.count() (GH-98484)
It now always returns an integer if one or less counting options are specified. Previously it could return a single count as a 1-tuple, an integer (only if option "update" was specified) or None if no items found. The result is now the same if wantobjects is set to 0.
This commit is contained in:
		
							parent
							
								
									81eba76450
								
							
						
					
					
						commit
						b8c20f9049
					
				
					 5 changed files with 53 additions and 55 deletions
				
			
		|  | @ -940,7 +940,15 @@ Porting to Python 3.13 | ||||||
| This section lists previously described changes and other bugfixes | This section lists previously described changes and other bugfixes | ||||||
| that may require changes to your code. | that may require changes to your code. | ||||||
| 
 | 
 | ||||||
| * None yet | Changes in the Python API | ||||||
|  | ------------------------- | ||||||
|  | 
 | ||||||
|  | * :meth:`!tkinter.Text.count` now always returns an integer if one or less | ||||||
|  |   counting options are specified. | ||||||
|  |   Previously it could return a single count as a 1-tuple, an integer (only if | ||||||
|  |   option ``"update"`` was specified) or ``None`` if no items found. | ||||||
|  |   The result is now the same if ``wantobjects`` is set to ``0``. | ||||||
|  |   (Contributed by Serhiy Storchaka in :gh:`97928`.) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| Build Changes | Build Changes | ||||||
|  |  | ||||||
|  | @ -25,10 +25,9 @@ def get_end_linenumber(text): | ||||||
| 
 | 
 | ||||||
| def get_displaylines(text, index): | def get_displaylines(text, index): | ||||||
|     """Display height, in lines, of a logical line in a Tk text widget.""" |     """Display height, in lines, of a logical line in a Tk text widget.""" | ||||||
|     res = text.count(f"{index} linestart", |     return text.count(f"{index} linestart", | ||||||
|                      f"{index} lineend", |                       f"{index} lineend", | ||||||
|                      "displaylines") |                       "displaylines") | ||||||
|     return res[0] if res else 0 |  | ||||||
| 
 | 
 | ||||||
| def get_widget_padding(widget): | def get_widget_padding(widget): | ||||||
|     """Get the total padding of a Tk widget, including its border.""" |     """Get the total padding of a Tk widget, including its border.""" | ||||||
|  |  | ||||||
|  | @ -10,6 +10,7 @@ class TextTest(AbstractTkTest, unittest.TestCase): | ||||||
|     def setUp(self): |     def setUp(self): | ||||||
|         super().setUp() |         super().setUp() | ||||||
|         self.text = tkinter.Text(self.root) |         self.text = tkinter.Text(self.root) | ||||||
|  |         self.text.pack() | ||||||
| 
 | 
 | ||||||
|     def test_debug(self): |     def test_debug(self): | ||||||
|         text = self.text |         text = self.text | ||||||
|  | @ -41,8 +42,6 @@ def test_search(self): | ||||||
|         self.assertEqual(text.search('test', '1.0', 'end'), '1.3') |         self.assertEqual(text.search('test', '1.0', 'end'), '1.3') | ||||||
| 
 | 
 | ||||||
|     def test_count(self): |     def test_count(self): | ||||||
|         # XXX Some assertions do not check against the intended result, |  | ||||||
|         # but instead check the current result to prevent regression. |  | ||||||
|         text = self.text |         text = self.text | ||||||
|         text.insert('1.0', |         text.insert('1.0', | ||||||
|             'Lorem ipsum dolor sit amet,\n' |             'Lorem ipsum dolor sit amet,\n' | ||||||
|  | @ -53,44 +52,27 @@ def test_count(self): | ||||||
|         options = ('chars', 'indices', 'lines', |         options = ('chars', 'indices', 'lines', | ||||||
|                    'displaychars', 'displayindices', 'displaylines', |                    'displaychars', 'displayindices', 'displaylines', | ||||||
|                    'xpixels', 'ypixels') |                    'xpixels', 'ypixels') | ||||||
|         if self.wantobjects: |         self.assertEqual(len(text.count('1.0', 'end', *options)), 8) | ||||||
|             self.assertEqual(len(text.count('1.0', 'end', *options)), 8) |         self.assertEqual(text.count('1.0', 'end', 'chars', 'lines'), (124, 4)) | ||||||
|         else: |         self.assertEqual(text.count('1.3', '4.5', 'chars', 'lines'), (92, 3)) | ||||||
|             text.count('1.0', 'end', *options) |         self.assertEqual(text.count('4.5', '1.3', 'chars', 'lines'), (-92, -3)) | ||||||
|         self.assertEqual(text.count('1.0', 'end', 'chars', 'lines'), (124, 4) |         self.assertEqual(text.count('1.3', '1.3', 'chars', 'lines'), (0, 0)) | ||||||
|                          if self.wantobjects else '124 4') |         self.assertEqual(text.count('1.0', 'end', 'lines'), 4) | ||||||
|         self.assertEqual(text.count('1.3', '4.5', 'chars', 'lines'), (92, 3) |         self.assertEqual(text.count('end', '1.0', 'lines'), -4) | ||||||
|                          if self.wantobjects else '92 3') |         self.assertEqual(text.count('1.3', '1.5', 'lines'), 0) | ||||||
|         self.assertEqual(text.count('4.5', '1.3', 'chars', 'lines'), (-92, -3) |         self.assertEqual(text.count('1.3', '1.3', 'lines'), 0) | ||||||
|                          if self.wantobjects else '-92 -3') |         self.assertEqual(text.count('1.0', 'end'), 124)  # 'indices' by default | ||||||
|         self.assertEqual(text.count('1.3', '1.3', 'chars', 'lines'), (0, 0) |         self.assertEqual(text.count('1.0', 'end', 'indices'), 124) | ||||||
|                          if self.wantobjects else '0 0') |  | ||||||
|         self.assertEqual(text.count('1.0', 'end', 'lines'), (4,) |  | ||||||
|                          if self.wantobjects else ('4',)) |  | ||||||
|         self.assertEqual(text.count('end', '1.0', 'lines'), (-4,) |  | ||||||
|                          if self.wantobjects else ('-4',)) |  | ||||||
|         self.assertEqual(text.count('1.3', '1.5', 'lines'), None |  | ||||||
|                          if self.wantobjects else ('0',)) |  | ||||||
|         self.assertEqual(text.count('1.3', '1.3', 'lines'), None |  | ||||||
|                          if self.wantobjects else ('0',)) |  | ||||||
|         self.assertEqual(text.count('1.0', 'end'), (124,)  # 'indices' by default |  | ||||||
|                          if self.wantobjects else ('124',)) |  | ||||||
|         self.assertRaises(tkinter.TclError, text.count, '1.0', 'end', 'spam') |         self.assertRaises(tkinter.TclError, text.count, '1.0', 'end', 'spam') | ||||||
|         self.assertRaises(tkinter.TclError, text.count, '1.0', 'end', '-lines') |         self.assertRaises(tkinter.TclError, text.count, '1.0', 'end', '-lines') | ||||||
| 
 | 
 | ||||||
|         self.assertIsInstance(text.count('1.3', '1.5', 'ypixels'), tuple) |         self.assertIsInstance(text.count('1.3', '1.5', 'ypixels'), int) | ||||||
|         self.assertIsInstance(text.count('1.3', '1.5', 'update', 'ypixels'), int |         self.assertIsInstance(text.count('1.3', '1.5', 'update', 'ypixels'), int) | ||||||
|                               if self.wantobjects else str) |         self.assertEqual(text.count('1.3', '1.3', 'update', 'ypixels'), 0) | ||||||
|         self.assertEqual(text.count('1.3', '1.3', 'update', 'ypixels'), None |         self.assertEqual(text.count('1.3', '1.5', 'update', 'indices'), 2) | ||||||
|                          if self.wantobjects else '0') |         self.assertEqual(text.count('1.3', '1.3', 'update', 'indices'), 0) | ||||||
|         self.assertEqual(text.count('1.3', '1.5', 'update', 'indices'), 2 |         self.assertEqual(text.count('1.3', '1.5', 'update'), 2) | ||||||
|                          if self.wantobjects else '2') |         self.assertEqual(text.count('1.3', '1.3', 'update'), 0) | ||||||
|         self.assertEqual(text.count('1.3', '1.3', 'update', 'indices'), None |  | ||||||
|                          if self.wantobjects else '0') |  | ||||||
|         self.assertEqual(text.count('1.3', '1.5', 'update'), (2,) |  | ||||||
|                          if self.wantobjects else ('2',)) |  | ||||||
|         self.assertEqual(text.count('1.3', '1.3', 'update'), None |  | ||||||
|                          if self.wantobjects else ('0',)) |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| if __name__ == "__main__": | if __name__ == "__main__": | ||||||
|  |  | ||||||
|  | @ -3715,25 +3715,28 @@ def compare(self, index1, op, index2): | ||||||
|         return self.tk.getboolean(self.tk.call( |         return self.tk.getboolean(self.tk.call( | ||||||
|             self._w, 'compare', index1, op, index2)) |             self._w, 'compare', index1, op, index2)) | ||||||
| 
 | 
 | ||||||
|     def count(self, index1, index2, *args): # new in Tk 8.5 |     def count(self, index1, index2, *options): # new in Tk 8.5 | ||||||
|         """Counts the number of relevant things between the two indices. |         """Counts the number of relevant things between the two indices. | ||||||
|         If index1 is after index2, the result will be a negative number | 
 | ||||||
|  |         If INDEX1 is after INDEX2, the result will be a negative number | ||||||
|         (and this holds for each of the possible options). |         (and this holds for each of the possible options). | ||||||
| 
 | 
 | ||||||
|         The actual items which are counted depends on the options given by |         The actual items which are counted depends on the options given. | ||||||
|         args. The result is a list of integers, one for the result of each |         The result is a tuple of integers, one for the result of each | ||||||
|         counting option given. Valid counting options are "chars", |         counting option given, if more than one option is specified, | ||||||
|  |         otherwise it is an integer. Valid counting options are "chars", | ||||||
|         "displaychars", "displayindices", "displaylines", "indices", |         "displaychars", "displayindices", "displaylines", "indices", | ||||||
|         "lines", "xpixels" and "ypixels". There is an additional possible |         "lines", "xpixels" and "ypixels". The default value, if no | ||||||
|  |         option is specified, is "indices". There is an additional possible | ||||||
|         option "update", which if given then all subsequent options ensure |         option "update", which if given then all subsequent options ensure | ||||||
|         that any possible out of date information is recalculated.""" |         that any possible out of date information is recalculated.""" | ||||||
|         args = ['-%s' % arg for arg in args] |         options = ['-%s' % arg for arg in options] | ||||||
|         args += [index1, index2] |         res = self.tk.call(self._w, 'count', *options, index1, index2) | ||||||
|         res = self.tk.call(self._w, 'count', *args) or None |         if not isinstance(res, int): | ||||||
|         if res is not None and len(args) <= 3: |             res = self._getints(res) | ||||||
|             return (res, ) |             if len(res) == 1: | ||||||
|         else: |                 res, = res | ||||||
|             return res |         return res | ||||||
| 
 | 
 | ||||||
|     def debug(self, boolean=None): |     def debug(self, boolean=None): | ||||||
|         """Turn on the internal consistency checks of the B-Tree inside the text |         """Turn on the internal consistency checks of the B-Tree inside the text | ||||||
|  |  | ||||||
|  | @ -0,0 +1,6 @@ | ||||||
|  | Change the behavior of :meth:`tkinter.Text.count`. It now always returns an | ||||||
|  | integer if one or less counting options are specified. Previously it could | ||||||
|  | return a single count as a 1-tuple, an integer (only if option ``"update"`` | ||||||
|  | was specified) or ``None`` if no items found. The result is now the same if | ||||||
|  | ``wantobjects`` is set to ``0``. | ||||||
|  | 
 | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Serhiy Storchaka
						Serhiy Storchaka