3131from test .support .script_helper import (assert_python_ok ,
3232assert_python_failure ,spawn_python )
3333from test .support import threading_helper
34- from test .support import (reap_children ,captured_output , captured_stdout ,
34+ from test .support import (reap_children ,captured_stdout ,
3535captured_stderr ,is_emscripten ,is_wasi ,
3636requires_docstrings ,MISSING_C_DOCSTRINGS )
3737from test .support .os_helper import (TESTFN ,rmtree ,unlink )
@@ -680,9 +680,8 @@ def test_help_output_redirect(self, pager_mock):
680680help_header = textwrap .dedent (help_header )
681681expected_help_pattern = help_header + expected_text_pattern
682682
683- with captured_output ('stdout' )as output , \
684- captured_output ('stderr' )as err , \
685- StringIO ()as buf :
683+ with captured_stdout ()as output ,captured_stderr ()as err :
684+ buf = StringIO ()
686685helper = pydoc .Helper (output = buf )
687686helper .help (module )
688687result = buf .getvalue ().strip ()
@@ -706,9 +705,8 @@ def test_help_output_redirect_various_requests(self, pager_mock):
706705
707706def run_pydoc_for_request (request ,expected_text_part ):
708707"""Helper function to run pydoc with its output redirected"""
709- with captured_output ('stdout' )as output , \
710- captured_output ('stderr' )as err , \
711- StringIO ()as buf :
708+ with captured_stdout ()as output ,captured_stderr ()as err :
709+ buf = StringIO ()
712710helper = pydoc .Helper (output = buf )
713711helper .help (request )
714712result = buf .getvalue ().strip ()
@@ -742,6 +740,45 @@ def run_pydoc_for_request(request, expected_text_part):
742740run_pydoc_for_request (pydoc .Helper .help ,'Help on function help in module pydoc:' )
743741# test for pydoc.Helper() instance skipped because it is always meant to be interactive
744742
743+ @unittest .skipIf (hasattr (sys ,'gettrace' )and sys .gettrace (),
744+ 'trace function introduces __locals__ unexpectedly' )
745+ @requires_docstrings
746+ def test_help_output_pager (self ):
747+ def run_pydoc_pager (request ,what ,expected_first_line ):
748+ with (captured_stdout ()as output ,
749+ captured_stderr ()as err ,
750+ unittest .mock .patch ('pydoc.pager' )as pager_mock ,
751+ self .subTest (repr (request ))):
752+ helper = pydoc .Helper ()
753+ helper .help (request )
754+ self .assertEqual ('' ,err .getvalue ())
755+ self .assertEqual ('\n ' ,output .getvalue ())
756+ pager_mock .assert_called_once ()
757+ result = clean_text (pager_mock .call_args .args [0 ])
758+ self .assertEqual (result .splitlines ()[0 ],expected_first_line )
759+ self .assertEqual (pager_mock .call_args .args [1 ],f'Help on{ what } ' )
760+
761+ run_pydoc_pager ('%' ,'EXPRESSIONS' ,'Operator precedence' )
762+ run_pydoc_pager ('True' ,'bool object' ,'Help on bool object:' )
763+ run_pydoc_pager (True ,'bool object' ,'Help on bool object:' )
764+ run_pydoc_pager ('assert' ,'assert' ,'The "assert" statement' )
765+ run_pydoc_pager ('TYPES' ,'TYPES' ,'The standard type hierarchy' )
766+ run_pydoc_pager ('pydoc.Helper.help' ,'pydoc.Helper.help' ,
767+ 'Help on function help in pydoc.Helper:' )
768+ run_pydoc_pager (pydoc .Helper .help ,'Helper.help' ,
769+ 'Help on function help in module pydoc:' )
770+ run_pydoc_pager ('str' ,'str' ,'Help on class str in module builtins:' )
771+ run_pydoc_pager (str ,'str' ,'Help on class str in module builtins:' )
772+ run_pydoc_pager ('str.upper' ,'str.upper' ,'Help on method_descriptor in str:' )
773+ run_pydoc_pager (str .upper ,'str.upper' ,'Help on method_descriptor:' )
774+ run_pydoc_pager (str .__add__ ,'str.__add__' ,'Help on wrapper_descriptor:' )
775+ run_pydoc_pager (int .numerator ,'int.numerator' ,
776+ 'Help on getset descriptor builtins.int.numerator:' )
777+ run_pydoc_pager (list [int ],'list' ,
778+ 'Help on GenericAlias in module builtins:' )
779+ run_pydoc_pager ('sys' ,'sys' ,'Help on built-in module sys:' )
780+ run_pydoc_pager (sys ,'sys' ,'Help on built-in module sys:' )
781+
745782def test_showtopic (self ):
746783with captured_stdout ()as showtopic_io :
747784helper = pydoc .Helper ()
@@ -775,9 +812,8 @@ def test_showtopic_output_redirect(self, pager_mock):
775812# Helper.showtopic should be redirected
776813self .maxDiff = None
777814
778- with captured_output ('stdout' )as output , \
779- captured_output ('stderr' )as err , \
780- StringIO ()as buf :
815+ with captured_stdout ()as output ,captured_stderr ()as err :
816+ buf = StringIO ()
781817helper = pydoc .Helper (output = buf )
782818helper .showtopic ('with' )
783819result = buf .getvalue ().strip ()
@@ -790,23 +826,23 @@ def test_showtopic_output_redirect(self, pager_mock):
790826def test_lambda_with_return_annotation (self ):
791827func = lambda a ,b ,c :1
792828func .__annotations__ = {"return" :int }
793- with captured_output ( 'stdout' )as help_io :
829+ with captured_stdout ( )as help_io :
794830pydoc .help (func )
795831helptext = help_io .getvalue ()
796832self .assertIn ("lambda (a, b, c) -> int" ,helptext )
797833
798834def test_lambda_without_return_annotation (self ):
799835func = lambda a ,b ,c :1
800836func .__annotations__ = {"a" :int ,"b" :int ,"c" :int }
801- with captured_output ( 'stdout' )as help_io :
837+ with captured_stdout ( )as help_io :
802838pydoc .help (func )
803839helptext = help_io .getvalue ()
804840self .assertIn ("lambda (a: int, b: int, c: int)" ,helptext )
805841
806842def test_lambda_with_return_and_params_annotation (self ):
807843func = lambda a ,b ,c :1
808844func .__annotations__ = {"a" :int ,"b" :int ,"c" :int ,"return" :int }
809- with captured_output ( 'stdout' )as help_io :
845+ with captured_stdout ( )as help_io :
810846pydoc .help (func )
811847helptext = help_io .getvalue ()
812848self .assertIn ("lambda (a: int, b: int, c: int) -> int" ,helptext )