Skip to content

Commit 146695a

Browse files
authored
fix: better exception and error handling for capsules (#3825)
* Make capsule errors better match python
1 parent 47079b9 commit 146695a

File tree

2 files changed

+21
-14
lines changed

2 files changed

+21
-14
lines changed

include/pybind11/numpy.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1288,7 +1288,8 @@ struct npy_format_descriptor<T, enable_if_t<array_info<T>::is_array>> {
12881288
static pybind11::dtype dtype() {
12891289
list shape;
12901290
array_info<T>::append_extents(shape);
1291-
return pybind11::dtype::from_args(pybind11::make_tuple(base_descr::dtype(), shape));
1291+
return pybind11::dtype::from_args(
1292+
pybind11::make_tuple(base_descr::dtype(), std::move(shape)));
12921293
}
12931294
};
12941295

include/pybind11/pytypes.h

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1574,42 +1574,50 @@ class capsule : public object {
15741574
void (*destructor)(PyObject *) = nullptr)
15751575
: object(PyCapsule_New(const_cast<void *>(value), name, destructor), stolen_t{}) {
15761576
if (!m_ptr) {
1577-
pybind11_fail("Could not allocate capsule object!");
1577+
throw error_already_set();
15781578
}
15791579
}
15801580

15811581
PYBIND11_DEPRECATED("Please pass a destructor that takes a void pointer as input")
15821582
capsule(const void *value, void (*destruct)(PyObject *))
15831583
: object(PyCapsule_New(const_cast<void *>(value), nullptr, destruct), stolen_t{}) {
15841584
if (!m_ptr) {
1585-
pybind11_fail("Could not allocate capsule object!");
1585+
throw error_already_set();
15861586
}
15871587
}
15881588

15891589
capsule(const void *value, void (*destructor)(void *)) {
15901590
m_ptr = PyCapsule_New(const_cast<void *>(value), nullptr, [](PyObject *o) {
15911591
auto destructor = reinterpret_cast<void (*)(void *)>(PyCapsule_GetContext(o));
1592+
if (destructor == nullptr) {
1593+
if (PyErr_Occurred()) {
1594+
throw error_already_set();
1595+
}
1596+
pybind11_fail("Unable to get capsule context");
1597+
}
15921598
void *ptr = PyCapsule_GetPointer(o, nullptr);
1599+
if (ptr == nullptr) {
1600+
throw error_already_set();
1601+
}
15931602
destructor(ptr);
15941603
});
15951604

1596-
if (!m_ptr) {
1597-
pybind11_fail("Could not allocate capsule object!");
1598-
}
1599-
1600-
if (PyCapsule_SetContext(m_ptr, (void *) destructor) != 0) {
1601-
pybind11_fail("Could not set capsule context!");
1605+
if (!m_ptr || PyCapsule_SetContext(m_ptr, (void *) destructor) != 0) {
1606+
throw error_already_set();
16021607
}
16031608
}
16041609

16051610
explicit capsule(void (*destructor)()) {
16061611
m_ptr = PyCapsule_New(reinterpret_cast<void *>(destructor), nullptr, [](PyObject *o) {
16071612
auto destructor = reinterpret_cast<void (*)()>(PyCapsule_GetPointer(o, nullptr));
1613+
if (destructor == nullptr) {
1614+
throw error_already_set();
1615+
}
16081616
destructor();
16091617
});
16101618

16111619
if (!m_ptr) {
1612-
pybind11_fail("Could not allocate capsule object!");
1620+
throw error_already_set();
16131621
}
16141622
}
16151623

@@ -1624,17 +1632,15 @@ class capsule : public object {
16241632
const auto *name = this->name();
16251633
T *result = static_cast<T *>(PyCapsule_GetPointer(m_ptr, name));
16261634
if (!result) {
1627-
PyErr_Clear();
1628-
pybind11_fail("Unable to extract capsule contents!");
1635+
throw error_already_set();
16291636
}
16301637
return result;
16311638
}
16321639

16331640
/// Replaces a capsule's pointer *without* calling the destructor on the existing one.
16341641
void set_pointer(const void *value) {
16351642
if (PyCapsule_SetPointer(m_ptr, const_cast<void *>(value)) != 0) {
1636-
PyErr_Clear();
1637-
pybind11_fail("Could not set capsule pointer");
1643+
throw error_already_set();
16381644
}
16391645
}
16401646

0 commit comments

Comments
 (0)