diff options
author | Sebastian Berg <sebastian@sipsolutions.net> | 2020-05-14 14:27:29 -0500 |
---|---|---|
committer | Sebastian Berg <sebastian@sipsolutions.net> | 2020-12-15 12:39:47 -0600 |
commit | 7628292e005fd3d6faf1b77434d2224921d49ad8 (patch) | |
tree | 8566c77c58f7780e663bc0a5c706b5f21d37536b | |
parent | 74e135b261e4613963cc50ddb97ac2edbd5936ba (diff) | |
download | numpy-7628292e005fd3d6faf1b77434d2224921d49ad8.tar.gz |
DOC: Warn when reloading numpy or using numpy in sub-interpreter
This adds a warning when the main NumPy module is reloaded
with the assumption that in this case objects such as `np.matrix`,
`np._NoValue` or exceptions may be cached internally.
It also gives a warning when NumPy is imported in a sub-interpreter.
-rw-r--r-- | numpy/__init__.py | 5 | ||||
-rw-r--r-- | numpy/core/src/multiarray/multiarraymodule.c | 39 | ||||
-rw-r--r-- | numpy/tests/test_reloading.py | 14 |
3 files changed, 53 insertions, 5 deletions
diff --git a/numpy/__init__.py b/numpy/__init__.py index 879e8f013..a242bb7df 100644 --- a/numpy/__init__.py +++ b/numpy/__init__.py @@ -389,7 +389,12 @@ else: # Note that this will currently only make a difference on Linux core.multiarray._set_madvise_hugepage(use_hugepage) + # Give a warning if NumPy is reloaded or imported on a sub-interpreter + # We do this from python, since the C-module may not be reloaded and + # it is tidier organized. + core.multiarray._multiarray_umath._reload_guard() from ._version import get_versions __version__ = get_versions()['version'] del get_versions + diff --git a/numpy/core/src/multiarray/multiarraymodule.c b/numpy/core/src/multiarray/multiarraymodule.c index 32c5ac0dc..870b633ed 100644 --- a/numpy/core/src/multiarray/multiarraymodule.c +++ b/numpy/core/src/multiarray/multiarraymodule.c @@ -4085,6 +4085,42 @@ normalize_axis_index(PyObject *NPY_UNUSED(self), PyObject *args, PyObject *kwds) } +static PyObject * +_reload_guard(PyObject *NPY_UNUSED(self)) { + static int initialized = 0; + +#if !defined(PYPY_VERSION) + if (PyThreadState_Get()->interp != PyInterpreterState_Main()) { + if (PyErr_WarnEx(PyExc_UserWarning, + "NumPy was imported from a Python sub-interpreter but " + "NumPy does not properly support sub-interpreters. " + "This will likely work for most users but might cause hard to " + "track down issues or subtle bugs. " + "A common user of the rare sub-interpreter feature is wsgi " + "which also allows single-interpreter mode.\n" + "Improvements in the case of bugs are welcome, but is not " + "on the NumPy roadmap, and full support may require " + "significant effort to achieve.", 2) < 0) { + return NULL; + } + /* No need to give the other warning in a sub-interpreter as well... */ + initialized = 1; + Py_RETURN_NONE; + } +#endif + if (initialized) { + if (PyErr_WarnEx(PyExc_UserWarning, + "The NumPy module was reloaded (imported a second time). " + "This can in some cases result in small but subtle issues " + "and is discouraged.", 2) < 0) { + return NULL; + } + } + initialized = 1; + Py_RETURN_NONE; +} + + static struct PyMethodDef array_module_methods[] = { {"_get_implementing_args", (PyCFunction)array__get_implementing_args, @@ -4276,6 +4312,9 @@ static struct PyMethodDef array_module_methods[] = { METH_VARARGS, NULL}, {"_set_madvise_hugepage", (PyCFunction)_set_madvise_hugepage, METH_O, NULL}, + {"_reload_guard", (PyCFunction)_reload_guard, + METH_NOARGS, + "Give a warning on reload and big warning in sub-interpreters."}, {NULL, NULL, 0, NULL} /* sentinel */ }; diff --git a/numpy/tests/test_reloading.py b/numpy/tests/test_reloading.py index 61ae91b00..5c4309f4a 100644 --- a/numpy/tests/test_reloading.py +++ b/numpy/tests/test_reloading.py @@ -1,4 +1,4 @@ -from numpy.testing import assert_raises, assert_, assert_equal +from numpy.testing import assert_raises, assert_warns, assert_, assert_equal from numpy.compat import pickle import sys @@ -16,13 +16,15 @@ def test_numpy_reloading(): VisibleDeprecationWarning = np.VisibleDeprecationWarning ModuleDeprecationWarning = np.ModuleDeprecationWarning - reload(np) + with assert_warns(UserWarning): + reload(np) assert_(_NoValue is np._NoValue) assert_(ModuleDeprecationWarning is np.ModuleDeprecationWarning) assert_(VisibleDeprecationWarning is np.VisibleDeprecationWarning) assert_raises(RuntimeError, reload, numpy._globals) - reload(np) + with assert_warns(UserWarning): + reload(np) assert_(_NoValue is np._NoValue) assert_(ModuleDeprecationWarning is np.ModuleDeprecationWarning) assert_(VisibleDeprecationWarning is np.VisibleDeprecationWarning) @@ -45,13 +47,15 @@ def test_full_reimport(): # This is generally unsafe, especially, since we also reload the C-modules. code = textwrap.dedent(r""" import sys + from pytest import warns import numpy as np for k in list(sys.modules.keys()): if "numpy" in k: del sys.modules[k] - import numpy as np + with warns(UserWarning): + import numpy as np """) p = subprocess.run([sys.executable, '-c', code]) - assert p.returncode == 0 + |