From ee3d8dcb005cd4e7ed92403dc07723f98573ae05 Mon Sep 17 00:00:00 2001 From: Kirill Podoprigora Date: Sat, 17 Feb 2024 18:39:48 +0300 Subject: [PATCH] [3.11] gh-107155: Fix help() for lambda function with return annotation (GH-115613) (cherry picked from commit b9a9e3dd62326b726ad2e8e8efd87ca6327b4019) --- Lib/pydoc.py | 6 +++-- Lib/test/test_pydoc/test_pydoc.py | 24 +++++++++++++++++++ ...-08-02-01-17-32.gh-issue-107155.Mj1K9L.rst | 3 +++ 3 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-08-02-01-17-32.gh-issue-107155.Mj1K9L.rst diff --git a/Lib/pydoc.py b/Lib/pydoc.py index c983cbb8aacb60..56a47dc68a6663 100755 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -1128,7 +1128,8 @@ def docroutine(self, object, name=None, mod=None, # XXX lambda's won't usually have func_annotations['return'] # since the syntax doesn't support but it is possible. # So removing parentheses isn't truly safe. - argspec = argspec[1:-1] # remove parentheses + if not object.__annotations__: + argspec = argspec[1:-1] # remove parentheses if not argspec: argspec = '(...)' @@ -1581,7 +1582,8 @@ def docroutine(self, object, name=None, mod=None, cl=None, homecls=None): # XXX lambda's won't usually have func_annotations['return'] # since the syntax doesn't support but it is possible. # So removing parentheses isn't truly safe. - argspec = argspec[1:-1] # remove parentheses + if not object.__annotations__: + argspec = argspec[1:-1] # remove parentheses if not argspec: argspec = '(...)' decl = asyncqualifier + title + argspec + note diff --git a/Lib/test/test_pydoc/test_pydoc.py b/Lib/test/test_pydoc/test_pydoc.py index a0c025c65185c4..ce61dba6a0d7d3 100644 --- a/Lib/test/test_pydoc/test_pydoc.py +++ b/Lib/test/test_pydoc/test_pydoc.py @@ -691,6 +691,30 @@ def test_help_output_redirect(self): finally: pydoc.getpager = getpager_old + def test_lambda_with_return_annotation(self): + func = lambda a, b, c: 1 + func.__annotations__ = {"return": int} + with captured_output('stdout') as help_io: + pydoc.help(func) + helptext = help_io.getvalue() + self.assertIn("lambda (a, b, c) -> int", helptext) + + def test_lambda_without_return_annotation(self): + func = lambda a, b, c: 1 + func.__annotations__ = {"a": int, "b": int, "c": int} + with captured_output('stdout') as help_io: + pydoc.help(func) + helptext = help_io.getvalue() + self.assertIn("lambda (a: int, b: int, c: int)", helptext) + + def test_lambda_with_return_and_params_annotation(self): + func = lambda a, b, c: 1 + func.__annotations__ = {"a": int, "b": int, "c": int, "return": int} + with captured_output('stdout') as help_io: + pydoc.help(func) + helptext = help_io.getvalue() + self.assertIn("lambda (a: int, b: int, c: int) -> int", helptext) + def test_namedtuple_fields(self): Person = namedtuple('Person', ['nickname', 'firstname']) with captured_stdout() as help_io: diff --git a/Misc/NEWS.d/next/Library/2023-08-02-01-17-32.gh-issue-107155.Mj1K9L.rst b/Misc/NEWS.d/next/Library/2023-08-02-01-17-32.gh-issue-107155.Mj1K9L.rst new file mode 100644 index 00000000000000..8362dc0fcfaa74 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-08-02-01-17-32.gh-issue-107155.Mj1K9L.rst @@ -0,0 +1,3 @@ +Fix incorrect output of ``help(x)`` where ``x`` is a :keyword:`lambda` +function, which has an ``__annotations__`` dictionary attribute with a +``"return"`` key.