Skip to content

Commit

Permalink
PYBIND11_OBJECT_CVT should use namespace for error_already_set() (#3797)
Browse files Browse the repository at this point in the history
* PYBIND11_OBJECT_CVT should use namespace for error_already_set()

This change makes the macro usable outside of pybind11 namespace.

* added test for use of PYBIND11_OBJECT_CVT for classes in external to pybind11 namespaces

* Extended test_pytypes.cpp and test_pytest.py

The added test defines a dummy function that takes a custom-defined class external::float_
that uses PYBIND11_OBJECT_CVT

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* fixed issues pointed out by CI

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* fixed memory leak in default constructor

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
oleksandr-pavlyk and pre-commit-ci[bot] authored Mar 11, 2022
1 parent d75b353 commit 91a6e12
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 2 deletions.
4 changes: 2 additions & 2 deletions include/pybind11/pytypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -1038,12 +1038,12 @@ public:
Name(const object &o) \
: Parent(check_(o) ? o.inc_ref().ptr() : ConvertFun(o.ptr()), stolen_t{}) { \
if (!m_ptr) \
throw error_already_set(); \
throw ::pybind11::error_already_set(); \
} \
/* NOLINTNEXTLINE(google-explicit-constructor) */ \
Name(object &&o) : Parent(check_(o) ? o.release().ptr() : ConvertFun(o.ptr()), stolen_t{}) { \
if (!m_ptr) \
throw error_already_set(); \
throw ::pybind11::error_already_set(); \
}

#define PYBIND11_OBJECT_CVT_DEFAULT(Name, Parent, CheckFun, ConvertFun) \
Expand Down
33 changes: 33 additions & 0 deletions tests/test_pytypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,34 @@

#include <utility>

namespace external {
namespace detail {
bool check(PyObject *o) { return PyFloat_Check(o) != 0; }

PyObject *conv(PyObject *o) {
PyObject *ret = nullptr;
if (PyLong_Check(o)) {
double v = PyLong_AsDouble(o);
if (!(v == -1.0 && PyErr_Occurred())) {
ret = PyFloat_FromDouble(v);
}
} else {
PyErr_SetString(PyExc_TypeError, "Unexpected type");
}
return ret;
}

PyObject *default_constructed() { return PyFloat_FromDouble(0.0); }
} // namespace detail
class float_ : public py::object {
PYBIND11_OBJECT_CVT(float_, py::object, external::detail::check, external::detail::conv)

float_() : py::object(external::detail::default_constructed(), stolen_t{}) {}

double get_value() const { return PyFloat_AsDouble(this->ptr()); }
};
} // namespace external

TEST_SUBMODULE(pytypes, m) {
// test_bool
m.def("get_bool", [] { return py::bool_(false); });
Expand Down Expand Up @@ -545,4 +573,9 @@ TEST_SUBMODULE(pytypes, m) {
py::detail::accessor_policies::tuple_item::set(o, (py::size_t) 0, s0);
return o;
});

m.def("square_float_", [](const external::float_ &x) -> double {
double v = x.get_value();
return v * v;
});
}
5 changes: 5 additions & 0 deletions tests/test_pytypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -634,3 +634,8 @@ def test_implementation_details():
assert m.tuple_item_set_ssize_t() == ("emely", "edmond")
assert m.tuple_item_get_size_t(tup) == 93
assert m.tuple_item_set_size_t() == ("candy", "cat")


def test_external_float_():
r1 = m.square_float_(2.0)
assert r1 == 4.0

0 comments on commit 91a6e12

Please sign in to comment.