diff --git a/Lib/pydoc.py b/Lib/pydoc.py index 1103b013cc65..9920fcb2de93 100755 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -55,6 +55,7 @@ class or function within a module or module in a package. If the import sys, imp, os, re, types, inspect, __builtin__, pkgutil from repr import Repr from string import expandtabs, find, join, lower, split, strip, rfind, rstrip +from traceback import extract_tb try: from collections import deque except ImportError: @@ -299,9 +300,9 @@ def safeimport(path, forceload=0, cache={}): elif exc is SyntaxError: # A SyntaxError occurred before we could execute the module. raise ErrorDuringImport(value.filename, info) - elif exc is ImportError and \ - split(lower(str(value)))[:2] == ['no', 'module']: - # The module was not found. + elif exc is ImportError and extract_tb(tb)[-1][2]=='safeimport': + # The import error occurred directly in this function, + # which means there is no such module in the path. return None else: # Some other error occurred during the importing process. diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py index 7990d3a492d9..ea66d262eac3 100644 --- a/Lib/test/test_pydoc.py +++ b/Lib/test/test_pydoc.py @@ -1,5 +1,6 @@ import sys import os +import os.path import difflib import subprocess import re @@ -7,6 +8,8 @@ import inspect import unittest import test.test_support +from contextlib import contextmanager +from test.test_support import TESTFN, forget, rmtree, EnvironmentVarGuard from test import pydoc_mod @@ -166,6 +169,9 @@ class B(__builtin__.object) # output pattern for missing module missing_pattern = "no Python documentation found for '%s'" +# output pattern for module with bad imports +badimport_pattern = "problem in %s - : No module named %s" + def run_pydoc(module_name, *args): """ Runs pydoc on the specified module. Returns the stripped @@ -237,6 +243,43 @@ def test_not_here(self): self.assertEqual(expected, result, "documentation for missing module found") + def test_badimport(self): + # This tests the fix for issue 5230, where if pydoc found the module + # but the module had an internal import error pydoc would report no doc + # found. + modname = 'testmod_xyzzy' + testpairs = ( + ('i_am_not_here', 'i_am_not_here'), + ('test.i_am_not_here_either', 'i_am_not_here_either'), + ('test.i_am_not_here.neither_am_i', 'i_am_not_here.neither_am_i'), + ('i_am_not_here.{0}'.format(modname), 'i_am_not_here.{0}'.format(modname)), + ('test.{0}'.format(modname), modname), + ) + + @contextmanager + def newdirinpath(dir): + os.mkdir(dir) + sys.path.insert(0, dir) + yield + sys.path.pop(0) + rmtree(dir) + + with newdirinpath(TESTFN): + with EnvironmentVarGuard() as env: + env.set('PYTHONPATH', TESTFN) + fullmodname = os.path.join(TESTFN, modname) + sourcefn = fullmodname + os.extsep + "py" + for importstring, expectedinmsg in testpairs: + f = open(sourcefn, 'w') + f.write("import {0}\n".format(importstring)) + f.close() + try: + result = run_pydoc(modname) + finally: + forget(modname) + expected = badimport_pattern % (modname, expectedinmsg) + self.assertEqual(expected, result) + def test_input_strip(self): missing_module = " test.i_am_not_here " result = run_pydoc(missing_module) diff --git a/Misc/ACKS b/Misc/ACKS index e0890e869540..b35cc4795ff8 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -464,6 +464,7 @@ Andrew McNamara Craig McPheeters Lambert Meertens Bill van Melle +Lucas Prado Melo Luke Mewburn Mike Meyer Steven Miale diff --git a/Misc/NEWS b/Misc/NEWS index 378435b79c09..06cd333a3bda 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -56,6 +56,10 @@ Core and Builtins Library ------- +- Issue #5230: pydoc would report no documentation found if a module generated + a 'not found' import error when loaded; it now reports the import errors. + Thanks to Lucas Prado Melo for initial fix and collaboration on the tests. + - Issue #6274: Fixed possible file descriptors leak in subprocess.py - Issue #6271: mmap tried to close invalid file handle (-1) when annonymous.