Merged revisions 87497 via svnmerge from

svn+ssh://pythondev@svn.python.org/python/branches/py3k

........
  r87497 | r.david.murray | 2010-12-26 14:54:29 -0500 (Sun, 26 Dec 2010) | 7 lines

  #5258/#10642: print fn, line, traceback and continue when .pth file is broken

  If a .pth file contained an error, it could cause a traceback in site.py,
  terminating its processing.  In 2.7 and 3.2, the interpreter will then not
  start.  Previously, a message would print saying to use -v to get the
  traceback.  In either case, the traceback generated for a failed .pth file did
  not include the .pth filename, making it difficult to debug the problem.  Now
  site.py reports not only the .pth filename but also the line number causing the
  error, and just skips the remainder of the file.
........
This commit is contained in:
R. David Murray 2010-12-26 22:29:53 +00:00
parent 8e726b4328
commit 5874ed6cee
3 changed files with 71 additions and 9 deletions

View File

@ -61,6 +61,7 @@ ImportError exception, it is silently ignored.
import sys import sys
import os import os
import __builtin__ import __builtin__
import traceback
# Prefixes for site-packages; add additional prefixes like /usr/local here # Prefixes for site-packages; add additional prefixes like /usr/local here
PREFIXES = [sys.prefix, sys.exec_prefix] PREFIXES = [sys.prefix, sys.exec_prefix]
@ -155,17 +156,26 @@ def addpackage(sitedir, name, known_paths):
except IOError: except IOError:
return return
with f: with f:
for line in f: for n, line in enumerate(f):
if line.startswith("#"): if line.startswith("#"):
continue continue
if line.startswith(("import ", "import\t")): try:
exec line if line.startswith(("import ", "import\t")):
continue exec line
line = line.rstrip() continue
dir, dircase = makepath(sitedir, line) line = line.rstrip()
if not dircase in known_paths and os.path.exists(dir): dir, dircase = makepath(sitedir, line)
sys.path.append(dir) if not dircase in known_paths and os.path.exists(dir):
known_paths.add(dircase) sys.path.append(dir)
known_paths.add(dircase)
except Exception as err:
print >>sys.stderr, "Error processing line {:d} of {}:\n".format(
n+1, fullname)
for record in traceback.format_exception(*sys.exc_info()):
for line in record.splitlines():
print >>sys.stderr, ' '+line
print >>sys.stderr, "\nRemainder of file ignored"
break
if reset: if reset:
known_paths = None known_paths = None
return known_paths return known_paths

View File

@ -6,6 +6,7 @@ executing have not been removed.
""" """
import unittest import unittest
from test.test_support import run_unittest, TESTFN, EnvironmentVarGuard from test.test_support import run_unittest, TESTFN, EnvironmentVarGuard
from test.test_support import captured_output
import __builtin__ import __builtin__
import os import os
import sys import sys
@ -94,6 +95,53 @@ class HelperFunctionsTests(unittest.TestCase):
finally: finally:
pth_file.cleanup() pth_file.cleanup()
def make_pth(self, contents, pth_dir='.', pth_name=TESTFN):
# Create a .pth file and return its (abspath, basename).
pth_dir = os.path.abspath(pth_dir)
pth_basename = pth_name + '.pth'
pth_fn = os.path.join(pth_dir, pth_basename)
pth_file = open(pth_fn, 'w')
self.addCleanup(lambda: os.remove(pth_fn))
pth_file.write(contents)
pth_file.close()
return pth_dir, pth_basename
def test_addpackage_import_bad_syntax(self):
# Issue 10642
pth_dir, pth_fn = self.make_pth("import bad)syntax\n")
with captured_output("stderr") as err_out:
site.addpackage(pth_dir, pth_fn, set())
self.assertRegexpMatches(err_out.getvalue(), "line 1")
self.assertRegexpMatches(err_out.getvalue(), os.path.join(pth_dir, pth_fn))
# XXX: the previous two should be independent checks so that the
# order doesn't matter. The next three could be a single check
# but my regex foo isn't good enough to write it.
self.assertRegexpMatches(err_out.getvalue(), 'Traceback')
self.assertRegexpMatches(err_out.getvalue(), r'import bad\)syntax')
self.assertRegexpMatches(err_out.getvalue(), 'SyntaxError')
def test_addpackage_import_bad_exec(self):
# Issue 10642
pth_dir, pth_fn = self.make_pth("randompath\nimport nosuchmodule\n")
with captured_output("stderr") as err_out:
site.addpackage(pth_dir, pth_fn, set())
self.assertRegexpMatches(err_out.getvalue(), "line 2")
self.assertRegexpMatches(err_out.getvalue(), os.path.join(pth_dir, pth_fn))
# XXX: ditto previous XXX comment.
self.assertRegexpMatches(err_out.getvalue(), 'Traceback')
self.assertRegexpMatches(err_out.getvalue(), 'ImportError')
def test_addpackage_import_bad_pth_file(self):
# Issue 5258
pth_dir, pth_fn = self.make_pth("abc\x00def\n")
with captured_output("stderr") as err_out:
site.addpackage(pth_dir, pth_fn, set())
self.assertRegexpMatches(err_out.getvalue(), "line 1")
self.assertRegexpMatches(err_out.getvalue(), os.path.join(pth_dir, pth_fn))
# XXX: ditto previous XXX comment.
self.assertRegexpMatches(err_out.getvalue(), 'Traceback')
self.assertRegexpMatches(err_out.getvalue(), 'TypeError')
def test_addsitedir(self): def test_addsitedir(self):
# Same tests for test_addpackage since addsitedir() essentially just # Same tests for test_addpackage since addsitedir() essentially just
# calls addpackage() for every .pth file in the directory # calls addpackage() for every .pth file in the directory

View File

@ -22,6 +22,10 @@ Core and Builtins
Library Library
------- -------
- Issue #5258/#10642: if site.py encounters a .pth file that generates an error,
it now prints the filename, line number, and traceback to stderr and skips
the rest of that individual file, instead of stopping processing entirely.
- Issue #10750: The ``raw`` attribute of buffered IO objects is now read-only. - Issue #10750: The ``raw`` attribute of buffered IO objects is now read-only.
- Issue #10242: unittest.TestCase.assertItemsEqual makes too many assumgptions - Issue #10242: unittest.TestCase.assertItemsEqual makes too many assumgptions