summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNick Coghlan <ncoghlan@gmail.com>2008-07-13 14:52:36 (GMT)
committerNick Coghlan <ncoghlan@gmail.com>2008-07-13 14:52:36 (GMT)
commitb028f509119d5ea7dd85d7f38df366ccc9d7bdb4 (patch)
tree0cef7d8095d49b149d12c1ce2d2044e4561c94e7
parent12c8660cc6f299464d61b3edd57a73dc6bcbffd7 (diff)
downloadcpython-b028f509119d5ea7dd85d7f38df366ccc9d7bdb4.zip
cpython-b028f509119d5ea7dd85d7f38df366ccc9d7bdb4.tar.gz
cpython-b028f509119d5ea7dd85d7f38df366ccc9d7bdb4.tar.bz2
Fix issue 3221 by emitting a RuntimeWarning instead of raising SystemError when the parent module can't be found during an absolute import (likely due to non-PEP 361 aware code which sets a module level __package__ attribute)
-rw-r--r--Lib/test/test_import.py36
-rw-r--r--Misc/NEWS6
-rw-r--r--Python/import.c25
3 files changed, 61 insertions, 6 deletions
diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py
index ab6fc25..ed9c7af 100644
--- a/Lib/test/test_import.py
+++ b/Lib/test/test_import.py
@@ -1,5 +1,3 @@
-from test.test_support import TESTFN, run_unittest, catch_warning
-
import unittest
import os
import random
@@ -7,7 +5,7 @@ import shutil
import sys
import py_compile
import warnings
-from test.test_support import unlink, TESTFN, unload
+from test.test_support import unlink, TESTFN, unload, run_unittest, catch_warning
def remove_files(name):
@@ -266,6 +264,38 @@ class RelativeImport(unittest.TestCase):
from . import relimport
self.assertTrue(hasattr(relimport, "RelativeImport"))
+ def test_issue3221(self):
+ def check_absolute():
+ exec "from os import path" in ns
+ def check_relative():
+ exec "from . import relimport" in ns
+ # Check both OK with __package__ and __name__ correct
+ ns = dict(__package__='test', __name__='test.notarealmodule')
+ check_absolute()
+ check_relative()
+ # Check both OK with only __name__ wrong
+ ns = dict(__package__='test', __name__='notarealpkg.notarealmodule')
+ check_absolute()
+ check_relative()
+ # Check relative fails with only __package__ wrong
+ ns = dict(__package__='foo', __name__='test.notarealmodule')
+ with catch_warning() as w:
+ check_absolute()
+ self.assert_('foo' in str(w.message))
+ self.assertEqual(w.category, RuntimeWarning)
+ self.assertRaises(SystemError, check_relative)
+ # Check relative fails with __package__ and __name__ wrong
+ ns = dict(__package__='foo', __name__='notarealpkg.notarealmodule')
+ with catch_warning() as w:
+ check_absolute()
+ self.assert_('foo' in str(w.message))
+ self.assertEqual(w.category, RuntimeWarning)
+ self.assertRaises(SystemError, check_relative)
+ # Check both fail with package set to a non-string
+ ns = dict(__package__=object())
+ self.assertRaises(ValueError, check_absolute)
+ self.assertRaises(ValueError, check_relative)
+
def test_main(verbose=None):
run_unittest(ImportTest, PathsTests, RelativeImport)
diff --git a/Misc/NEWS b/Misc/NEWS
index 0cee84e..e29a9b0 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,12 @@ What's New in Python 2.6 beta 2?
Core and Builtins
-----------------
+- Issue #3221: Issue a RuntimeWarning instead of raising SystemError if
+ the parent module cannot be found while performing an absolute import.
+ This means that an incorrectly defined __package__ attribute will
+ now only prevent relative imports in that module rather than causing
+ all imports from that module to fail.
+
- Issue #2517: Allow unicode messages in Exceptions again by correctly
bypassing the instance dictionary when looking up __unicode__ on
new-style classes.
diff --git a/Python/import.c b/Python/import.c
index b65ed0e..f0ee40a 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -2160,6 +2160,7 @@ get_parent(PyObject *globals, char *buf, Py_ssize_t *p_buflen, int level)
static PyObject *pathstr = NULL;
static PyObject *pkgstr = NULL;
PyObject *pkgname, *modname, *modpath, *modules, *parent;
+ int orig_level = level;
if (globals == NULL || !PyDict_Check(globals) || !level)
return Py_None;
@@ -2285,9 +2286,27 @@ get_parent(PyObject *globals, char *buf, Py_ssize_t *p_buflen, int level)
modules = PyImport_GetModuleDict();
parent = PyDict_GetItemString(modules, buf);
- if (parent == NULL)
- PyErr_Format(PyExc_SystemError,
- "Parent module '%.200s' not loaded", buf);
+ if (parent == NULL) {
+ if (orig_level < 1) {
+ PyObject *err_msg = PyString_FromFormat(
+ "Parent module '%.200s' not found "
+ "while handling absolute import", buf);
+ if (err_msg == NULL) {
+ return NULL;
+ }
+ if (!PyErr_WarnEx(PyExc_RuntimeWarning,
+ PyString_AsString(err_msg), 1)) {
+ *buf = '\0';
+ *p_buflen = 0;
+ parent = Py_None;
+ }
+ Py_DECREF(err_msg);
+ } else {
+ PyErr_Format(PyExc_SystemError,
+ "Parent module '%.200s' not loaded, "
+ "cannot perform relative import", buf);
+ }
+ }
return parent;
/* We expect, but can't guarantee, if parent != None, that:
- parent.__name__ == buf