mirror of
https://github.com/python/cpython.git
synced 2026-01-30 19:22:20 +00:00
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)
This commit is contained in:
parent
12c8660cc6
commit
b028f50911
3 changed files with 61 additions and 6 deletions
|
|
@ -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 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 @@ def test_relimport_star(self):
|
|||
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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue