gh-97928: Partially restore the behavior of tkinter.Text.count() by default
diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst
index c25d41351c2f3c..6531d108d5ffe0 100644
--- a/Doc/whatsnew/3.13.rst
+++ b/Doc/whatsnew/3.13.rst
@@ -430,6 +430,12 @@ tkinter
   a dict instead of a tuple.
   (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
   the :meth:`~tkinter.ttk.Style.element_create` method of
   :class:`tkinter.ttk.Style`.
@@ -1247,13 +1253,6 @@ that may require changes to your code.
 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`,
   :c:func:`PyMapping_HasKey`, :c:func:`PyMapping_HasKeyString`,
   :c:func:`PyObject_HasAttr`, :c:func:`PyObject_HasAttrString`, and
diff --git a/Lib/idlelib/sidebar.py b/Lib/idlelib/sidebar.py
index ff77b568a786e0..aa19a24e3edef2 100644
--- a/Lib/idlelib/sidebar.py
+++ b/Lib/idlelib/sidebar.py
@@ -27,7 +27,7 @@ def get_displaylines(text, index):
     """Display height, in lines, of a logical line in a Tk text widget."""
     return text.count(f"{index} linestart",
                       f"{index} lineend",
-                      "displaylines")
+                      "displaylines", return_ints=True)
 
 def get_widget_padding(widget):
     """Get the total padding of a Tk widget, including its border."""
diff --git a/Lib/test/test_tkinter/test_text.py b/Lib/test/test_tkinter/test_text.py
index f809c4510e3a1f..b26956930d3402 100644
--- a/Lib/test/test_tkinter/test_text.py
+++ b/Lib/test/test_tkinter/test_text.py
@@ -52,27 +52,47 @@ def test_count(self):
         options = ('chars', 'indices', 'lines',
                    'displaychars', 'displayindices', 'displaylines',
                    '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(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('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('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.0', 'end', 'lines'), 4)
-        self.assertEqual(text.count('end', '1.0', 'lines'), -4)
-        self.assertEqual(text.count('1.3', '1.5', 'lines'), 0)
-        self.assertEqual(text.count('1.3', '1.3', 'lines'), 0)
-        self.assertEqual(text.count('1.0', 'end'), 124)  # 'indices' by default
-        self.assertEqual(text.count('1.0', 'end', 'indices'), 124)
+        self.assertEqual(text.count('1.0', 'end', 'lines', return_ints=True), 4)
+        self.assertEqual(text.count('1.0', 'end', 'lines'), (4,))
+        self.assertEqual(text.count('end', '1.0', 'lines', return_ints=True), -4)
+        self.assertEqual(text.count('end', '1.0', 'lines'), (-4,))
+        self.assertEqual(text.count('1.3', '1.5', 'lines', return_ints=True), 0)
+        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', '-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.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.3', 'update', 'indices'), 0)
-        self.assertEqual(text.count('1.3', '1.5', 'update'), 2)
-        self.assertEqual(text.count('1.3', '1.3', 'update'), 0)
+        self.assertEqual(text.count('1.3', '1.3', 'update', 'indices', return_ints=True), 0)
+        self.assertEqual(text.count('1.3', '1.3', 'update', 'indices'), None)
+        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__":
diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py
index 2be9da2cfb9299..175bfbd7d912d2 100644
--- a/Lib/tkinter/__init__.py
+++ b/Lib/tkinter/__init__.py
@@ -3745,7 +3745,7 @@ def compare(self, index1, op, index2):
         return self.tk.getboolean(self.tk.call(
             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.
 
         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 result is a tuple of integers, one for the result of each
-        counting option given, if more than one option is specified,
-        otherwise it is an integer. Valid counting options are "chars",
-        "displaychars", "displayindices", "displaylines", "indices",
-        "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
-        that any possible out of date information is recalculated."""
+        counting option given, if more than one option is specified or
+        return_ints is false (default), otherwise it is an integer.
+        Valid counting options are "chars", "displaychars",
+        "displayindices", "displaylines", "indices", "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 that any
+        possible out of date information is recalculated.
+        """
         options = ['-%s' % arg for arg in options]
         res = self.tk.call(self._w, 'count', *options, index1, index2)
         if not isinstance(res, int):
             res = self._getints(res)
             if len(res) == 1:
                 res, = res
+        if not return_ints:
+            if not res:
+                res = None
+            elif len(options) <= 1:
+                res = (res,)
         return res
 
     def debug(self, boolean=None):
diff --git a/Misc/NEWS.d/next/Library/2024-02-05-16-48-06.gh-issue-97928.JZCies.rst b/Misc/NEWS.d/next/Library/2024-02-05-16-48-06.gh-issue-97928.JZCies.rst
new file mode 100644
index 00000000000000..24fed926a95513
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-02-05-16-48-06.gh-issue-97928.JZCies.rst
@@ -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``.

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').
Except that setting wantobjects to 0 no longer affects the result.

Add a new parameter return_ints: specifying return_ints=True makes Text.count() returning the single count as an integer.

<!--
Thanks for your contribution!
Please read this comment in its entirety. It's quite important.

# Pull Request title

It should be in the following format:

```
gh-NNNNN: Summary of the changes made
```

Where: gh-NNNNN refers to the GitHub issue number.

Most PRs will require an issue number. Trivial changes, like fixing a typo, do not need an issue.

# Backport Pull Request title

If this is a backport PR (PR made against branches other than `main`),
please ensure that the PR title is in the following format:

```
[X.Y] <title from the original PR> (GH-NNNN)
```

Where: [X.Y] is the branch name, e.g. [3.6].

GH-NNNN refers to the PR number from `main`.

-->


<!-- readthedocs-preview cpython-previews start -->
----
📚 Documentation preview 📚: https://cpython-previews--115031.org.readthedocs.build/

<!-- readthedocs-preview cpython-previews end -->

<!-- gh-issue-number: gh-97928 -->
* Issue: gh-97928
<!-- /gh-issue-number -->
