diff options
author | Nick Coghlan <ncoghlan@gmail.com> | 2008-07-13 14:52:36 (GMT) |
---|---|---|
committer | Nick Coghlan <ncoghlan@gmail.com> | 2008-07-13 14:52:36 (GMT) |
commit | b028f509119d5ea7dd85d7f38df366ccc9d7bdb4 (patch) | |
tree | 0cef7d8095d49b149d12c1ce2d2044e4561c94e7 | |
parent | 12c8660cc6f299464d61b3edd57a73dc6bcbffd7 (diff) | |
download | cpython-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.py | 36 | ||||
-rw-r--r-- | Misc/NEWS | 6 | ||||
-rw-r--r-- | Python/import.c | 25 |
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) @@ -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 |