8000 API: Always use BufferError when dlpack export fails by seberg · Pull Request #22542 · numpy/numpy · GitHub
[go: up one dir, main page]

Skip to content

API: Always use BufferError when dlpack export fails #22542

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
API: Always use BufferError when dlpack export fails
See also data-apis/array-api#498.

I think we should just change this.  It is a niche feature and just
an error type change.

Closes gh-20742
  • Loading branch information
seberg committed Nov 7, 2022
commit 26342d7f117ed5759fefdaba7e60569e674f9a12
7 changes: 7 additions & 0 deletions doc/release/upcoming_changes/22542.compatibility.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
DLPack export raises ``BufferError``
------------------------------------
When an array buffer cannot be exported via DLPack a
``BufferError`` is now always raised where previously
``TypeError`` or ``RuntimeError`` was raised.
This allows falling back to the buffer protocol or
``__array_interface__`` when DLPack was tried first.
31 changes: 17 additions & 14 deletions numpy/core/src/multiarray/dlpack.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,14 +133,15 @@ array_dlpack(PyArrayObject *self,
}

if (stream != Py_None) {
PyErr_SetString(PyExc_RuntimeError, "NumPy only supports "
"stream=None.");
PyErr_SetString(PyExc_RuntimeError,
"NumPy only supports stream=None.");
return NULL;
}

if ( !(PyArray_FLAGS(self) & NPY_ARRAY_WRITEABLE)) {
PyErr_SetString(PyExc_TypeError, "NumPy currently only supports "
"dlpack for writeable arrays");
PyErr_SetString(PyExc_BufferError,
"Cannot export readonly array since signalling readonly "
"is unsupported by DLPack.");
return NULL;
}

Expand All @@ -152,7 +153,7 @@ array_dlpack(PyArrayObject *self,
if (!PyArray_IS_C_CONTIGUOUS(self) && PyArray_SIZE(self) != 1) {
for (int i = 0; i < ndim; ++i) {
if (shape[i] != 1 && strides[i] % itemsize != 0) {
PyErr_SetString(PyExc_RuntimeError,
PyErr_SetString(PyExc_BufferError,
"DLPack only supports strides which are a multiple of "
"itemsize.");
return NULL;
Expand All @@ -164,8 +165,8 @@ array_dlpack(PyArrayObject *self,
PyArray_Descr *dtype = PyArray_DESCR(self);

if (PyDataType_ISBYTESWAPPED(dtype)) {
PyErr_SetString(PyExc_TypeError, "DLPack only supports native "
"byte swapping.");
PyErr_SetString(PyExc_BufferError,
"DLPack only supports native byte order.");
return NULL;
}

Expand All @@ -182,8 +183,9 @@ array_dlpack(PyArrayObject *self,
// We can't be sure that the dtype is
// IEEE or padded.
if (itemsize > 8) {
PyErr_SetString(PyExc_TypeError, "DLPack only supports IEEE "
"floating point types without padding.");
PyErr_SetString(PyExc_BufferError,
"DLPack only supports IEEE floating point types "
"without padding (longdouble typically is not IEEE).");
return NULL;
}
managed_dtype.code = kDLFloat;
Expand All @@ -192,16 +194,17 @@ array_dlpack(PyArrayObject *self,
// We can't be sure that the dtype is
// IEEE or padded.
if (itemsize > 16) {
PyErr_SetString(PyExc_TypeError, "DLPack only supports IEEE "
"complex point types without padding.");
PyErr_SetString(PyExc_BufferError,
"DLPack only supports IEEE floating point types "
"without padding (longdouble typically is not IEEE).");
return NULL;
}
managed_dtype.code = kDLComplex;
}
else {
PyErr_SetString(PyExc_TypeError,
"DLPack only supports signed/unsigned integers, float "
"and complex dtypes.");
PyErr_SetString(PyExc_BufferError,
"DLPack only supports signed/unsigned integers, float "
"and complex dtypes.");
return NULL;
}

Expand Down
10 changes: 5 additions & 5 deletions numpy/core/tests/test_dlpack.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def test_strides_not_multiple_of_itemsize(self):
y = np.zeros((5,), dtype=dt)
z = y['int']

with pytest.raises(RuntimeError):
with pytest.raises(BufferError):
np.from_dlpack(z)

@pytest.mark.skipif(IS_PYPY, reason="PyPy can't get refcounts.")
Expand All @@ -53,14 +53,14 @@ def test_dtype_passthrough(self, dtype):
def test_invalid_dtype(self):
x = np.asarray(np.datetime64('2021-05-27'))

with pytest.raises(TypeError):
with pytest.raises(BufferError):
np.from_dlpack(x)

def test_invalid_byte_swapping(self):
dt = np.dtype('=i8').newbyteorder()
x = np.arange(5, dtype=dt)

with pytest.raises(TypeError):
wi 8140 th pytest.raises(BufferError):
np.from_dlpack(x)

def test_non_contiguous(self):
Expand Down Expand Up @@ -100,15 +100,15 @@ def dlpack_deleter_exception(self):
x = np.arange(5)
_ = x.__dlpack__()
raise RuntimeError

def test_dlpack_destructor_exception(self):
with pytest.raises(RuntimeError):
self.dlpack_deleter_exception()

def test_readonly(self):
x = np.arange(5)
x.flags.writeable = False
with pytest.raises(TypeError):
with pytest.raises(BufferError):
x.__dlpack__()

def test_ndim0(self):
Expand Down
0