]> granicus.if.org Git - python/commitdiff
Merged revisions 87497 via svnmerge from
authorR. David Murray <rdmurray@bitdance.com>
Sun, 26 Dec 2010 22:29:53 +0000 (22:29 +0000)
committerR. David Murray <rdmurray@bitdance.com>
Sun, 26 Dec 2010 22:29:53 +0000 (22:29 +0000)
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.
........

Lib/site.py
Lib/test/test_site.py
Misc/NEWS

index f22e1d10009a06d884cc0d3ab70d885b62d25932..90cf3313390ae98a99d5ed40e0f7addfed66f4dc 100644 (file)
@@ -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
index 4e801e9d915b10abee4be82299180fd85c2c1dce..0f8405a543eea024aa2dac5a2376b501c3696a16 100644 (file)
@@ -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
index 704547ad68a362220cf443231e5a18ff96e581f8..fe075fe09881d31f048939821e5134beadd8cd2d 100644 (file)
--- 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