summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/site.py28
-rw-r--r--Lib/test/test_site.py48
-rw-r--r--Misc/NEWS4
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
diff --git a/Misc/NEWS b/Misc/NEWS
index 704547a..fe075fe 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -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