mirror of https://github.com/python/cpython
gh-120541: Improve the "less" prompt in pydoc (GH-120543)
When help() is called with non-string argument, use __qualname__ or __name__ if available, otherwise use "{typename} object".
This commit is contained in:
parent
9e0b11eb21
commit
31d1d72d7e
|
@ -1755,7 +1755,14 @@ def doc(thing, title='Python Library Documentation: %s', forceload=0,
|
||||||
"""Display text documentation, given an object or a path to an object."""
|
"""Display text documentation, given an object or a path to an object."""
|
||||||
if output is None:
|
if output is None:
|
||||||
try:
|
try:
|
||||||
what = thing if isinstance(thing, str) else type(thing).__name__
|
if isinstance(thing, str):
|
||||||
|
what = thing
|
||||||
|
else:
|
||||||
|
what = getattr(thing, '__qualname__', None)
|
||||||
|
if not isinstance(what, str):
|
||||||
|
what = getattr(thing, '__name__', None)
|
||||||
|
if not isinstance(what, str):
|
||||||
|
what = type(thing).__name__ + ' object'
|
||||||
pager(render_doc(thing, title, forceload), f'Help on {what!s}')
|
pager(render_doc(thing, title, forceload), f'Help on {what!s}')
|
||||||
except ImportError as exc:
|
except ImportError as exc:
|
||||||
if is_cli:
|
if is_cli:
|
||||||
|
|
|
@ -31,7 +31,7 @@ from test.support import os_helper
|
||||||
from test.support.script_helper import (assert_python_ok,
|
from test.support.script_helper import (assert_python_ok,
|
||||||
assert_python_failure, spawn_python)
|
assert_python_failure, spawn_python)
|
||||||
from test.support import threading_helper
|
from test.support import threading_helper
|
||||||
from test.support import (reap_children, captured_output, captured_stdout,
|
from test.support import (reap_children, captured_stdout,
|
||||||
captured_stderr, is_emscripten, is_wasi,
|
captured_stderr, is_emscripten, is_wasi,
|
||||||
requires_docstrings, MISSING_C_DOCSTRINGS)
|
requires_docstrings, MISSING_C_DOCSTRINGS)
|
||||||
from test.support.os_helper import (TESTFN, rmtree, unlink)
|
from test.support.os_helper import (TESTFN, rmtree, unlink)
|
||||||
|
@ -680,9 +680,8 @@ class PydocDocTest(unittest.TestCase):
|
||||||
help_header = textwrap.dedent(help_header)
|
help_header = textwrap.dedent(help_header)
|
||||||
expected_help_pattern = help_header + expected_text_pattern
|
expected_help_pattern = help_header + expected_text_pattern
|
||||||
|
|
||||||
with captured_output('stdout') as output, \
|
with captured_stdout() as output, captured_stderr() as err:
|
||||||
captured_output('stderr') as err, \
|
buf = StringIO()
|
||||||
StringIO() as buf:
|
|
||||||
helper = pydoc.Helper(output=buf)
|
helper = pydoc.Helper(output=buf)
|
||||||
helper.help(module)
|
helper.help(module)
|
||||||
result = buf.getvalue().strip()
|
result = buf.getvalue().strip()
|
||||||
|
@ -706,9 +705,8 @@ class PydocDocTest(unittest.TestCase):
|
||||||
|
|
||||||
def run_pydoc_for_request(request, expected_text_part):
|
def run_pydoc_for_request(request, expected_text_part):
|
||||||
"""Helper function to run pydoc with its output redirected"""
|
"""Helper function to run pydoc with its output redirected"""
|
||||||
with captured_output('stdout') as output, \
|
with captured_stdout() as output, captured_stderr() as err:
|
||||||
captured_output('stderr') as err, \
|
buf = StringIO()
|
||||||
StringIO() as buf:
|
|
||||||
helper = pydoc.Helper(output=buf)
|
helper = pydoc.Helper(output=buf)
|
||||||
helper.help(request)
|
helper.help(request)
|
||||||
result = buf.getvalue().strip()
|
result = buf.getvalue().strip()
|
||||||
|
@ -742,6 +740,45 @@ class PydocDocTest(unittest.TestCase):
|
||||||
run_pydoc_for_request(pydoc.Helper.help, 'Help on function help in module pydoc:')
|
run_pydoc_for_request(pydoc.Helper.help, 'Help on function help in module pydoc:')
|
||||||
# test for pydoc.Helper() instance skipped because it is always meant to be interactive
|
# test for pydoc.Helper() instance skipped because it is always meant to be interactive
|
||||||
|
|
||||||
|
@unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(),
|
||||||
|
'trace function introduces __locals__ unexpectedly')
|
||||||
|
@requires_docstrings
|
||||||
|
def test_help_output_pager(self):
|
||||||
|
def run_pydoc_pager(request, what, expected_first_line):
|
||||||
|
with (captured_stdout() as output,
|
||||||
|
captured_stderr() as err,
|
||||||
|
unittest.mock.patch('pydoc.pager') as pager_mock,
|
||||||
|
self.subTest(repr(request))):
|
||||||
|
helper = pydoc.Helper()
|
||||||
|
helper.help(request)
|
||||||
|
self.assertEqual('', err.getvalue())
|
||||||
|
self.assertEqual('\n', output.getvalue())
|
||||||
|
pager_mock.assert_called_once()
|
||||||
|
result = clean_text(pager_mock.call_args.args[0])
|
||||||
|
self.assertEqual(result.splitlines()[0], expected_first_line)
|
||||||
|
self.assertEqual(pager_mock.call_args.args[1], f'Help on {what}')
|
||||||
|
|
||||||
|
run_pydoc_pager('%', 'EXPRESSIONS', 'Operator precedence')
|
||||||
|
run_pydoc_pager('True', 'bool object', 'Help on bool object:')
|
||||||
|
run_pydoc_pager(True, 'bool object', 'Help on bool object:')
|
||||||
|
run_pydoc_pager('assert', 'assert', 'The "assert" statement')
|
||||||
|
run_pydoc_pager('TYPES', 'TYPES', 'The standard type hierarchy')
|
||||||
|
run_pydoc_pager('pydoc.Helper.help', 'pydoc.Helper.help',
|
||||||
|
'Help on function help in pydoc.Helper:')
|
||||||
|
run_pydoc_pager(pydoc.Helper.help, 'Helper.help',
|
||||||
|
'Help on function help in module pydoc:')
|
||||||
|
run_pydoc_pager('str', 'str', 'Help on class str in module builtins:')
|
||||||
|
run_pydoc_pager(str, 'str', 'Help on class str in module builtins:')
|
||||||
|
run_pydoc_pager('str.upper', 'str.upper', 'Help on method_descriptor in str:')
|
||||||
|
run_pydoc_pager(str.upper, 'str.upper', 'Help on method_descriptor:')
|
||||||
|
run_pydoc_pager(str.__add__, 'str.__add__', 'Help on wrapper_descriptor:')
|
||||||
|
run_pydoc_pager(int.numerator, 'int.numerator',
|
||||||
|
'Help on getset descriptor builtins.int.numerator:')
|
||||||
|
run_pydoc_pager(list[int], 'list',
|
||||||
|
'Help on GenericAlias in module builtins:')
|
||||||
|
run_pydoc_pager('sys', 'sys', 'Help on built-in module sys:')
|
||||||
|
run_pydoc_pager(sys, 'sys', 'Help on built-in module sys:')
|
||||||
|
|
||||||
def test_showtopic(self):
|
def test_showtopic(self):
|
||||||
with captured_stdout() as showtopic_io:
|
with captured_stdout() as showtopic_io:
|
||||||
helper = pydoc.Helper()
|
helper = pydoc.Helper()
|
||||||
|
@ -775,9 +812,8 @@ class PydocDocTest(unittest.TestCase):
|
||||||
# Helper.showtopic should be redirected
|
# Helper.showtopic should be redirected
|
||||||
self.maxDiff = None
|
self.maxDiff = None
|
||||||
|
|
||||||
with captured_output('stdout') as output, \
|
with captured_stdout() as output, captured_stderr() as err:
|
||||||
captured_output('stderr') as err, \
|
buf = StringIO()
|
||||||
StringIO() as buf:
|
|
||||||
helper = pydoc.Helper(output=buf)
|
helper = pydoc.Helper(output=buf)
|
||||||
helper.showtopic('with')
|
helper.showtopic('with')
|
||||||
result = buf.getvalue().strip()
|
result = buf.getvalue().strip()
|
||||||
|
@ -790,7 +826,7 @@ class PydocDocTest(unittest.TestCase):
|
||||||
def test_lambda_with_return_annotation(self):
|
def test_lambda_with_return_annotation(self):
|
||||||
func = lambda a, b, c: 1
|
func = lambda a, b, c: 1
|
||||||
func.__annotations__ = {"return": int}
|
func.__annotations__ = {"return": int}
|
||||||
with captured_output('stdout') as help_io:
|
with captured_stdout() as help_io:
|
||||||
pydoc.help(func)
|
pydoc.help(func)
|
||||||
helptext = help_io.getvalue()
|
helptext = help_io.getvalue()
|
||||||
self.assertIn("lambda (a, b, c) -> int", helptext)
|
self.assertIn("lambda (a, b, c) -> int", helptext)
|
||||||
|
@ -798,7 +834,7 @@ class PydocDocTest(unittest.TestCase):
|
||||||
def test_lambda_without_return_annotation(self):
|
def test_lambda_without_return_annotation(self):
|
||||||
func = lambda a, b, c: 1
|
func = lambda a, b, c: 1
|
||||||
func.__annotations__ = {"a": int, "b": int, "c": int}
|
func.__annotations__ = {"a": int, "b": int, "c": int}
|
||||||
with captured_output('stdout') as help_io:
|
with captured_stdout() as help_io:
|
||||||
pydoc.help(func)
|
pydoc.help(func)
|
||||||
helptext = help_io.getvalue()
|
helptext = help_io.getvalue()
|
||||||
self.assertIn("lambda (a: int, b: int, c: int)", helptext)
|
self.assertIn("lambda (a: int, b: int, c: int)", helptext)
|
||||||
|
@ -806,7 +842,7 @@ class PydocDocTest(unittest.TestCase):
|
||||||
def test_lambda_with_return_and_params_annotation(self):
|
def test_lambda_with_return_and_params_annotation(self):
|
||||||
func = lambda a, b, c: 1
|
func = lambda a, b, c: 1
|
||||||
func.__annotations__ = {"a": int, "b": int, "c": int, "return": int}
|
func.__annotations__ = {"a": int, "b": int, "c": int, "return": int}
|
||||||
with captured_output('stdout') as help_io:
|
with captured_stdout() as help_io:
|
||||||
pydoc.help(func)
|
pydoc.help(func)
|
||||||
helptext = help_io.getvalue()
|
helptext = help_io.getvalue()
|
||||||
self.assertIn("lambda (a: int, b: int, c: int) -> int", helptext)
|
self.assertIn("lambda (a: int, b: int, c: int) -> int", helptext)
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Improve the prompt in the "less" pager when :func:`help` is called with
|
||||||
|
non-string argument.
|
Loading…
Reference in New Issue