Skip to content

Commit 26342d7

Browse files
committed
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 numpygh-20742
1 parent fcafb65 commit 26342d7

File tree

3 files changed

+29
-19
lines changed

3 files changed

+29
-19
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
DLPack export raises ``BufferError``
2+
------------------------------------
3+
When an array buffer cannot be exported via DLPack a
4+
``BufferError`` is now always raised where previously
5+
``TypeError`` or ``RuntimeError`` was raised.
6+
This allows falling back to the buffer protocol or
7+
``__array_interface__`` when DLPack was tried first.

numpy/core/src/multiarray/dlpack.c

+17-14
Original file line numberDiff line numberDiff line change
@@ -133,14 +133,15 @@ array_dlpack(PyArrayObject *self,
133133
}
134134

135135
if (stream != Py_None) {
136-
PyErr_SetString(PyExc_RuntimeError, "NumPy only supports "
137-
"stream=None.");
136+
PyErr_SetString(PyExc_RuntimeError,
137+
"NumPy only supports stream=None.");
138138
return NULL;
139139
}
140140

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

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

166167
if (PyDataType_ISBYTESWAPPED(dtype)) {
167-
PyErr_SetString(PyExc_TypeError, "DLPack only supports native "
168-
"byte swapping.");
168+
PyErr_SetString(PyExc_BufferError,
169+
"DLPack only supports native byte order.");
169170
return NULL;
170171
}
171172

@@ -182,8 +183,9 @@ array_dlpack(PyArrayObject *self,
182183
// We can't be sure that the dtype is
183184
// IEEE or padded.
184185
if (itemsize > 8) {
185-
PyErr_SetString(PyExc_TypeError, "DLPack only supports IEEE "
186-
"floating point types without padding.");
186+
PyErr_SetString(PyExc_BufferError,
187+
"DLPack only supports IEEE floating point types "
188+
"without padding (longdouble typically is not IEEE).");
187189
return NULL;
188190
}
189191
managed_dtype.code = kDLFloat;
@@ -192,16 +194,17 @@ array_dlpack(PyArrayObject *self,
192194
// We can't be sure that the dtype is
193195
// IEEE or padded.
194196
if (itemsize > 16) {
195-
PyErr_SetString(PyExc_TypeError, "DLPack only supports IEEE "
196-
"complex point types without padding.");
197+
PyErr_SetString(PyExc_BufferError,
198+
"DLPack only supports IEEE floating point types "
199+
"without padding (longdouble typically is not IEEE).");
197200
return NULL;
198201
}
199202
managed_dtype.code = kDLComplex;
200203
}
201204
else {
202-
PyErr_SetString(PyExc_TypeError,
203-
"DLPack only supports signed/unsigned integers, float "
204-
"and complex dtypes.");
205+
PyErr_SetString(PyExc_BufferError,
206+
"DLPack only supports signed/unsigned integers, float "
207+
"and complex dtypes.");
205208
return NULL;
206209
}
207210

numpy/core/tests/test_dlpack.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def test_strides_not_multiple_of_itemsize(self):
2626
y = np.zeros((5,), dtype=dt)
2727
z = y['int']
2828

29-
with pytest.raises(RuntimeError):
29+
with pytest.raises(BufferError):
3030
np.from_dlpack(z)
3131

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

56-
with pytest.raises(TypeError):
56+
with pytest.raises(BufferError):
5757
np.from_dlpack(x)
5858

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

63-
with pytest.raises(TypeError):
63+
with pytest.raises(BufferError):
6464
np.from_dlpack(x)
6565

6666
def test_non_contiguous(self):
@@ -100,15 +100,15 @@ def dlpack_deleter_exception(self):
100100
x = np.arange(5)
101101
_ = x.__dlpack__()
102102
raise RuntimeError
103-
103+
104104
def test_dlpack_destructor_exception(self):
105105
with pytest.raises(RuntimeError):
106106
self.dlpack_deleter_exception()
107107

108108
def test_readonly(self):
109109
x = np.arange(5)
110110
x.flags.writeable = False
111-
with pytest.raises(TypeError):
111+
with pytest.raises(BufferError):
112112
x.__dlpack__()
113113

114114
def test_ndim0(self):

0 commit comments

Comments
 (0)