mirror of
https://github.com/python/cpython
synced 2024-10-14 09:31:57 +00:00
gh-97928: Partially restore the behavior of tkinter.Text.count() by default (GH-115031)
By default, it preserves an inconsistent behavior of older Python versions: packs the count into a 1-tuple if only one or none options are specified (including 'update'), returns None instead of 0. Except that setting wantobjects to 0 no longer affects the result. Add a new parameter return_ints: specifying return_ints=True makes Text.count() always returning the single count as an integer instead of a 1-tuple or None.
This commit is contained in:
parent
5d2794a16b
commit
d2c4baa41f
|
@ -469,6 +469,12 @@ tkinter
|
||||||
a dict instead of a tuple.
|
a dict instead of a tuple.
|
||||||
(Contributed by Serhiy Storchaka in :gh:`43457`.)
|
(Contributed by Serhiy Storchaka in :gh:`43457`.)
|
||||||
|
|
||||||
|
* Add new optional keyword-only parameter *return_ints* in
|
||||||
|
the :meth:`!Text.count` method.
|
||||||
|
Passing ``return_ints=True`` makes it always returning the single count
|
||||||
|
as an integer instead of a 1-tuple or ``None``.
|
||||||
|
(Contributed by Serhiy Storchaka in :gh:`97928`.)
|
||||||
|
|
||||||
* Add support of the "vsapi" element type in
|
* Add support of the "vsapi" element type in
|
||||||
the :meth:`~tkinter.ttk.Style.element_create` method of
|
the :meth:`~tkinter.ttk.Style.element_create` method of
|
||||||
:class:`tkinter.ttk.Style`.
|
:class:`tkinter.ttk.Style`.
|
||||||
|
@ -1286,13 +1292,6 @@ that may require changes to your code.
|
||||||
Changes in the Python API
|
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`.)
|
|
||||||
|
|
||||||
* Functions :c:func:`PyDict_GetItem`, :c:func:`PyDict_GetItemString`,
|
* Functions :c:func:`PyDict_GetItem`, :c:func:`PyDict_GetItemString`,
|
||||||
:c:func:`PyMapping_HasKey`, :c:func:`PyMapping_HasKeyString`,
|
:c:func:`PyMapping_HasKey`, :c:func:`PyMapping_HasKeyString`,
|
||||||
:c:func:`PyObject_HasAttr`, :c:func:`PyObject_HasAttrString`, and
|
:c:func:`PyObject_HasAttr`, :c:func:`PyObject_HasAttrString`, and
|
||||||
|
|
|
@ -27,7 +27,7 @@ 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."""
|
||||||
return text.count(f"{index} linestart",
|
return text.count(f"{index} linestart",
|
||||||
f"{index} lineend",
|
f"{index} lineend",
|
||||||
"displaylines")
|
"displaylines", return_ints=True)
|
||||||
|
|
||||||
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."""
|
||||||
|
|
|
@ -52,27 +52,47 @@ def test_count(self):
|
||||||
options = ('chars', 'indices', 'lines',
|
options = ('chars', 'indices', 'lines',
|
||||||
'displaychars', 'displayindices', 'displaylines',
|
'displaychars', 'displayindices', 'displaylines',
|
||||||
'xpixels', 'ypixels')
|
'xpixels', 'ypixels')
|
||||||
|
self.assertEqual(len(text.count('1.0', 'end', *options, return_ints=True)), 8)
|
||||||
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))
|
self.assertEqual(text.count('1.0', 'end', 'chars', 'lines', return_ints=True),
|
||||||
|
(124, 4))
|
||||||
self.assertEqual(text.count('1.3', '4.5', 'chars', 'lines'), (92, 3))
|
self.assertEqual(text.count('1.3', '4.5', 'chars', 'lines'), (92, 3))
|
||||||
|
self.assertEqual(text.count('4.5', '1.3', 'chars', 'lines', return_ints=True),
|
||||||
|
(-92, -3))
|
||||||
self.assertEqual(text.count('4.5', '1.3', 'chars', 'lines'), (-92, -3))
|
self.assertEqual(text.count('4.5', '1.3', 'chars', 'lines'), (-92, -3))
|
||||||
|
self.assertEqual(text.count('1.3', '1.3', 'chars', 'lines', return_ints=True),
|
||||||
|
(0, 0))
|
||||||
self.assertEqual(text.count('1.3', '1.3', 'chars', 'lines'), (0, 0))
|
self.assertEqual(text.count('1.3', '1.3', 'chars', 'lines'), (0, 0))
|
||||||
self.assertEqual(text.count('1.0', 'end', 'lines'), 4)
|
self.assertEqual(text.count('1.0', 'end', 'lines', return_ints=True), 4)
|
||||||
self.assertEqual(text.count('end', '1.0', 'lines'), -4)
|
self.assertEqual(text.count('1.0', 'end', 'lines'), (4,))
|
||||||
self.assertEqual(text.count('1.3', '1.5', 'lines'), 0)
|
self.assertEqual(text.count('end', '1.0', 'lines', return_ints=True), -4)
|
||||||
self.assertEqual(text.count('1.3', '1.3', 'lines'), 0)
|
self.assertEqual(text.count('end', '1.0', 'lines'), (-4,))
|
||||||
self.assertEqual(text.count('1.0', 'end'), 124) # 'indices' by default
|
self.assertEqual(text.count('1.3', '1.5', 'lines', return_ints=True), 0)
|
||||||
self.assertEqual(text.count('1.0', 'end', 'indices'), 124)
|
self.assertEqual(text.count('1.3', '1.5', 'lines'), None)
|
||||||
|
self.assertEqual(text.count('1.3', '1.3', 'lines', return_ints=True), 0)
|
||||||
|
self.assertEqual(text.count('1.3', '1.3', 'lines'), None)
|
||||||
|
# Count 'indices' by default.
|
||||||
|
self.assertEqual(text.count('1.0', 'end', return_ints=True), 124)
|
||||||
|
self.assertEqual(text.count('1.0', 'end'), (124,))
|
||||||
|
self.assertEqual(text.count('1.0', 'end', 'indices', return_ints=True), 124)
|
||||||
|
self.assertEqual(text.count('1.0', 'end', 'indices'), (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'), int)
|
self.assertIsInstance(text.count('1.3', '1.5', 'ypixels', return_ints=True), int)
|
||||||
|
self.assertIsInstance(text.count('1.3', '1.5', 'ypixels'), tuple)
|
||||||
|
self.assertIsInstance(text.count('1.3', '1.5', 'update', 'ypixels', return_ints=True), int)
|
||||||
self.assertIsInstance(text.count('1.3', '1.5', 'update', 'ypixels'), int)
|
self.assertIsInstance(text.count('1.3', '1.5', 'update', 'ypixels'), int)
|
||||||
self.assertEqual(text.count('1.3', '1.3', 'update', 'ypixels'), 0)
|
self.assertEqual(text.count('1.3', '1.3', 'update', 'ypixels', return_ints=True), 0)
|
||||||
|
self.assertEqual(text.count('1.3', '1.3', 'update', 'ypixels'), None)
|
||||||
|
self.assertEqual(text.count('1.3', '1.5', 'update', 'indices', return_ints=True), 2)
|
||||||
self.assertEqual(text.count('1.3', '1.5', 'update', 'indices'), 2)
|
self.assertEqual(text.count('1.3', '1.5', 'update', 'indices'), 2)
|
||||||
self.assertEqual(text.count('1.3', '1.3', 'update', 'indices'), 0)
|
self.assertEqual(text.count('1.3', '1.3', 'update', 'indices', return_ints=True), 0)
|
||||||
self.assertEqual(text.count('1.3', '1.5', 'update'), 2)
|
self.assertEqual(text.count('1.3', '1.3', 'update', 'indices'), None)
|
||||||
self.assertEqual(text.count('1.3', '1.3', 'update'), 0)
|
self.assertEqual(text.count('1.3', '1.5', 'update', return_ints=True), 2)
|
||||||
|
self.assertEqual(text.count('1.3', '1.5', 'update'), (2,))
|
||||||
|
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__":
|
if __name__ == "__main__":
|
||||||
|
|
|
@ -3745,7 +3745,7 @@ 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, *options): # new in Tk 8.5
|
def count(self, index1, index2, *options, return_ints=False): # 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
|
||||||
|
@ -3753,19 +3753,26 @@ def count(self, index1, index2, *options): # new in Tk 8.5
|
||||||
|
|
||||||
The actual items which are counted depends on the options given.
|
The actual items which are counted depends on the options given.
|
||||||
The result is a tuple of integers, one for the result of each
|
The result is a tuple of integers, one for the result of each
|
||||||
counting option given, if more than one option is specified,
|
counting option given, if more than one option is specified or
|
||||||
otherwise it is an integer. Valid counting options are "chars",
|
return_ints is false (default), otherwise it is an integer.
|
||||||
"displaychars", "displayindices", "displaylines", "indices",
|
Valid counting options are "chars", "displaychars",
|
||||||
"lines", "xpixels" and "ypixels". The default value, if no
|
"displayindices", "displaylines", "indices", "lines", "xpixels"
|
||||||
option is specified, is "indices". There is an additional possible
|
and "ypixels". The default value, if no option is specified, is
|
||||||
option "update", which if given then all subsequent options ensure
|
"indices". There is an additional possible option "update",
|
||||||
that any possible out of date information is recalculated."""
|
which if given then all subsequent options ensure that any
|
||||||
|
possible out of date information is recalculated.
|
||||||
|
"""
|
||||||
options = ['-%s' % arg for arg in options]
|
options = ['-%s' % arg for arg in options]
|
||||||
res = self.tk.call(self._w, 'count', *options, index1, index2)
|
res = self.tk.call(self._w, 'count', *options, index1, index2)
|
||||||
if not isinstance(res, int):
|
if not isinstance(res, int):
|
||||||
res = self._getints(res)
|
res = self._getints(res)
|
||||||
if len(res) == 1:
|
if len(res) == 1:
|
||||||
res, = res
|
res, = res
|
||||||
|
if not return_ints:
|
||||||
|
if not res:
|
||||||
|
res = None
|
||||||
|
elif len(options) <= 1:
|
||||||
|
res = (res,)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def debug(self, boolean=None):
|
def debug(self, boolean=None):
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
Partially revert the behavior of :meth:`tkinter.Text.count`. By default it
|
||||||
|
preserves the behavior of older Python versions, except that setting
|
||||||
|
``wantobjects`` to 0 no longer has effect. Add a new parameter *return_ints*:
|
||||||
|
specifying ``return_ints=True`` makes ``Text.count()`` always returning the
|
||||||
|
single count as an integer instead of a 1-tuple or ``None``.
|
Loading…
Reference in a new issue