Kaydet (Commit) d80d5f4e authored tarafından Georg Brandl's avatar Georg Brandl

#940286: pydoc.Helper.help() ignores input/output init parameters.

üst 4c4c0f2f
...@@ -1310,6 +1310,11 @@ doubt, consult the module reference at the location listed above. ...@@ -1310,6 +1310,11 @@ doubt, consult the module reference at the location listed above.
line += '\n' + self.indent(str(doc)) line += '\n' + self.indent(str(doc))
return line return line
class _PlainTextDoc(TextDoc):
"""Subclass of TextDoc which overrides string styling"""
def bold(self, text):
return text
# --------------------------------------------------------- user interfaces # --------------------------------------------------------- user interfaces
def pager(text): def pager(text):
...@@ -1464,6 +1469,7 @@ def locate(path, forceload=0): ...@@ -1464,6 +1469,7 @@ def locate(path, forceload=0):
# --------------------------------------- interactive interpreter interface # --------------------------------------- interactive interpreter interface
text = TextDoc() text = TextDoc()
plaintext = _PlainTextDoc()
html = HTMLDoc() html = HTMLDoc()
def resolve(thing, forceload=0): def resolve(thing, forceload=0):
...@@ -1476,8 +1482,11 @@ def resolve(thing, forceload=0): ...@@ -1476,8 +1482,11 @@ def resolve(thing, forceload=0):
else: else:
return thing, getattr(thing, '__name__', None) return thing, getattr(thing, '__name__', None)
def render_doc(thing, title='Python Library Documentation: %s', forceload=0): def render_doc(thing, title='Python Library Documentation: %s', forceload=0,
renderer=None):
"""Render text documentation, given an object or a path to an object.""" """Render text documentation, given an object or a path to an object."""
if renderer is None:
renderer = text
object, name = resolve(thing, forceload) object, name = resolve(thing, forceload)
desc = describe(object) desc = describe(object)
module = inspect.getmodule(object) module = inspect.getmodule(object)
...@@ -1496,12 +1505,16 @@ def render_doc(thing, title='Python Library Documentation: %s', forceload=0): ...@@ -1496,12 +1505,16 @@ def render_doc(thing, title='Python Library Documentation: %s', forceload=0):
# document its available methods instead of its value. # document its available methods instead of its value.
object = type(object) object = type(object)
desc += ' object' desc += ' object'
return title % desc + '\n\n' + text.document(object, name) return title % desc + '\n\n' + renderer.document(object, name)
def doc(thing, title='Python Library Documentation: %s', forceload=0): def doc(thing, title='Python Library Documentation: %s', forceload=0,
output=None):
"""Display text documentation, given an object or a path to an object.""" """Display text documentation, given an object or a path to an object."""
try: try:
pager(render_doc(thing, title, forceload)) if output is None:
pager(render_doc(thing, title, forceload))
else:
output.write(render_doc(thing, title, forceload, plaintext))
except (ImportError, ErrorDuringImport) as value: except (ImportError, ErrorDuringImport) as value:
print(value) print(value)
...@@ -1755,9 +1768,9 @@ has the same effect as typing a particular string at the help> prompt. ...@@ -1755,9 +1768,9 @@ has the same effect as typing a particular string at the help> prompt.
elif request in self.symbols: self.showsymbol(request) elif request in self.symbols: self.showsymbol(request)
elif request in self.keywords: self.showtopic(request) elif request in self.keywords: self.showtopic(request)
elif request in self.topics: self.showtopic(request) elif request in self.topics: self.showtopic(request)
elif request: doc(request, 'Help on %s:') elif request: doc(request, 'Help on %s:', output=self._output)
elif isinstance(request, Helper): self() elif isinstance(request, Helper): self()
else: doc(request, 'Help on %s:') else: doc(request, 'Help on %s:', output=self._output)
self.output.write('\n') self.output.write('\n')
def intro(self): def intro(self):
......
...@@ -9,9 +9,11 @@ import inspect ...@@ -9,9 +9,11 @@ import inspect
import unittest import unittest
import test.support import test.support
import xml.etree import xml.etree
import textwrap
from io import StringIO
from contextlib import contextmanager from contextlib import contextmanager
from test.support import ( from test.support import TESTFN, forget, rmtree, EnvironmentVarGuard, \
TESTFN, forget, rmtree, EnvironmentVarGuard, reap_children) reap_children, captured_output
from test import pydoc_mod from test import pydoc_mod
...@@ -327,6 +329,41 @@ class PyDocDocTest(unittest.TestCase): ...@@ -327,6 +329,41 @@ class PyDocDocTest(unittest.TestCase):
self.assertEqual(stripid("<type 'exceptions.Exception'>"), self.assertEqual(stripid("<type 'exceptions.Exception'>"),
"<type 'exceptions.Exception'>") "<type 'exceptions.Exception'>")
@unittest.skipIf(sys.flags.optimize >= 2,
'Docstrings are omitted with -O2 and above')
def test_help_output_redirect(self):
# issue 940286, if output is set in Helper, then all output from
# Helper.help should be redirected
old_pattern = expected_text_pattern
getpager_old = pydoc.getpager
getpager_new = lambda: (lambda x: x)
self.maxDiff = None
buf = StringIO()
helper = pydoc.Helper(output=buf)
unused, doc_loc = get_pydoc_text(pydoc_mod)
module = "test.pydoc_mod"
help_header = """
Help on module test.pydoc_mod in test:
""".lstrip()
help_header = textwrap.dedent(help_header)
expected_help_pattern = help_header + expected_text_pattern
pydoc.getpager = getpager_new
try:
with captured_output('stdout') as output, \
captured_output('stderr') as err:
helper.help(module)
result = buf.getvalue().strip()
expected_text = expected_help_pattern % \
(doc_loc, inspect.getabsfile(pydoc_mod))
self.assertEqual('', output.getvalue())
self.assertEqual('', err.getvalue())
self.assertEqual(expected_text, result)
finally:
pydoc.getpager = getpager_old
class TestDescriptions(unittest.TestCase): class TestDescriptions(unittest.TestCase):
......
...@@ -33,6 +33,8 @@ Core and Builtins ...@@ -33,6 +33,8 @@ Core and Builtins
Library Library
------- -------
- Issue #940286: pydoc.Helper.help() ignores input/output init parameters.
- Issue #1745035: Add a command size and data size limit to smtpd.py, to - Issue #1745035: Add a command size and data size limit to smtpd.py, to
prevent DoS attacks. Patch by Savio Sena. prevent DoS attacks. Patch by Savio Sena.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment