From 54237f9feaefd209c2aaa5b4003810e69f6714f3 Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Mon, 16 Feb 2015 19:45:01 -0500 Subject: fix pydoc.apropos and pydoc.synopsis on modules with empty docstrings (#21548) Patch by Yuyang Guo and Berker Peksag. --- Lib/pydoc.py | 4 ++-- Lib/test/test_pydoc.py | 32 ++++++++++++++++++++++++++++++++ Misc/ACKS | 1 + Misc/NEWS | 3 +++ 4 files changed, 38 insertions(+), 2 deletions(-) diff --git a/Lib/pydoc.py b/Lib/pydoc.py index d53a1b4..d37ebf1 100755 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -270,7 +270,7 @@ def synopsis(filename, cache={}): except: return None del sys.modules['__temp__'] - result = (module.__doc__ or '').splitlines()[0] + result = module.__doc__.splitlines()[0] if module.__doc__ else None # Cache the result. cache[filename] = (mtime, result) return result @@ -2075,7 +2075,7 @@ class ModuleScanner: if onerror: onerror(modname) continue - desc = (module.__doc__ or '').splitlines()[0] + desc = module.__doc__.splitlines()[0] if module.__doc__ else '' path = getattr(module,'__file__',None) name = modname + ' - ' + desc if name.lower().find(key) >= 0: diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py index 8bf9b20..1427c77 100644 --- a/Lib/test/test_pydoc.py +++ b/Lib/test/test_pydoc.py @@ -3,12 +3,15 @@ import sys import builtins import contextlib import difflib +import importlib.util import inspect import pydoc +import py_compile import keyword import _pickle import pkgutil import re +import stat import string import test.support import time @@ -557,6 +560,18 @@ class PydocDocTest(unittest.TestCase): self.assertEqual(synopsis, expected) + def test_synopsis_sourceless_empty_doc(self): + with test.support.temp_cwd() as test_dir: + init_path = os.path.join(test_dir, 'foomod42.py') + cached_path = importlib.util.cache_from_source(init_path) + with open(init_path, 'w') as fobj: + fobj.write("foo = 1") + py_compile.compile(init_path) + synopsis = pydoc.synopsis(init_path, {}) + self.assertIsNone(synopsis) + synopsis_cached = pydoc.synopsis(cached_path, {}) + self.assertIsNone(synopsis_cached) + def test_splitdoc_with_description(self): example_string = "I Am A Doc\n\n\nHere is my description" self.assertEqual(pydoc.splitdoc(example_string), @@ -612,6 +627,7 @@ class PydocImportTest(PydocBaseTest): def setUp(self): self.test_dir = os.mkdir(TESTFN) self.addCleanup(rmtree, TESTFN) + importlib.invalidate_caches() def test_badimport(self): # This tests the fix for issue 5230, where if pydoc found the module @@ -670,6 +686,22 @@ class PydocImportTest(PydocBaseTest): self.assertEqual(out.getvalue(), '') self.assertEqual(err.getvalue(), '') + def test_apropos_empty_doc(self): + pkgdir = os.path.join(TESTFN, 'walkpkg') + os.mkdir(pkgdir) + self.addCleanup(rmtree, pkgdir) + init_path = os.path.join(pkgdir, '__init__.py') + with open(init_path, 'w') as fobj: + fobj.write("foo = 1") + current_mode = stat.S_IMODE(os.stat(pkgdir).st_mode) + try: + os.chmod(pkgdir, current_mode & ~stat.S_IEXEC) + with self.restrict_walk_packages(path=[TESTFN]), captured_stdout() as stdout: + pydoc.apropos('') + self.assertIn('walkpkg', stdout.getvalue()) + finally: + os.chmod(pkgdir, current_mode) + @unittest.skip('causes undesireable side-effects (#20128)') def test_modules(self): # See Helper.listmodules(). diff --git a/Misc/ACKS b/Misc/ACKS index 65518db..71f4048 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -506,6 +506,7 @@ Eric Groo Dag Gruneau Filip Gruszczyński Thomas Guettler +Yuyang Guo Anuj Gupta Michael Guravage Lars Gustäbel diff --git a/Misc/NEWS b/Misc/NEWS index b453fe4..3f50594 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,9 @@ Core and Builtins Library ------- +- Issue #21548: Fix pydoc.synopsis() and pydoc.apropos() on modules with empty + docstrings. + - Issue #22885: Fixed arbitrary code execution vulnerability in the dbm.dumb module. Original patch by Claudiu Popa. -- cgit v0.12