mirror of
https://github.com/python/cpython.git
synced 2025-10-10 00:43:41 +00:00
Issue 20123: Fix pydoc.synopsis() for "binary" modules.
Also add missing tests to test_pydoc.
This commit is contained in:
parent
244ad600e9
commit
aed5b22ead
3 changed files with 77 additions and 23 deletions
46
Lib/pydoc.py
46
Lib/pydoc.py
|
@ -225,34 +225,34 @@ def synopsis(filename, cache={}):
|
||||||
mtime = os.stat(filename).st_mtime
|
mtime = os.stat(filename).st_mtime
|
||||||
lastupdate, result = cache.get(filename, (None, None))
|
lastupdate, result = cache.get(filename, (None, None))
|
||||||
if lastupdate is None or lastupdate < mtime:
|
if lastupdate is None or lastupdate < mtime:
|
||||||
try:
|
# Look for binary suffixes first, falling back to source.
|
||||||
file = tokenize.open(filename)
|
if filename.endswith(tuple(importlib.machinery.BYTECODE_SUFFIXES)):
|
||||||
except OSError:
|
loader_cls = importlib.machinery.SourcelessFileLoader
|
||||||
# module can't be opened, so skip it
|
elif filename.endswith(tuple(importlib.machinery.EXTENSION_SUFFIXES)):
|
||||||
return None
|
loader_cls = importlib.machinery.ExtensionFileLoader
|
||||||
binary_suffixes = importlib.machinery.BYTECODE_SUFFIXES[:]
|
else:
|
||||||
binary_suffixes += importlib.machinery.EXTENSION_SUFFIXES[:]
|
loader_cls = None
|
||||||
if any(filename.endswith(x) for x in binary_suffixes):
|
# Now handle the choice.
|
||||||
# binary modules have to be imported
|
if loader_cls is None:
|
||||||
file.close()
|
# Must be a source file.
|
||||||
if any(filename.endswith(x) for x in
|
try:
|
||||||
importlib.machinery.BYTECODE_SUFFIXES):
|
file = tokenize.open(filename)
|
||||||
loader = importlib.machinery.SourcelessFileLoader('__temp__',
|
except OSError:
|
||||||
filename)
|
# module can't be opened, so skip it
|
||||||
else:
|
return None
|
||||||
loader = importlib.machinery.ExtensionFileLoader('__temp__',
|
# text modules can be directly examined
|
||||||
filename)
|
with file:
|
||||||
|
result = source_synopsis(file)
|
||||||
|
else:
|
||||||
|
# Must be a binary module, which has to be imported.
|
||||||
|
loader = loader_cls('__temp__', filename)
|
||||||
try:
|
try:
|
||||||
module = loader.load_module('__temp__')
|
module = loader.load_module('__temp__')
|
||||||
except:
|
except:
|
||||||
return None
|
return None
|
||||||
result = (module.__doc__ or '').splitlines()[0]
|
|
||||||
del sys.modules['__temp__']
|
del sys.modules['__temp__']
|
||||||
else:
|
result = (module.__doc__ or '').splitlines()[0]
|
||||||
# text modules can be directly examined
|
# Cache the result.
|
||||||
result = source_synopsis(file)
|
|
||||||
file.close()
|
|
||||||
|
|
||||||
cache[filename] = (mtime, result)
|
cache[filename] = (mtime, result)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
|
@ -487,6 +487,13 @@ class PydocDocTest(unittest.TestCase):
|
||||||
synopsis = pydoc.synopsis(TESTFN, {})
|
synopsis = pydoc.synopsis(TESTFN, {})
|
||||||
self.assertEqual(synopsis, 'line 1: h\xe9')
|
self.assertEqual(synopsis, 'line 1: h\xe9')
|
||||||
|
|
||||||
|
def test_synopsis_sourceless(self):
|
||||||
|
expected = os.__doc__.splitlines()[0]
|
||||||
|
filename = os.__cached__
|
||||||
|
synopsis = pydoc.synopsis(filename)
|
||||||
|
|
||||||
|
self.assertEqual(synopsis, expected)
|
||||||
|
|
||||||
def test_splitdoc_with_description(self):
|
def test_splitdoc_with_description(self):
|
||||||
example_string = "I Am A Doc\n\n\nHere is my description"
|
example_string = "I Am A Doc\n\n\nHere is my description"
|
||||||
self.assertEqual(pydoc.splitdoc(example_string),
|
self.assertEqual(pydoc.splitdoc(example_string),
|
||||||
|
@ -600,6 +607,50 @@ class PydocImportTest(PydocBaseTest):
|
||||||
self.assertEqual(out.getvalue(), '')
|
self.assertEqual(out.getvalue(), '')
|
||||||
self.assertEqual(err.getvalue(), '')
|
self.assertEqual(err.getvalue(), '')
|
||||||
|
|
||||||
|
def test_modules(self):
|
||||||
|
# See Helper.listmodules().
|
||||||
|
num_header_lines = 2
|
||||||
|
num_module_lines_min = 5 # Playing it safe.
|
||||||
|
num_footer_lines = 3
|
||||||
|
expected = num_header_lines + num_module_lines_min + num_footer_lines
|
||||||
|
|
||||||
|
output = StringIO()
|
||||||
|
helper = pydoc.Helper(output=output)
|
||||||
|
helper('modules')
|
||||||
|
result = output.getvalue().strip()
|
||||||
|
num_lines = len(result.splitlines())
|
||||||
|
|
||||||
|
self.assertGreaterEqual(num_lines, expected)
|
||||||
|
|
||||||
|
def test_modules_search(self):
|
||||||
|
# See Helper.listmodules().
|
||||||
|
expected = 'pydoc - '
|
||||||
|
|
||||||
|
output = StringIO()
|
||||||
|
helper = pydoc.Helper(output=output)
|
||||||
|
with captured_stdout() as help_io:
|
||||||
|
helper('modules pydoc')
|
||||||
|
result = help_io.getvalue()
|
||||||
|
|
||||||
|
self.assertIn(expected, result)
|
||||||
|
|
||||||
|
def test_modules_search_builtin(self):
|
||||||
|
expected = 'gc - '
|
||||||
|
|
||||||
|
output = StringIO()
|
||||||
|
helper = pydoc.Helper(output=output)
|
||||||
|
with captured_stdout() as help_io:
|
||||||
|
helper('modules garbage')
|
||||||
|
result = help_io.getvalue()
|
||||||
|
|
||||||
|
self.assertTrue(result.startswith(expected))
|
||||||
|
|
||||||
|
def test_importfile(self):
|
||||||
|
loaded_pydoc = pydoc.importfile(pydoc.__file__)
|
||||||
|
|
||||||
|
self.assertEqual(loaded_pydoc.__name__, 'pydoc')
|
||||||
|
self.assertEqual(loaded_pydoc.__file__, pydoc.__file__)
|
||||||
|
|
||||||
|
|
||||||
class TestDescriptions(unittest.TestCase):
|
class TestDescriptions(unittest.TestCase):
|
||||||
|
|
||||||
|
@ -827,6 +878,7 @@ class PydocWithMetaClasses(unittest.TestCase):
|
||||||
print_diffs(expected_text, result)
|
print_diffs(expected_text, result)
|
||||||
self.fail("outputs are not equal, see diff above")
|
self.fail("outputs are not equal, see diff above")
|
||||||
|
|
||||||
|
|
||||||
@reap_threads
|
@reap_threads
|
||||||
def test_main():
|
def test_main():
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -221,6 +221,8 @@ Library
|
||||||
- Issue #19782: imaplib now supports SSLContext.check_hostname and server name
|
- Issue #19782: imaplib now supports SSLContext.check_hostname and server name
|
||||||
indication for TLS/SSL connections.
|
indication for TLS/SSL connections.
|
||||||
|
|
||||||
|
- Issue 20123: Fix pydoc.synopsis() for "binary" modules.
|
||||||
|
|
||||||
- Issue #19834: Support unpickling of exceptions pickled by Python 2.
|
- Issue #19834: Support unpickling of exceptions pickled by Python 2.
|
||||||
|
|
||||||
- Issue #19781: ftplib now supports SSLContext.check_hostname and server name
|
- Issue #19781: ftplib now supports SSLContext.check_hostname and server name
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue