From 1d4d0295a2133cd26e48419ced3a24c31bc166a3 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 1 Jul 2026 10:21:49 +0300 Subject: [PATCH 1/2] gh-83637: Make IDLE calltip tests pass without docstrings Skip the tests that check docstrings with test.support.requires_docstrings, as test_inspect and test_pydoc do. They failed under -OO. --- Lib/idlelib/idle_test/test_calltip.py | 12 +++++++----- .../2026-07-01-20-00-00.gh-issue-83637.cTipOO.rst | 2 ++ 2 files changed, 9 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/IDLE/2026-07-01-20-00-00.gh-issue-83637.cTipOO.rst diff --git a/Lib/idlelib/idle_test/test_calltip.py b/Lib/idlelib/idle_test/test_calltip.py index 28c196a42672fcd..2148c7b446d8107 100644 --- a/Lib/idlelib/idle_test/test_calltip.py +++ b/Lib/idlelib/idle_test/test_calltip.py @@ -7,7 +7,7 @@ import types import re from idlelib.idle_test.mock_tk import Text -from test.support import MISSING_C_DOCSTRINGS +from test.support import MISSING_C_DOCSTRINGS, requires_docstrings # Test Class TC is used in multiple get_argspec test methods @@ -51,8 +51,7 @@ class Get_argspecTest(unittest.TestCase): # but a red buildbot is better than a user crash (as has happened). # For a simple mismatch, change the expected output to the actual. - @unittest.skipIf(MISSING_C_DOCSTRINGS, - "Signature information for builtins requires docstrings") + @requires_docstrings def test_builtins(self): def tiptest(obj, out): @@ -112,6 +111,7 @@ def test_signature_wrap(self): If you want to completely replace the main wrapping algorithm, you\'ll probably have to override _wrap_chunks().''') + @requires_docstrings def test_properly_formatted(self): def foo(s='a'*100): @@ -186,17 +186,19 @@ def t5(a, b=None, *args, **kw): 'doc' with self.subTest(func=func): self.assertEqual(get_spec(func), func.tip + doc) + @requires_docstrings def test_methods(self): - doc = '\ndoc' if TC.__doc__ is not None else '' + doc = '\ndoc' for meth in (TC.t1, TC.t2, TC.t3, TC.t4, TC.t5, TC.t6, TC.__call__): with self.subTest(meth=meth): self.assertEqual(get_spec(meth), meth.tip + doc) self.assertEqual(get_spec(TC.cm), "(a)" + doc) self.assertEqual(get_spec(TC.sm), "(b)" + doc) + @requires_docstrings def test_bound_methods(self): # test that first parameter is correctly removed from argspec - doc = '\ndoc' if TC.__doc__ is not None else '' + doc = '\ndoc' for meth, mtip in ((tc.t1, "()"), (tc.t4, "(*args)"), (tc.t6, "(self)"), (tc.__call__, '(ci)'), (tc, '(ci)'), (TC.cm, "(a)"),): diff --git a/Misc/NEWS.d/next/IDLE/2026-07-01-20-00-00.gh-issue-83637.cTipOO.rst b/Misc/NEWS.d/next/IDLE/2026-07-01-20-00-00.gh-issue-83637.cTipOO.rst new file mode 100644 index 000000000000000..2abf68e28884ae8 --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2026-07-01-20-00-00.gh-issue-83637.cTipOO.rst @@ -0,0 +1,2 @@ +Skip IDLE calltip tests that require docstrings when running with ``-OO`` or +without docstrings. From 65cb8ccbac44e6763202ef4574face6968554843 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 2 Jul 2026 07:10:00 +0300 Subject: [PATCH 2/2] gh-83637: Make more IDLE tests pass without docstrings and with -O --- Lib/idlelib/idle_test/test_calltip.py | 25 +++++++++++------ Lib/idlelib/idle_test/test_pyparse.py | 28 +++++++++++-------- Lib/idlelib/idle_test/test_run.py | 3 +- ...6-07-01-20-00-00.gh-issue-83637.cTipOO.rst | 4 +-- 4 files changed, 37 insertions(+), 23 deletions(-) diff --git a/Lib/idlelib/idle_test/test_calltip.py b/Lib/idlelib/idle_test/test_calltip.py index 2148c7b446d8107..ca84bd9aa2766fd 100644 --- a/Lib/idlelib/idle_test/test_calltip.py +++ b/Lib/idlelib/idle_test/test_calltip.py @@ -111,7 +111,6 @@ def test_signature_wrap(self): If you want to completely replace the main wrapping algorithm, you\'ll probably have to override _wrap_chunks().''') - @requires_docstrings def test_properly_formatted(self): def foo(s='a'*100): @@ -131,7 +130,9 @@ def baz(s='a'*100, z='b'*100): "aaaaaaaaaa')" sbar = "(s='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"\ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" + indent + "aaaaaaaaa"\ - "aaaaaaaaaa')\nHello Guido" + "aaaaaaaaaa')" + if bar.__doc__ is not None: + sbar += "\nHello Guido" sbaz = "(s='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"\ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" + indent + "aaaaaaaaa"\ "aaaaaaaaaa', z='bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"\ @@ -186,24 +187,32 @@ def t5(a, b=None, *args, **kw): 'doc' with self.subTest(func=func): self.assertEqual(get_spec(func), func.tip + doc) - @requires_docstrings def test_methods(self): - doc = '\ndoc' - for meth in (TC.t1, TC.t2, TC.t3, TC.t4, TC.t5, TC.t6, TC.__call__): + doc = '\ndoc' if TC.__doc__ is not None else '' + for meth in (TC.t1, TC.t2, TC.t3, TC.t4, TC.t5, TC.t6): with self.subTest(meth=meth): self.assertEqual(get_spec(meth), meth.tip + doc) self.assertEqual(get_spec(TC.cm), "(a)" + doc) self.assertEqual(get_spec(TC.sm), "(b)" + doc) + # __call__ inherits object.__call__'s docstring when its own is + # missing (build without docstrings or run with -OO). + call_doc = doc or ('\n' + object.__call__.__doc__ + if object.__call__.__doc__ else '') + self.assertEqual(get_spec(TC.__call__), TC.__call__.tip + call_doc) - @requires_docstrings def test_bound_methods(self): # test that first parameter is correctly removed from argspec - doc = '\ndoc' + doc = '\ndoc' if TC.__doc__ is not None else '' for meth, mtip in ((tc.t1, "()"), (tc.t4, "(*args)"), - (tc.t6, "(self)"), (tc.__call__, '(ci)'), + (tc.t6, "(self)"), (tc, '(ci)'), (TC.cm, "(a)"),): with self.subTest(meth=meth, mtip=mtip): self.assertEqual(get_spec(meth), mtip + doc) + # __call__ inherits object.__call__'s docstring when its own is + # missing (build without docstrings or run with -OO). + call_doc = doc or ('\n' + object.__call__.__doc__ + if object.__call__.__doc__ else '') + self.assertEqual(get_spec(tc.__call__), '(ci)' + call_doc) def test_starred_parameter(self): # test that starred first parameter is *not* removed from argspec diff --git a/Lib/idlelib/idle_test/test_pyparse.py b/Lib/idlelib/idle_test/test_pyparse.py index 384db566ac76cdb..a0fc3a544eb5247 100644 --- a/Lib/idlelib/idle_test/test_pyparse.py +++ b/Lib/idlelib/idle_test/test_pyparse.py @@ -41,8 +41,9 @@ def test_set_code(self): setcode = p.set_code # Not empty and doesn't end with newline. - with self.assertRaises(AssertionError): - setcode('a') + if __debug__: # Assertions are removed with -O. + with self.assertRaises(AssertionError): + setcode('a') tests = ('', 'a\n') @@ -131,8 +132,9 @@ def test_set_lo(self): p.set_code(code) # Previous character is not a newline. - with self.assertRaises(AssertionError): - p.set_lo(5) + if __debug__: # Assertions are removed with -O. + with self.assertRaises(AssertionError): + p.set_lo(5) # A value of 0 doesn't change self.code. p.set_lo(0) @@ -326,9 +328,10 @@ def test_compute_bracket_indent(self): ) # Must be C_BRACKET continuation type. - setcode('def function1(self, a, b):\n') - with self.assertRaises(AssertionError): - indent() + if __debug__: # Assertions are removed with -O. + setcode('def function1(self, a, b):\n') + with self.assertRaises(AssertionError): + indent() for test in tests: setcode(test.string) @@ -345,11 +348,12 @@ def test_compute_backslash_indent(self): (' """ (\\\n'), # Docstring. ('a = #\\\n'), # Inline comment. ) - for string in errors: - with self.subTest(string=string): - setcode(string) - with self.assertRaises(AssertionError): - indent() + if __debug__: # Assertions are removed with -O. + for string in errors: + with self.subTest(string=string): + setcode(string) + with self.assertRaises(AssertionError): + indent() TestInfo = namedtuple('TestInfo', ('string', 'spaces')) tests = (TestInfo('a = (1 + 2) - 5 *\\\n', 4), diff --git a/Lib/idlelib/idle_test/test_run.py b/Lib/idlelib/idle_test/test_run.py index 57bf5559c0fa88a..a1e9920b64743b4 100644 --- a/Lib/idlelib/idle_test/test_run.py +++ b/Lib/idlelib/idle_test/test_run.py @@ -454,7 +454,8 @@ def test_default_recursion_limit_preserved(self): def test_fixdoc(self): # Put here until better place for miscellaneous test. - def func(): "docstring" + def func(): pass + func.__doc__ = "docstring" run.fixdoc(func, "more") self.assertEqual(func.__doc__, "docstring\n\nmore") func.__doc__ = None diff --git a/Misc/NEWS.d/next/IDLE/2026-07-01-20-00-00.gh-issue-83637.cTipOO.rst b/Misc/NEWS.d/next/IDLE/2026-07-01-20-00-00.gh-issue-83637.cTipOO.rst index 2abf68e28884ae8..519c7e192844973 100644 --- a/Misc/NEWS.d/next/IDLE/2026-07-01-20-00-00.gh-issue-83637.cTipOO.rst +++ b/Misc/NEWS.d/next/IDLE/2026-07-01-20-00-00.gh-issue-83637.cTipOO.rst @@ -1,2 +1,2 @@ -Skip IDLE calltip tests that require docstrings when running with ``-OO`` or -without docstrings. +Make IDLE tests pass when running with ``-O`` or ``-OO`` or without +docstrings.