From 9df4e6f6735af274813cf1b611ee1a342955ad63 Mon Sep 17 00:00:00 2001 From: Thomas Wouters Date: Thu, 27 Apr 2006 23:13:20 +0000 Subject: - Add new Warning class, ImportWarning - Warn-raise ImportWarning when importing would have picked up a directory as package, if only it'd had an __init__.py. This swaps two tests (for case-ness and __init__-ness), but case-test is not really more expensive, and it's not in a speed-critical section. - Test for the new warning by importing a common non-package directory on sys.path: site-packages - In regrtest.py, silence warnings generated by the build-environment because Modules/ (which is added to sys.path for Setup-created modules) has 'zlib' and '_ctypes' directories without __init__.py's. --- Include/pyerrors.h | 1 + Lib/test/exception_hierarchy.txt | 1 + Lib/test/regrtest.py | 6 ++++++ Lib/test/test_import.py | 17 +++++++++++++++++ Python/exceptions.c | 5 +++++ Python/import.c | 37 ++++++++++++++++++++++++++++++------- 6 files changed, 60 insertions(+), 7 deletions(-) diff --git a/Include/pyerrors.h b/Include/pyerrors.h index 1fe2e45..edf3efd 100644 --- a/Include/pyerrors.h +++ b/Include/pyerrors.h @@ -108,6 +108,7 @@ PyAPI_DATA(PyObject *) PyExc_SyntaxWarning; PyAPI_DATA(PyObject *) PyExc_OverflowWarning; PyAPI_DATA(PyObject *) PyExc_RuntimeWarning; PyAPI_DATA(PyObject *) PyExc_FutureWarning; +PyAPI_DATA(PyObject *) PyExc_ImportWarning; /* Convenience functions */ diff --git a/Lib/test/exception_hierarchy.txt b/Lib/test/exception_hierarchy.txt index 9ed92d0..5fff7d9 100644 --- a/Lib/test/exception_hierarchy.txt +++ b/Lib/test/exception_hierarchy.txt @@ -44,3 +44,4 @@ BaseException +-- UserWarning +-- FutureWarning +-- OverflowWarning [not generated by the interpreter] + +-- ImportWarning diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py index 7db94aa..be06d9d 100755 --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -138,6 +138,12 @@ if sys.maxint > 0x7fffffff: warnings.filterwarnings("ignore", "hex/oct constants", FutureWarning, "") +# Ignore ImportWarnings that only occur in the source tree, +# (because of modules with the same name as source-directories in Modules/) +for mod in ("ctypes", "gzip", "test.test_zipimport", "test.test_zlib"): + warnings.filterwarnings(module=".*%s$" % (mod,), + action="ignore", category=ImportWarning) + # MacOSX (a.k.a. Darwin) has a default stack size that is too small # for deeply recursive regular expressions. We see this as crashes in # the Python test suite when running test_re.py and test_sre.py. The diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py index a72b8bd..effba3c 100644 --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -205,3 +205,20 @@ def test_import_name_binding(): assert y is test.test_support, y.__name__ test_import_name_binding() + +def test_import_initless_directory_warning(): + import warnings + oldfilters = warnings.filters[:] + warnings.simplefilter('error', ImportWarning); + try: + # Just a random non-package directory we always expect to be + # somewhere in sys.path... + __import__("site-packages") + except ImportWarning: + pass + else: + raise AssertionError + finally: + warnings.filters = oldfilters + +test_import_initless_directory_warning() diff --git a/Python/exceptions.c b/Python/exceptions.c index 5c824e6..31fb53e 100644 --- a/Python/exceptions.c +++ b/Python/exceptions.c @@ -1647,6 +1647,8 @@ PyDoc_STRVAR(FutureWarning__doc__, "Base class for warnings about constructs that will change semantically " "in the future."); +PyDoc_STRVAR(ImportWarning__doc__, +"Base class for warnings about probable mistakes in module imports"); /* module global functions */ @@ -1719,6 +1721,7 @@ PyObject *PyExc_SyntaxWarning; PyObject *PyExc_OverflowWarning; PyObject *PyExc_RuntimeWarning; PyObject *PyExc_FutureWarning; +PyObject *PyExc_ImportWarning; @@ -1818,6 +1821,8 @@ static struct { RuntimeWarning__doc__}, {"FutureWarning", &PyExc_FutureWarning, &PyExc_Warning, FutureWarning__doc__}, + {"ImportWarning", &PyExc_ImportWarning, &PyExc_Warning, + ImportWarning__doc__}, /* Sentinel */ {NULL} }; diff --git a/Python/import.c b/Python/import.c index 81027d8..6642082 100644 --- a/Python/import.c +++ b/Python/import.c @@ -1271,19 +1271,42 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf, #ifdef HAVE_STAT if (stat(buf, &statbuf) == 0 && /* it exists */ S_ISDIR(statbuf.st_mode) && /* it's a directory */ - find_init_module(buf) && /* it has __init__.py */ - case_ok(buf, len, namelen, name)) { /* and case matches */ - Py_XDECREF(copy); - return &fd_package; + case_ok(buf, len, namelen, name)) { /* case matches */ + if (find_init_module(buf)) { /* and has __init__.py */ + Py_XDECREF(copy); + return &fd_package; + } + else { + char warnstr[MAXPATHLEN+80]; + sprintf(warnstr, "Not importing directory " + "'%.*s': missing __init__.py", + MAXPATHLEN, buf); + if (PyErr_Warn(PyExc_ImportWarning, + warnstr)) { + Py_XDECREF(copy); + return NULL; + } + } } #else /* XXX How are you going to test for directories? */ #ifdef RISCOS if (isdir(buf) && - find_init_module(buf) && case_ok(buf, len, namelen, name)) { - Py_XDECREF(copy); - return &fd_package; + if (find_init_module(buf)) { + Py_XDECREF(copy); + return &fd_package; + } + else { + char warnstr[MAXPATHLEN+80]; + sprintf(warnstr, "Not importing directory " + "'%.*s': missing __init__.py", + MAXPATHLEN, buf); + if (PyErr_Warn(PyExc_ImportWarning, + warnstr)) { + Py_XDECREF(copy); + return NULL; + } } #endif #endif -- cgit v0.12