diff options
| -rw-r--r-- | Lib/site.py | 28 | ||||
| -rw-r--r-- | Lib/test/test_site.py | 48 | ||||
| -rw-r--r-- | Misc/NEWS | 4 |
3 files changed, 71 insertions, 9 deletions
diff --git a/Lib/site.py b/Lib/site.py index f22e1d1..90cf331 100644 --- a/Lib/site.py +++ b/Lib/site.py @@ -61,6 +61,7 @@ ImportError exception, it is silently ignored. import sys import os import __builtin__ +import traceback # Prefixes for site-packages; add additional prefixes like /usr/local here PREFIXES = [sys.prefix, sys.exec_prefix] @@ -155,17 +156,26 @@ def addpackage(sitedir, name, known_paths): except IOError: return with f: - for line in f: + for n, line in enumerate(f): if line.startswith("#"): continue - if line.startswith(("import ", "import\t")): - exec line - continue - line = line.rstrip() - dir, dircase = makepath(sitedir, line) - if not dircase in known_paths and os.path.exists(dir): - sys.path.append(dir) - known_paths.add(dircase) + try: + if line.startswith(("import ", "import\t")): + exec line + continue + line = line.rstrip() + dir, dircase = makepath(sitedir, line) + if not dircase in known_paths and os.path.exists(dir): + 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: known_paths = None return known_paths diff --git a/Lib/test/test_site.py b/Lib/test/test_site.py index 4e801e9..0f8405a 100644 --- a/Lib/test/test_site.py +++ b/Lib/test/test_site.py @@ -6,6 +6,7 @@ executing have not been removed. """ import unittest from test.test_support import run_unittest, TESTFN, EnvironmentVarGuard +from test.test_support import captured_output import __builtin__ import os import sys @@ -94,6 +95,53 @@ class HelperFunctionsTests(unittest.TestCase): finally: 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): # Same tests for test_addpackage since addsitedir() essentially just # calls addpackage() for every .pth file in the directory @@ -22,6 +22,10 @@ Core and Builtins 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 #10242: unittest.TestCase.assertItemsEqual makes too many assumgptions |
