-from test.test_support import TESTFN, run_unittest, catch_warning
-
import unittest
import os
import random
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):
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)
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.
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;
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