diff options
-rwxr-xr-x | Lib/pydoc.py | 46 | ||||
-rw-r--r-- | Lib/test/test_pydoc.py | 52 | ||||
-rw-r--r-- | Misc/NEWS | 2 |
3 files changed, 77 insertions, 23 deletions
diff --git a/Lib/pydoc.py b/Lib/pydoc.py index 2e63226..1369e8a 100755 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -225,34 +225,34 @@ def synopsis(filename, cache={}): mtime = os.stat(filename).st_mtime lastupdate, result = cache.get(filename, (None, None)) if lastupdate is None or lastupdate < mtime: - try: - file = tokenize.open(filename) - except OSError: - # module can't be opened, so skip it - return None - binary_suffixes = importlib.machinery.BYTECODE_SUFFIXES[:] - binary_suffixes += importlib.machinery.EXTENSION_SUFFIXES[:] - if any(filename.endswith(x) for x in binary_suffixes): - # binary modules have to be imported - file.close() - if any(filename.endswith(x) for x in - importlib.machinery.BYTECODE_SUFFIXES): - loader = importlib.machinery.SourcelessFileLoader('__temp__', - filename) - else: - loader = importlib.machinery.ExtensionFileLoader('__temp__', - filename) + # Look for binary suffixes first, falling back to source. + if filename.endswith(tuple(importlib.machinery.BYTECODE_SUFFIXES)): + loader_cls = importlib.machinery.SourcelessFileLoader + elif filename.endswith(tuple(importlib.machinery.EXTENSION_SUFFIXES)): + loader_cls = importlib.machinery.ExtensionFileLoader + else: + loader_cls = None + # Now handle the choice. + if loader_cls is None: + # Must be a source file. + try: + file = tokenize.open(filename) + except OSError: + # module can't be opened, so skip it + return None + # text modules can be directly examined + with file: + result = source_synopsis(file) + else: + # Must be a binary module, which has to be imported. + loader = loader_cls('__temp__', filename) try: module = loader.load_module('__temp__') except: return None - result = (module.__doc__ or '').splitlines()[0] del sys.modules['__temp__'] - else: - # text modules can be directly examined - result = source_synopsis(file) - file.close() - + result = (module.__doc__ or '').splitlines()[0] + # Cache the result. cache[filename] = (mtime, result) return result diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py index cdf28a4..7fe0644 100644 --- a/Lib/test/test_pydoc.py +++ b/Lib/test/test_pydoc.py @@ -487,6 +487,13 @@ class PydocDocTest(unittest.TestCase): synopsis = pydoc.synopsis(TESTFN, {}) 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): example_string = "I Am A Doc\n\n\nHere is my description" self.assertEqual(pydoc.splitdoc(example_string), @@ -600,6 +607,50 @@ class PydocImportTest(PydocBaseTest): self.assertEqual(out.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): @@ -827,6 +878,7 @@ class PydocWithMetaClasses(unittest.TestCase): print_diffs(expected_text, result) self.fail("outputs are not equal, see diff above") + @reap_threads def test_main(): try: @@ -221,6 +221,8 @@ Library - Issue #19782: imaplib now supports SSLContext.check_hostname and server name indication for TLS/SSL connections. +- Issue 20123: Fix pydoc.synopsis() for "binary" modules. + - Issue #19834: Support unpickling of exceptions pickled by Python 2. - Issue #19781: ftplib now supports SSLContext.check_hostname and server name |