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 9d1084a..a2c0bec 100644
--- a/Lib/site.py
+++ b/Lib/site.py
@@ -55,6 +55,7 @@ ImportError exception, it is silently ignored.
import sys
import os
import builtins
+import traceback
# Prefixes for site-packages; add additional prefixes like /usr/local here
PREFIXES = [sys.prefix, sys.exec_prefix]
@@ -141,17 +142,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("Error processing line {:d} of {}:\n".format(n+1, fullname),
+ file=sys.stderr)
+ for record in traceback.format_exception(*sys.exc_info()):
+ for line in record.splitlines():
+ print(' '+line, file=sys.stderr)
+ print("\nRemainder of file ignored", file=sys.stderr)
+ break
if reset:
known_paths = None
return known_paths
diff --git a/Lib/test/test_site.py b/Lib/test/test_site.py
index 94d6699..0ed4706 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.support import run_unittest, TESTFN, EnvironmentVarGuard
+from test.support import captured_stderr
import builtins
import os
import sys
@@ -90,6 +91,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', encoding='utf-8')
+ 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_stderr() as err_out:
+ site.addpackage(pth_dir, pth_fn, set())
+ self.assertRegex(err_out.getvalue(), "line 1")
+ self.assertRegex(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.assertRegex(err_out.getvalue(), 'Traceback')
+ self.assertRegex(err_out.getvalue(), r'import bad\)syntax')
+ self.assertRegex(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_stderr() as err_out:
+ site.addpackage(pth_dir, pth_fn, set())
+ self.assertRegex(err_out.getvalue(), "line 2")
+ self.assertRegex(err_out.getvalue(), os.path.join(pth_dir, pth_fn))
+ # XXX: ditto previous XXX comment.
+ self.assertRegex(err_out.getvalue(), 'Traceback')
+ self.assertRegex(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_stderr() as err_out:
+ site.addpackage(pth_dir, pth_fn, set())
+ self.assertRegex(err_out.getvalue(), "line 1")
+ self.assertRegex(err_out.getvalue(), os.path.join(pth_dir, pth_fn))
+ # XXX: ditto previous XXX comment.
+ self.assertRegex(err_out.getvalue(), 'Traceback')
+ self.assertRegex(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 88dd836..4d86c94 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -11,6 +11,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 #10763: subprocess.communicate() closes stdout and stderr if both are
pipes (bug specific to Windows).