Commit b028f509 authored by Nick Coghlan's avatar Nick Coghlan

Fix issue 3221 by emitting a RuntimeWarning instead of raising SystemError...

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)
parent 12c8660c
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.
......
......@@ -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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment