From 9646762c6581b77b221bec8784d1600b64ed7891 Mon Sep 17 00:00:00 2001 From: adam j hartz Date: Wed, 20 Aug 2025 20:25:01 -0400 Subject: [PATCH 1/7] don't suggest things involving help() at the interactive help prompt --- Lib/pydoc.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Lib/pydoc.py b/Lib/pydoc.py index d508fb70ea429e..29df8788a995b5 100644 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -1771,7 +1771,7 @@ def render_doc(thing, title='Python Library Documentation: %s', forceload=0, return title % desc + '\n\n' + renderer.document(object, name) def doc(thing, title='Python Library Documentation: %s', forceload=0, - output=None, is_cli=False): + output=None, is_cli=False, is_interactive=False): """Display text documentation, given an object or a path to an object.""" if output is None: try: @@ -1787,7 +1787,11 @@ def doc(thing, title='Python Library Documentation: %s', forceload=0, except ImportError as exc: if is_cli: raise - print(exc) + if is_interactive: + # don't show the usual hints if we're running interactively + print(exc.args[0].splitlines(False)[0]) + else: + print(exc) else: try: s = render_doc(thing, title, forceload, plaintext) @@ -2070,10 +2074,7 @@ def interact(self): and request[0] not in request[1:-1]): request = request[1:-1] if request.lower() in ('q', 'quit', 'exit'): break - if request == 'help': - self.intro() - else: - self.help(request) + self.help(request, is_interactive=True) def getline(self, prompt): """Read one line, using input() when appropriate.""" @@ -2084,7 +2085,7 @@ def getline(self, prompt): self.output.flush() return self.input.readline() - def help(self, request, is_cli=False): + def help(self, request, is_cli=False, is_interactive=False): if isinstance(request, str): request = request.strip() if request == 'keywords': self.listkeywords() @@ -2099,7 +2100,8 @@ def help(self, request, is_cli=False): doc(eval(request), 'Help on %s:', output=self._output, is_cli=is_cli) elif request in self.keywords: self.showtopic(request) elif request in self.topics: self.showtopic(request) - elif request: doc(request, 'Help on %s:', output=self._output, is_cli=is_cli) + elif request: + doc(request, 'Help on %s:', output=self._output, is_cli=is_cli, is_interactive=is_interactive) else: doc(str, 'Help on %s:', output=self._output, is_cli=is_cli) elif isinstance(request, Helper): self() else: doc(request, 'Help on %s:', output=self._output, is_cli=is_cli) From a70cbdd8179380ee7bb8919cbc52e0e9248f7a50 Mon Sep 17 00:00:00 2001 From: adam j hartz Date: Sat, 23 Aug 2025 13:17:16 -0400 Subject: [PATCH 2/7] better output for help(help) --- Lib/pydoc.py | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/Lib/pydoc.py b/Lib/pydoc.py index 29df8788a995b5..430578511c7981 100644 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -2088,7 +2088,9 @@ def getline(self, prompt): def help(self, request, is_cli=False, is_interactive=False): if isinstance(request, str): request = request.strip() - if request == 'keywords': self.listkeywords() + if request == 'help': + self.helphelp(is_interactive=is_interactive) + elif request == 'keywords': self.listkeywords() elif request == 'symbols': self.listsymbols() elif request == 'topics': self.listtopics() elif request == 'modules': self.listmodules() @@ -2103,10 +2105,35 @@ def help(self, request, is_cli=False, is_interactive=False): elif request: doc(request, 'Help on %s:', output=self._output, is_cli=is_cli, is_interactive=is_interactive) else: doc(str, 'Help on %s:', output=self._output, is_cli=is_cli) - elif isinstance(request, Helper): self() + elif isinstance(request, (Helper, type(builtins.help))): + self.helphelp(is_interactive=is_interactive) else: doc(request, 'Help on %s:', output=self._output, is_cli=is_cli) self.output.write('\n') + def helphelp(self, is_interactive=False): + if is_interactive: + self.output.write(_introdoc()) + else: + pager(textwrap.dedent("""\ + help - Interactive Help + ======================= + The built-in help function implements an interactive help utility. You + can make use of it in a few different ways: + + * Calling help() with no arguments starts an interactive help session. + + * Calling help(x) will have one of two behaviors depending on the type + of the argument: + + * If x is a string, help(x) provides information about the given + topic. For example, help("class") will provide information about + the "class" keyword, and help("math.sqrt") will provide + information about the "math.sqrt" function. + + * If x is not a string, help(x) prints information about x's type. + For example, help(42) will provide information about the int type. + """)) + def intro(self): self.output.write(_introdoc()) From f069a995b11a6b9e82161357d6fe297f96f202aa Mon Sep 17 00:00:00 2001 From: adam j hartz Date: Sat, 23 Aug 2025 13:26:16 -0400 Subject: [PATCH 3/7] use helper function for intro text instead of rewriting it --- Lib/pydoc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/pydoc.py b/Lib/pydoc.py index 430578511c7981..6fdbaa72b3744b 100644 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -2112,7 +2112,7 @@ def help(self, request, is_cli=False, is_interactive=False): def helphelp(self, is_interactive=False): if is_interactive: - self.output.write(_introdoc()) + self.intro() else: pager(textwrap.dedent("""\ help - Interactive Help From c6912de161817bb0890daac7d97cdc408dc6d46f Mon Sep 17 00:00:00 2001 From: adam j hartz Date: Sat, 23 Aug 2025 13:29:09 -0400 Subject: [PATCH 4/7] change test case to adjust for change in interactive help --- Lib/test/test_pydoc/test_pydoc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_pydoc/test_pydoc.py b/Lib/test/test_pydoc/test_pydoc.py index 3b50ead00bdd31..b62416ec66027e 100644 --- a/Lib/test/test_pydoc/test_pydoc.py +++ b/Lib/test/test_pydoc/test_pydoc.py @@ -664,10 +664,10 @@ def test_builtin_on_metaclasses(self): self.assertNotIn('Built-in subclasses', text) def test_fail_help_cli(self): - elines = (missing_pattern % 'abd').splitlines() + elines = (missing_pattern % 'abd').splitlines(False)[:1] with spawn_python("-c" "help()") as proc: out, _ = proc.communicate(b"abd") - olines = out.decode().splitlines()[-9:-6] + olines = out.decode().splitlines(False)[-7:-6] olines[0] = olines[0].removeprefix('help> ') self.assertEqual(elines, olines) From 1d822cab9956279e3e4c02403299162698e80a3b Mon Sep 17 00:00:00 2001 From: adam j hartz Date: Sat, 23 Aug 2025 13:46:18 -0400 Subject: [PATCH 5/7] more accurate help(help) output --- Lib/pydoc.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Lib/pydoc.py b/Lib/pydoc.py index 6fdbaa72b3744b..019c65a2ae4bd9 100644 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -2117,21 +2117,25 @@ def helphelp(self, is_interactive=False): pager(textwrap.dedent("""\ help - Interactive Help ======================= + The built-in help function implements an interactive help utility. You can make use of it in a few different ways: * Calling help() with no arguments starts an interactive help session. - * Calling help(x) will have one of two behaviors depending on the type - of the argument: + * The behavior of help(x) depends on the type of the argument: * If x is a string, help(x) provides information about the given topic. For example, help("class") will provide information about the "class" keyword, and help("math.sqrt") will provide information about the "math.sqrt" function. - * If x is not a string, help(x) prints information about x's type. - For example, help(42) will provide information about the int type. + * If x is a class or a built-in type, help(x) provides information + about that type. For example, help(str) will provide information + about the str type. + + * Otherwise, help(x) provides information about x's type. For + example, help(42) will provide information about the int type. """)) def intro(self): From 45b5b4fa441cba271e63fa175fdf80d2557e92fe Mon Sep 17 00:00:00 2001 From: adam j hartz Date: Sat, 23 Aug 2025 14:08:10 -0400 Subject: [PATCH 6/7] add news blurb --- .../2025-08-23-14-07-56.gh-issue-138094.U92SHS.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-08-23-14-07-56.gh-issue-138094.U92SHS.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-23-14-07-56.gh-issue-138094.U92SHS.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-08-23-14-07-56.gh-issue-138094.U92SHS.rst new file mode 100644 index 00000000000000..6c84123d82131e --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-08-23-14-07-56.gh-issue-138094.U92SHS.rst @@ -0,0 +1,2 @@ +Removed potentially-misleading suggestions from the interactive ``help`` +prompt. Patch by Adam Hartz. From 4617a582b773cb7adb65a90e4294f5f023bb023e Mon Sep 17 00:00:00 2001 From: adam j hartz Date: Sun, 24 Aug 2025 00:24:53 -0400 Subject: [PATCH 7/7] Use Sphinx reference in news blurb Co-authored-by: Peter Bierma --- .../2025-08-23-14-07-56.gh-issue-138094.U92SHS.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-23-14-07-56.gh-issue-138094.U92SHS.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-08-23-14-07-56.gh-issue-138094.U92SHS.rst index 6c84123d82131e..d831dc41885872 100644 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-23-14-07-56.gh-issue-138094.U92SHS.rst +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-08-23-14-07-56.gh-issue-138094.U92SHS.rst @@ -1,2 +1,2 @@ -Removed potentially-misleading suggestions from the interactive ``help`` +Removed potentially-misleading suggestions from the interactive :func:`help` prompt. Patch by Adam Hartz.