mirror of
https://github.com/pybind/pybind11.git
synced 2025-02-17 06:00:51 +00:00
Merge branch 'pybind:master' into master
This commit is contained in:
commit
812293c6a8
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@ -324,8 +324,8 @@ jobs:
|
|||||||
# Testing NVCC; forces sources to behave like .cu files
|
# Testing NVCC; forces sources to behave like .cu files
|
||||||
cuda:
|
cuda:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
name: "🐍 3.8 • CUDA 11.2 • Ubuntu 20.04"
|
name: "🐍 3.10 • CUDA 11.7 • Ubuntu 22.04"
|
||||||
container: nvidia/cuda:11.2.2-devel-ubuntu20.04
|
container: nvidia/cuda:11.7.0-devel-ubuntu22.04
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
@ -1545,7 +1545,7 @@ private:
|
|||||||
throw cast_error_unable_to_convert_call_arg(a.name, a.type);
|
throw cast_error_unable_to_convert_call_arg(a.name, a.type);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
m_kwargs[a.name] = a.value;
|
m_kwargs[a.name] = std::move(a.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void process(list & /*args_list*/, detail::kwargs_proxy kp) {
|
void process(list & /*args_list*/, detail::kwargs_proxy kp) {
|
||||||
|
@ -1578,6 +1578,22 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Nvidia's NVCC is broken between 11.4.0 and 11.8.0
|
||||||
|
// https://github.com/pybind/pybind11/issues/4193
|
||||||
|
#if defined(__CUDACC__) && (__CUDACC_VER_MAJOR__ == 11) && (__CUDACC_VER_MINOR__ >= 4) \
|
||||||
|
&& (__CUDACC_VER_MINOR__ <= 8)
|
||||||
|
template <typename T, typename... Extra>
|
||||||
|
class_ &def(const T &op, const Extra &...extra) {
|
||||||
|
op.execute(*this, extra...);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename... Extra>
|
||||||
|
class_ &def_cast(const T &op, const Extra &...extra) {
|
||||||
|
op.execute_cast(*this, extra...);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#else
|
||||||
template <detail::op_id id, detail::op_type ot, typename L, typename R, typename... Extra>
|
template <detail::op_id id, detail::op_type ot, typename L, typename R, typename... Extra>
|
||||||
class_ &def(const detail::op_<id, ot, L, R> &op, const Extra &...extra) {
|
class_ &def(const detail::op_<id, ot, L, R> &op, const Extra &...extra) {
|
||||||
op.execute(*this, extra...);
|
op.execute(*this, extra...);
|
||||||
@ -1589,6 +1605,7 @@ public:
|
|||||||
op.execute_cast(*this, extra...);
|
op.execute_cast(*this, extra...);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
template <typename... Args, typename... Extra>
|
template <typename... Args, typename... Extra>
|
||||||
class_ &def(const detail::initimpl::constructor<Args...> &init, const Extra &...extra) {
|
class_ &def(const detail::initimpl::constructor<Args...> &init, const Extra &...extra) {
|
||||||
|
@ -1829,18 +1829,18 @@ public:
|
|||||||
// guard if destructor called while err indicator is set
|
// guard if destructor called while err indicator is set
|
||||||
error_scope error_guard;
|
error_scope error_guard;
|
||||||
auto destructor = reinterpret_cast<void (*)(void *)>(PyCapsule_GetContext(o));
|
auto destructor = reinterpret_cast<void (*)(void *)>(PyCapsule_GetContext(o));
|
||||||
if (destructor == nullptr) {
|
if (PyErr_Occurred()) {
|
||||||
if (PyErr_Occurred()) {
|
throw error_already_set();
|
||||||
throw error_already_set();
|
|
||||||
}
|
|
||||||
pybind11_fail("Unable to get capsule context");
|
|
||||||
}
|
}
|
||||||
const char *name = get_name_in_error_scope(o);
|
const char *name = get_name_in_error_scope(o);
|
||||||
void *ptr = PyCapsule_GetPointer(o, name);
|
void *ptr = PyCapsule_GetPointer(o, name);
|
||||||
if (ptr == nullptr) {
|
if (ptr == nullptr) {
|
||||||
throw error_already_set();
|
throw error_already_set();
|
||||||
}
|
}
|
||||||
destructor(ptr);
|
|
||||||
|
if (destructor != nullptr) {
|
||||||
|
destructor(ptr);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!m_ptr || PyCapsule_SetContext(m_ptr, (void *) destructor) != 0) {
|
if (!m_ptr || PyCapsule_SetContext(m_ptr, (void *) destructor) != 0) {
|
||||||
|
@ -197,11 +197,40 @@ TEST_SUBMODULE(eigen, m) {
|
|||||||
|
|
||||||
// Return a block of a matrix (gives non-standard strides)
|
// Return a block of a matrix (gives non-standard strides)
|
||||||
m.def("block",
|
m.def("block",
|
||||||
[](const Eigen::Ref<const Eigen::MatrixXd> &x,
|
[m](const py::object &x_obj,
|
||||||
int start_row,
|
int start_row,
|
||||||
int start_col,
|
int start_col,
|
||||||
int block_rows,
|
int block_rows,
|
||||||
int block_cols) { return x.block(start_row, start_col, block_rows, block_cols); });
|
int block_cols) {
|
||||||
|
return m.attr("_block")(x_obj, x_obj, start_row, start_col, block_rows, block_cols);
|
||||||
|
});
|
||||||
|
|
||||||
|
m.def(
|
||||||
|
"_block",
|
||||||
|
[](const py::object &x_obj,
|
||||||
|
const Eigen::Ref<const Eigen::MatrixXd> &x,
|
||||||
|
int start_row,
|
||||||
|
int start_col,
|
||||||
|
int block_rows,
|
||||||
|
int block_cols) {
|
||||||
|
// See PR #4217 for background. This test is a bit over the top, but might be useful
|
||||||
|
// as a concrete example to point to when explaining the dangling reference trap.
|
||||||
|
auto i0 = py::make_tuple(0, 0);
|
||||||
|
auto x0_orig = x_obj[*i0].cast<double>();
|
||||||
|
if (x(0, 0) != x0_orig) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
"Something in the type_caster for Eigen::Ref is terribly wrong.");
|
||||||
|
}
|
||||||
|
double x0_mod = x0_orig + 1;
|
||||||
|
x_obj[*i0] = x0_mod;
|
||||||
|
auto copy_detected = (x(0, 0) != x0_mod);
|
||||||
|
x_obj[*i0] = x0_orig;
|
||||||
|
if (copy_detected) {
|
||||||
|
throw std::runtime_error("type_caster for Eigen::Ref made a copy.");
|
||||||
|
}
|
||||||
|
return x.block(start_row, start_col, block_rows, block_cols);
|
||||||
|
},
|
||||||
|
py::keep_alive<0, 1>());
|
||||||
|
|
||||||
// test_eigen_return_references, test_eigen_keepalive
|
// test_eigen_return_references, test_eigen_keepalive
|
||||||
// return value referencing/copying tests:
|
// return value referencing/copying tests:
|
||||||
|
@ -217,15 +217,24 @@ def test_negative_stride_from_python(msg):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_block_runtime_error_type_caster_eigen_ref_made_a_copy():
|
||||||
|
with pytest.raises(RuntimeError) as excinfo:
|
||||||
|
m.block(ref, 0, 0, 0, 0)
|
||||||
|
assert str(excinfo.value) == "type_caster for Eigen::Ref made a copy."
|
||||||
|
|
||||||
|
|
||||||
def test_nonunit_stride_to_python():
|
def test_nonunit_stride_to_python():
|
||||||
assert np.all(m.diagonal(ref) == ref.diagonal())
|
assert np.all(m.diagonal(ref) == ref.diagonal())
|
||||||
assert np.all(m.diagonal_1(ref) == ref.diagonal(1))
|
assert np.all(m.diagonal_1(ref) == ref.diagonal(1))
|
||||||
for i in range(-5, 7):
|
for i in range(-5, 7):
|
||||||
assert np.all(m.diagonal_n(ref, i) == ref.diagonal(i)), f"m.diagonal_n({i})"
|
assert np.all(m.diagonal_n(ref, i) == ref.diagonal(i)), f"m.diagonal_n({i})"
|
||||||
|
|
||||||
assert np.all(m.block(ref, 2, 1, 3, 3) == ref[2:5, 1:4])
|
# Must be order="F", otherwise the type_caster will make a copy and
|
||||||
assert np.all(m.block(ref, 1, 4, 4, 2) == ref[1:, 4:])
|
# m.block() will return a dangling reference (heap-use-after-free).
|
||||||
assert np.all(m.block(ref, 1, 4, 3, 2) == ref[1:4, 4:])
|
rof = np.asarray(ref, order="F")
|
||||||
|
assert np.all(m.block(rof, 2, 1, 3, 3) == rof[2:5, 1:4])
|
||||||
|
assert np.all(m.block(rof, 1, 4, 4, 2) == rof[1:, 4:])
|
||||||
|
assert np.all(m.block(rof, 1, 4, 3, 2) == rof[1:4, 4:])
|
||||||
|
|
||||||
|
|
||||||
def test_eigen_ref_to_python():
|
def test_eigen_ref_to_python():
|
||||||
|
@ -289,6 +289,12 @@ TEST_SUBMODULE(pytypes, m) {
|
|||||||
return capsule;
|
return capsule;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
m.def("return_capsule_with_explicit_nullptr_dtor", []() {
|
||||||
|
py::print("creating capsule with explicit nullptr dtor");
|
||||||
|
return py::capsule(reinterpret_cast<void *>(1234),
|
||||||
|
static_cast<void (*)(void *)>(nullptr)); // PR #4221
|
||||||
|
});
|
||||||
|
|
||||||
// test_accessors
|
// test_accessors
|
||||||
m.def("accessor_api", [](const py::object &o) {
|
m.def("accessor_api", [](const py::object &o) {
|
||||||
auto d = py::dict();
|
auto d = py::dict();
|
||||||
|
@ -299,6 +299,17 @@ def test_capsule(capture):
|
|||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
with capture:
|
||||||
|
a = m.return_capsule_with_explicit_nullptr_dtor()
|
||||||
|
del a
|
||||||
|
pytest.gc_collect()
|
||||||
|
assert (
|
||||||
|
capture.unordered
|
||||||
|
== """
|
||||||
|
creating capsule with explicit nullptr dtor
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_accessors():
|
def test_accessors():
|
||||||
class SubTestObject:
|
class SubTestObject:
|
||||||
|
Loading…
Reference in New Issue
Block a user