diff options
author | Benjamin Peterson <benjamin@python.org> | 2015-02-17 00:45:01 (GMT) |
---|---|---|
committer | Benjamin Peterson <benjamin@python.org> | 2015-02-17 00:45:01 (GMT) |
commit | 54237f9feaefd209c2aaa5b4003810e69f6714f3 (patch) | |
tree | f6dc68eea09d8fd6f6115259723914296aa01d6c | |
parent | 3584056ca58957a6adca060419e48a9488852550 (diff) | |
download | cpython-54237f9feaefd209c2aaa5b4003810e69f6714f3.zip cpython-54237f9feaefd209c2aaa5b4003810e69f6714f3.tar.gz cpython-54237f9feaefd209c2aaa5b4003810e69f6714f3.tar.bz2 |
fix pydoc.apropos and pydoc.synopsis on modules with empty docstrings (#21548)
Patch by Yuyang Guo and Berker Peksag.
-rwxr-xr-x | Lib/pydoc.py | 4 | ||||
-rw-r--r-- | Lib/test/test_pydoc.py | 32 | ||||
-rw-r--r-- | Misc/ACKS | 1 | ||||
-rw-r--r-- | 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(). @@ -506,6 +506,7 @@ Eric Groo Dag Gruneau Filip Gruszczyński Thomas Guettler +Yuyang Guo Anuj Gupta Michael Guravage Lars Gustäbel @@ -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. |