summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Berg <sebastian@sipsolutions.net>2019-07-08 13:18:44 -0700
committerSebastian Berg <sebastian@sipsolutions.net>2019-07-16 17:21:44 -0700
commit81cfd4726c2d441406b3f7bd78716d664377fee2 (patch)
treed804ceeb99c5884e2f27179ab4e9ab3c74c6c209
parent88021a568cc13ef7325a52e22573f027a2be9df7 (diff)
downloadnumpy-81cfd4726c2d441406b3f7bd78716d664377fee2.tar.gz
DEP: Speed up WarnOnWrite deprecation in buffer interface
When a buffer interface does not request a writeable buffer, simply pass a read-only one when the warn on write flag is set. This is to give an easier way forward with avoiding the deprecation warnings: Simply do not ask for a writeable buffer. It will break code that expects writeable buffers but does not ask for them specifically a bit harder than would be nice. But since such code probably should ask for it specifically, this is likely fine (an RC release has to find out). The main reason for this is, that this way it plays very will with cython, which requests writeable buffers explicitly and if declared `const` is happy about read-only (so that using `const` is the best way to avoid the warning and makes code cleaner). Closes gh-13929, gh-13974
-rw-r--r--numpy/core/src/multiarray/buffer.c23
-rw-r--r--numpy/lib/tests/test_stride_tricks.py29
2 files changed, 37 insertions, 15 deletions
diff --git a/numpy/core/src/multiarray/buffer.c b/numpy/core/src/multiarray/buffer.c
index d8ad80266..b729027ad 100644
--- a/numpy/core/src/multiarray/buffer.c
+++ b/numpy/core/src/multiarray/buffer.c
@@ -771,17 +771,6 @@ array_getbuffer(PyObject *obj, Py_buffer *view, int flags)
goto fail;
}
}
- /*
- * If a read-only buffer is requested on a read-write array, we return a
- * read-write buffer, which is dubious behavior. But that's why this call
- * is guarded by PyArray_ISWRITEABLE rather than (flags &
- * PyBUF_WRITEABLE).
- */
- if (PyArray_ISWRITEABLE(self)) {
- if (array_might_be_written(self) < 0) {
- goto fail;
- }
- }
if (view == NULL) {
PyErr_SetString(PyExc_ValueError, "NULL view in getbuffer");
@@ -797,7 +786,17 @@ array_getbuffer(PyObject *obj, Py_buffer *view, int flags)
view->buf = PyArray_DATA(self);
view->suboffsets = NULL;
view->itemsize = PyArray_ITEMSIZE(self);
- view->readonly = !PyArray_ISWRITEABLE(self);
+ /*
+ * If a read-only buffer is requested on a read-write array, we return a
+ * read-write buffer as per buffer protocol.
+ * We set a requested buffer to readonly also if the array will be readonly
+ * after a deprecation. This jumps the deprecation, but avoiding the
+ * warning is not convenient here. A warning is given if a writeable
+ * buffer is requested since `PyArray_FailUnlessWriteable` is called above
+ * (and clears the `NPY_ARRAY_WARN_ON_WRITE` flag).
+ */
+ view->readonly = (!PyArray_ISWRITEABLE(self) ||
+ PyArray_CHKFLAGS(self, NPY_ARRAY_WARN_ON_WRITE));
view->internal = NULL;
view->len = PyArray_NBYTES(self);
if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) {
diff --git a/numpy/lib/tests/test_stride_tricks.py b/numpy/lib/tests/test_stride_tricks.py
index 955fb914c..85fcceedc 100644
--- a/numpy/lib/tests/test_stride_tricks.py
+++ b/numpy/lib/tests/test_stride_tricks.py
@@ -417,17 +417,21 @@ def test_writeable():
# but the result of broadcast_arrays needs to be writeable, to
# preserve backwards compatibility
- for results in [broadcast_arrays(original),
- broadcast_arrays(0, original)]:
+ for is_broadcast, results in [(False, broadcast_arrays(original,)),
+ (True, broadcast_arrays(0, original))]:
for result in results:
# This will change to False in a future version
- if any([s == 0 for s in result.strides]):
+ if is_broadcast:
with assert_warns(FutureWarning):
assert_equal(result.flags.writeable, True)
with assert_warns(DeprecationWarning):
result[:] = 0
# Warning not emitted, writing to the array resets it
assert_equal(result.flags.writeable, True)
+ else:
+ # No warning:
+ assert_equal(result.flags.writeable, True)
+
for results in [broadcast_arrays(original),
broadcast_arrays(0, original)]:
for result in results:
@@ -451,6 +455,25 @@ def test_writeable():
assert_(first.shape == second.shape)
+def test_writeable_memoryview():
+ # The result of broadcast_arrays exports as a non-writeable memoryview
+ # because otherwise there is no good way to opt in to the new behaviour
+ # (i.e. you would need to set writeable to False explicitly).
+ # See gh-13929.
+ original = np.array([1, 2, 3])
+
+ for is_broadcast, results in [(False, broadcast_arrays(original,)),
+ (True, broadcast_arrays(0, original))]:
+ for result in results:
+ # This will change to False in a future version
+ if is_broadcast:
+ # memoryview(result, writable=True) will give warning but cannot
+ # be tested using the python API.
+ assert memoryview(result).readonly
+ else:
+ assert not memoryview(result).readonly
+
+
def test_reference_types():
input_array = np.array('a', dtype=object)
expected = np.array(['a'] * 3, dtype=object)