]> granicus.if.org Git - python/commitdiff
Fix issue 3221 by emitting a RuntimeWarning instead of raising SystemError when the...
authorNick Coghlan <ncoghlan@gmail.com>
Sun, 13 Jul 2008 14:52:36 +0000 (14:52 +0000)
committerNick Coghlan <ncoghlan@gmail.com>
Sun, 13 Jul 2008 14:52:36 +0000 (14:52 +0000)
Lib/test/test_import.py
Misc/NEWS
Python/import.c

index ab6fc2546dc5c0e1c3e7af5747119d99061958c4..ed9c7af40619e65f5f2865eae19cad8458ccda7c 100644 (file)
@@ -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)
 
index 0cee84e5cf963e818075ca8cfa6958f05f27434a..e29a9b079019782c8d051481483c129cc4697b2c 100644 (file)
--- 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.
index b65ed0e86afac150956a7d952c1e0d555ecba686..f0ee40a6ce02804a38f3cf3fff5525a53b6659c5 100644 (file)
@@ -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