summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Berg <sebastian@sipsolutions.net>2020-05-14 14:27:29 -0500
committerSebastian Berg <sebastian@sipsolutions.net>2020-12-15 12:39:47 -0600
commit7628292e005fd3d6faf1b77434d2224921d49ad8 (patch)
tree8566c77c58f7780e663bc0a5c706b5f21d37536b
parent74e135b261e4613963cc50ddb97ac2edbd5936ba (diff)
downloadnumpy-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__.py5
-rw-r--r--numpy/core/src/multiarray/multiarraymodule.c39
-rw-r--r--numpy/tests/test_reloading.py14
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
+