1515import types
1616import typing
1717import unittest
18+ import unittest .mock
1819import urllib .parse
1920import xml .etree
2021import xml .etree .ElementTree
@@ -656,16 +657,13 @@ def test_fail_help_output_redirect(self):
656657
657658@unittest .skipIf (hasattr (sys ,'gettrace' )and sys .gettrace (),
658659'trace function introduces __locals__ unexpectedly' )
660+ @unittest .mock .patch ('pydoc.pager' )
659661@requires_docstrings
660- def test_help_output_redirect (self ):
662+ def test_help_output_redirect (self , pager_mock ):
661663# issue 940286, if output is set in Helper, then all output from
662664# Helper.help should be redirected
663- getpager_old = pydoc .getpager
664- getpager_new = lambda : (lambda x :x )
665665self .maxDiff = None
666666
667- buf = StringIO ()
668- helper = pydoc .Helper (output = buf )
669667unused ,doc_loc = get_pydoc_text (pydoc_mod )
670668module = "test.test_pydoc.pydoc_mod"
671669help_header = """
@@ -675,21 +673,112 @@ def test_help_output_redirect(self):
675673help_header = textwrap .dedent (help_header )
676674expected_help_pattern = help_header + expected_text_pattern
677675
678- pydoc .getpager = getpager_new
679- try :
676+ with captured_output ('stdout' )as output , \
677+ captured_output ('stderr' )as err , \
678+ StringIO ()as buf :
679+ helper = pydoc .Helper (output = buf )
680+ helper .help (module )
681+ result = buf .getvalue ().strip ()
682+ expected_text = expected_help_pattern % (
683+ (doc_loc ,)+
684+ expected_text_data_docstrings +
685+ (inspect .getabsfile (pydoc_mod ),))
686+ self .assertEqual ('' ,output .getvalue ())
687+ self .assertEqual ('' ,err .getvalue ())
688+ self .assertEqual (expected_text ,result )
689+
690+ pager_mock .assert_not_called ()
691+
692+ @unittest .skipIf (hasattr (sys ,'gettrace' )and sys .gettrace (),
693+ 'trace function introduces __locals__ unexpectedly' )
694+ @requires_docstrings
695+ @unittest .mock .patch ('pydoc.pager' )
696+ def test_help_output_redirect_various_requests (self ,pager_mock ):
697+ # issue 940286, if output is set in Helper, then all output from
698+ # Helper.help should be redirected
699+
700+ def run_pydoc_for_request (request ,expected_text_part ):
701+ """Helper function to run pydoc with its output redirected"""
680702with captured_output ('stdout' )as output , \
681- captured_output ('stderr' )as err :
682- helper .help (module )
703+ captured_output ('stderr' )as err , \
704+ StringIO ()as buf :
705+ helper = pydoc .Helper (output = buf )
706+ helper .help (request )
683707result = buf .getvalue ().strip ()
684- expected_text = expected_help_pattern % (
685- (doc_loc ,)+
686- expected_text_data_docstrings +
687- (inspect .getabsfile (pydoc_mod ),))
688- self .assertEqual ('' ,output .getvalue ())
689- self .assertEqual ('' ,err .getvalue ())
690- self .assertEqual (expected_text ,result )
691- finally :
692- pydoc .getpager = getpager_old
708+ self .assertEqual ('' ,output .getvalue (),msg = f'failed on request "{ request } "' )
709+ self .assertEqual ('' ,err .getvalue (),msg = f'failed on request "{ request } "' )
710+ self .assertIn (expected_text_part ,result ,msg = f'failed on request "{ request } "' )
711+ pager_mock .assert_not_called ()
712+
713+ self .maxDiff = None
714+
715+ # test for "keywords"
716+ run_pydoc_for_request ('keywords' ,'Here is a list of the Python keywords.' )
717+ # test for "symbols"
718+ run_pydoc_for_request ('symbols' ,'Here is a list of the punctuation symbols' )
719+ # test for "topics"
720+ run_pydoc_for_request ('topics' ,'Here is a list of available topics.' )
721+ # test for "modules" skipped, see test_modules()
722+ # test for symbol "%"
723+ run_pydoc_for_request ('%' ,'The power operator' )
724+ # test for special True, False, None keywords
725+ run_pydoc_for_request ('True' ,'class bool(int)' )
726+ run_pydoc_for_request ('False' ,'class bool(int)' )
727+ run_pydoc_for_request ('None' ,'class NoneType(object)' )
728+ # test for keyword "assert"
729+ run_pydoc_for_request ('assert' ,'The "assert" statement' )
730+ # test for topic "TYPES"
731+ run_pydoc_for_request ('TYPES' ,'The standard type hierarchy' )
732+ # test for "pydoc.Helper.help"
733+ run_pydoc_for_request ('pydoc.Helper.help' ,'Help on function help in pydoc.Helper:' )
734+ # test for pydoc.Helper.help
735+ run_pydoc_for_request (pydoc .Helper .help ,'Help on function help in module pydoc:' )
736+ # test for pydoc.Helper() instance skipped because it is always meant to be interactive
737+
738+ def test_showtopic (self ):
739+ with captured_stdout ()as showtopic_io :
740+ helper = pydoc .Helper ()
741+ helper .showtopic ('with' )
742+ helptext = showtopic_io .getvalue ()
743+ self .assertIn ('The "with" statement' ,helptext )
744+
745+ def test_fail_showtopic (self ):
746+ with captured_stdout ()as showtopic_io :
747+ helper = pydoc .Helper ()
748+ helper .showtopic ('abd' )
749+ expected = "no documentation found for 'abd'"
750+ self .assertEqual (expected ,showtopic_io .getvalue ().strip ())
751+
752+ @unittest .mock .patch ('pydoc.pager' )
753+ def test_fail_showtopic_output_redirect (self ,pager_mock ):
754+ with StringIO ()as buf :
755+ helper = pydoc .Helper (output = buf )
756+ helper .showtopic ("abd" )
757+ expected = "no documentation found for 'abd'"
758+ self .assertEqual (expected ,buf .getvalue ().strip ())
759+
760+ pager_mock .assert_not_called ()
761+
762+ @unittest .skipIf (hasattr (sys ,'gettrace' )and sys .gettrace (),
763+ 'trace function introduces __locals__ unexpectedly' )
764+ @requires_docstrings
765+ @unittest .mock .patch ('pydoc.pager' )
766+ def test_showtopic_output_redirect (self ,pager_mock ):
767+ # issue 940286, if output is set in Helper, then all output from
768+ # Helper.showtopic should be redirected
769+ self .maxDiff = None
770+
771+ with captured_output ('stdout' )as output , \
772+ captured_output ('stderr' )as err , \
773+ StringIO ()as buf :
774+ helper = pydoc .Helper (output = buf )
775+ helper .showtopic ('with' )
776+ result = buf .getvalue ().strip ()
777+ self .assertEqual ('' ,output .getvalue ())
778+ self .assertEqual ('' ,err .getvalue ())
779+ self .assertIn ('The "with" statement' ,result )
780+
781+ pager_mock .assert_not_called ()
693782
694783def test_lambda_with_return_annotation (self ):
695784func = lambda a ,b ,c :1