Compare commits

..

1 Commits

Author SHA1 Message Date
Ralf W. Grosse-Kunstleve
7047539be8
Merge 3670868825 into ad0d55a616 2025-02-17 16:47:32 -08:00
55 changed files with 460 additions and 172 deletions

View File

@ -836,6 +836,8 @@ protected:
holder_type holder; holder_type holder;
}; };
#ifdef PYBIND11_SMART_HOLDER_ENABLED
template <typename, typename SFINAE = void> template <typename, typename SFINAE = void>
struct copyable_holder_caster_shared_ptr_with_smart_holder_support_enabled : std::true_type {}; struct copyable_holder_caster_shared_ptr_with_smart_holder_support_enabled : std::true_type {};
@ -926,13 +928,13 @@ protected:
return; return;
} }
throw cast_error("Unable to cast from non-held to held instance (T& to Holder<T>) " throw cast_error("Unable to cast from non-held to held instance (T& to Holder<T>) "
#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) # if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
"(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for " "(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for "
"type information)"); "type information)");
#else # else
"of type '" "of type '"
+ type_id<std::shared_ptr<type>>() + "''"); + type_id<std::shared_ptr<type>>() + "''");
#endif # endif
} }
template <typename T = std::shared_ptr<type>, template <typename T = std::shared_ptr<type>,
@ -966,6 +968,8 @@ protected:
std::shared_ptr<type> shared_ptr_storage; std::shared_ptr<type> shared_ptr_storage;
}; };
#endif // PYBIND11_SMART_HOLDER_ENABLED
/// Specialize for the common std::shared_ptr, so users don't need to /// Specialize for the common std::shared_ptr, so users don't need to
template <typename T> template <typename T>
class type_caster<std::shared_ptr<T>> : public copyable_holder_caster<T, std::shared_ptr<T>> {}; class type_caster<std::shared_ptr<T>> : public copyable_holder_caster<T, std::shared_ptr<T>> {};
@ -986,6 +990,8 @@ struct move_only_holder_caster {
static constexpr auto name = type_caster_base<type>::name; static constexpr auto name = type_caster_base<type>::name;
}; };
#ifdef PYBIND11_SMART_HOLDER_ENABLED
template <typename, typename SFINAE = void> template <typename, typename SFINAE = void>
struct move_only_holder_caster_unique_ptr_with_smart_holder_support_enabled : std::true_type {}; struct move_only_holder_caster_unique_ptr_with_smart_holder_support_enabled : std::true_type {};
@ -1123,6 +1129,8 @@ public:
std::shared_ptr<std::unique_ptr<type, deleter>> unique_ptr_storage; std::shared_ptr<std::unique_ptr<type, deleter>> unique_ptr_storage;
}; };
#endif // PYBIND11_SMART_HOLDER_ENABLED
template <typename type, typename deleter> template <typename type, typename deleter>
class type_caster<std::unique_ptr<type, deleter>> class type_caster<std::unique_ptr<type, deleter>>
: public move_only_holder_caster<type, std::unique_ptr<type, deleter>> {}; : public move_only_holder_caster<type, std::unique_ptr<type, deleter>> {};
@ -1161,8 +1169,10 @@ struct is_holder_type
template <typename base, typename deleter> template <typename base, typename deleter>
struct is_holder_type<base, std::unique_ptr<base, deleter>> : std::true_type {}; struct is_holder_type<base, std::unique_ptr<base, deleter>> : std::true_type {};
#ifdef PYBIND11_SMART_HOLDER_ENABLED
template <typename base> template <typename base>
struct is_holder_type<base, smart_holder> : std::true_type {}; struct is_holder_type<base, smart_holder> : std::true_type {};
#endif
#ifdef PYBIND11_DISABLE_HANDLE_TYPE_NAME_DEFAULT_IMPLEMENTATION // See PR #4888 #ifdef PYBIND11_DISABLE_HANDLE_TYPE_NAME_DEFAULT_IMPLEMENTATION // See PR #4888

View File

@ -22,6 +22,8 @@
// Additional convention: 0xD = dev // Additional convention: 0xD = dev
#define PYBIND11_VERSION_HEX 0x030000D1 #define PYBIND11_VERSION_HEX 0x030000D1
#define PYBIND11_SMART_HOLDER_ENABLED // TODO(rwgk): purge
// Define some generic pybind11 helper macros for warning management. // Define some generic pybind11 helper macros for warning management.
// //
// Note that compiler-specific push/pop pairs are baked into the // Note that compiler-specific push/pop pairs are baked into the

View File

@ -198,6 +198,8 @@ void construct(value_and_holder &v_h, Alias<Class> &&result, bool) {
v_h.value_ptr() = new Alias<Class>(std::move(result)); v_h.value_ptr() = new Alias<Class>(std::move(result));
} }
#ifdef PYBIND11_SMART_HOLDER_ENABLED
template <typename T, typename D> template <typename T, typename D>
smart_holder init_smart_holder_from_unique_ptr(std::unique_ptr<T, D> &&unq_ptr, smart_holder init_smart_holder_from_unique_ptr(std::unique_ptr<T, D> &&unq_ptr,
bool void_cast_raw_ptr) { bool void_cast_raw_ptr) {
@ -266,6 +268,8 @@ void construct(value_and_holder &v_h,
v_h.type->init_instance(v_h.inst, &smhldr); v_h.type->init_instance(v_h.inst, &smhldr);
} }
#endif // PYBIND11_SMART_HOLDER_ENABLED
// Implementing class for py::init<...>() // Implementing class for py::init<...>()
template <typename... Args> template <typename... Args>
struct constructor { struct constructor {

View File

@ -511,6 +511,8 @@ inline PyThreadState *get_thread_state_unchecked() {
void keep_alive_impl(handle nurse, handle patient); void keep_alive_impl(handle nurse, handle patient);
inline PyObject *make_new_instance(PyTypeObject *type); inline PyObject *make_new_instance(PyTypeObject *type);
#ifdef PYBIND11_SMART_HOLDER_ENABLED
// PYBIND11:REMINDER: Needs refactoring of existing pybind11 code. // PYBIND11:REMINDER: Needs refactoring of existing pybind11 code.
inline bool deregister_instance(instance *self, void *valptr, const type_info *tinfo); inline bool deregister_instance(instance *self, void *valptr, const type_info *tinfo);
@ -866,6 +868,8 @@ struct load_helper : value_and_holder_helper {
PYBIND11_NAMESPACE_END(smart_holder_type_caster_support) PYBIND11_NAMESPACE_END(smart_holder_type_caster_support)
#endif // PYBIND11_SMART_HOLDER_ENABLED
class type_caster_generic { class type_caster_generic {
public: public:
PYBIND11_NOINLINE explicit type_caster_generic(const std::type_info &type_info) PYBIND11_NOINLINE explicit type_caster_generic(const std::type_info &type_info)
@ -970,6 +974,7 @@ public:
// Base methods for generic caster; there are overridden in copyable_holder_caster // Base methods for generic caster; there are overridden in copyable_holder_caster
void load_value(value_and_holder &&v_h) { void load_value(value_and_holder &&v_h) {
#ifdef PYBIND11_SMART_HOLDER_ENABLED
if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) { if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) {
smart_holder_type_caster_support::value_and_holder_helper v_h_helper; smart_holder_type_caster_support::value_and_holder_helper v_h_helper;
v_h_helper.loaded_v_h = v_h; v_h_helper.loaded_v_h = v_h;
@ -979,6 +984,7 @@ public:
return; return;
} }
} }
#endif
auto *&vptr = v_h.value_ptr(); auto *&vptr = v_h.value_ptr();
// Lazy allocation for unallocated values: // Lazy allocation for unallocated values:
if (vptr == nullptr) { if (vptr == nullptr) {

View File

@ -5,18 +5,29 @@
#pragma once #pragma once
#include "common.h" #include "common.h"
#include "struct_smart_holder.h" #include "internals.h"
#include <type_traits> #include <type_traits>
#ifdef PYBIND11_SMART_HOLDER_ENABLED
# include "struct_smart_holder.h"
#endif
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
#ifdef PYBIND11_SMART_HOLDER_ENABLED
using pybindit::memory::smart_holder; using pybindit::memory::smart_holder;
#endif
PYBIND11_NAMESPACE_BEGIN(detail) PYBIND11_NAMESPACE_BEGIN(detail)
#ifdef PYBIND11_SMART_HOLDER_ENABLED
template <typename H> template <typename H>
using is_smart_holder = std::is_same<H, smart_holder>; using is_smart_holder = std::is_same<H, smart_holder>;
#else
template <typename>
struct is_smart_holder : std::false_type {};
#endif
PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@ -7,7 +7,6 @@
#include "common.h" #include "common.h"
#include <cstddef> #include <cstddef>
#include <cstdint>
#include <typeinfo> #include <typeinfo>
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)

View File

@ -225,22 +225,19 @@ struct EigenProps {
= !show_c_contiguous && show_order && requires_col_major; = !show_c_contiguous && show_order && requires_col_major;
static constexpr auto descriptor static constexpr auto descriptor
= const_name("typing.Annotated[") = const_name("numpy.ndarray[") + npy_format_descriptor<Scalar>::name + const_name("[")
+ io_name("numpy.typing.ArrayLike, ", "numpy.typing.NDArray[")
+ npy_format_descriptor<Scalar>::name + io_name("", "]") + const_name(", \"[")
+ const_name<fixed_rows>(const_name<(size_t) rows>(), const_name("m")) + const_name(", ") + const_name<fixed_rows>(const_name<(size_t) rows>(), const_name("m")) + const_name(", ")
+ const_name<fixed_cols>(const_name<(size_t) cols>(), const_name("n")) + const_name<fixed_cols>(const_name<(size_t) cols>(), const_name("n")) + const_name("]")
+ const_name("]\"") +
// For a reference type (e.g. Ref<MatrixXd>) we have other constraints that might need to // For a reference type (e.g. Ref<MatrixXd>) we have other constraints that might need to
// be satisfied: writeable=True (for a mutable reference), and, depending on the map's // be satisfied: writeable=True (for a mutable reference), and, depending on the map's
// stride options, possibly f_contiguous or c_contiguous. We include them in the // stride options, possibly f_contiguous or c_contiguous. We include them in the
// descriptor output to provide some hint as to why a TypeError is occurring (otherwise // descriptor output to provide some hint as to why a TypeError is occurring (otherwise
// it can be confusing to see that a function accepts a // it can be confusing to see that a function accepts a 'numpy.ndarray[float64[3,2]]' and
// 'typing.Annotated[numpy.typing.NDArray[numpy.float64], "[3,2]"]' and an error message // an error message that you *gave* a numpy.ndarray of the right type and dimensions.
// that you *gave* a numpy.ndarray of the right type and dimensions. const_name<show_writeable>(", flags.writeable", "")
+ const_name<show_writeable>(", \"flags.writeable\"", "") + const_name<show_c_contiguous>(", flags.c_contiguous", "")
+ const_name<show_c_contiguous>(", \"flags.c_contiguous\"", "") + const_name<show_f_contiguous>(", flags.f_contiguous", "") + const_name("]");
+ const_name<show_f_contiguous>(", \"flags.f_contiguous\"", "") + const_name("]");
}; };
// Casts an Eigen type to numpy array. If given a base, the numpy array references the src data, // Casts an Eigen type to numpy array. If given a base, the numpy array references the src data,
@ -444,9 +441,7 @@ public:
} }
} }
// return_descr forces the use of NDArray instead of ArrayLike in args static constexpr auto name = props::descriptor;
// since Ref<...> args can only accept arrays.
static constexpr auto name = return_descr(props::descriptor);
// Explicitly delete these: support python -> C++ conversion on these (i.e. these can be return // Explicitly delete these: support python -> C++ conversion on these (i.e. these can be return
// types but not bound arguments). We still provide them (with an explicitly delete) so that // types but not bound arguments). We still provide them (with an explicitly delete) so that

View File

@ -124,16 +124,13 @@ struct eigen_tensor_helper<
template <typename Type, bool ShowDetails, bool NeedsWriteable = false> template <typename Type, bool ShowDetails, bool NeedsWriteable = false>
struct get_tensor_descriptor { struct get_tensor_descriptor {
static constexpr auto details static constexpr auto details
= const_name<NeedsWriteable>(", \"flags.writeable\"", "") + const_name = const_name<NeedsWriteable>(", flags.writeable", "") + const_name
< static_cast<int>(Type::Layout) < static_cast<int>(Type::Layout)
== static_cast<int>(Eigen::RowMajor) == static_cast<int>(Eigen::RowMajor) > (", flags.c_contiguous", ", flags.f_contiguous");
> (", \"flags.c_contiguous\"", ", \"flags.f_contiguous\"");
static constexpr auto value static constexpr auto value
= const_name("typing.Annotated[") = const_name("numpy.ndarray[") + npy_format_descriptor<typename Type::Scalar>::name
+ io_name("numpy.typing.ArrayLike, ", "numpy.typing.NDArray[") + const_name("[") + eigen_tensor_helper<remove_cv_t<Type>>::dimensions_descriptor
+ npy_format_descriptor<typename Type::Scalar>::name + io_name("", "]") + const_name("]") + const_name<ShowDetails>(details, const_name("")) + const_name("]");
+ const_name(", \"[") + eigen_tensor_helper<remove_cv_t<Type>>::dimensions_descriptor
+ const_name("]\"") + const_name<ShowDetails>(details, const_name("")) + const_name("]");
}; };
// When EIGEN_AVOID_STL_ARRAY is defined, Eigen::DSizes<T, 0> does not have the begin() member // When EIGEN_AVOID_STL_ARRAY is defined, Eigen::DSizes<T, 0> does not have the begin() member
@ -505,10 +502,7 @@ protected:
std::unique_ptr<MapType> value; std::unique_ptr<MapType> value;
public: public:
// return_descr forces the use of NDArray instead of ArrayLike since refs can only reference static constexpr auto name = get_tensor_descriptor<Type, true, needs_writeable>::value;
// arrays
static constexpr auto name
= return_descr(get_tensor_descriptor<Type, true, needs_writeable>::value);
explicit operator MapType *() { return value.get(); } explicit operator MapType *() { return value.get(); }
explicit operator MapType &() { return *value; } explicit operator MapType &() { return *value; }
explicit operator MapType &&() && { return std::move(*value); } explicit operator MapType &&() && { return std::move(*value); }

View File

@ -175,6 +175,7 @@ inline numpy_internals &get_numpy_internals() {
PYBIND11_NOINLINE module_ import_numpy_core_submodule(const char *submodule_name) { PYBIND11_NOINLINE module_ import_numpy_core_submodule(const char *submodule_name) {
module_ numpy = module_::import("numpy"); module_ numpy = module_::import("numpy");
str version_string = numpy.attr("__version__"); str version_string = numpy.attr("__version__");
module_ numpy_lib = module_::import("numpy.lib"); module_ numpy_lib = module_::import("numpy.lib");
object numpy_version = numpy_lib.attr("NumpyVersion")(version_string); object numpy_version = numpy_lib.attr("NumpyVersion")(version_string);
int major_version = numpy_version.attr("major").cast<int>(); int major_version = numpy_version.attr("major").cast<int>();
@ -2182,8 +2183,7 @@ vectorize_helper<Func, Return, Args...> vectorize_extractor(const Func &f, Retur
template <typename T, int Flags> template <typename T, int Flags>
struct handle_type_name<array_t<T, Flags>> { struct handle_type_name<array_t<T, Flags>> {
static constexpr auto name static constexpr auto name
= io_name("typing.Annotated[numpy.typing.ArrayLike, ", "numpy.typing.NDArray[") = const_name("numpy.ndarray[") + npy_format_descriptor<T>::name + const_name("]");
+ npy_format_descriptor<T>::name + const_name("]");
}; };
PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(detail)

View File

@ -1663,6 +1663,8 @@ PYBIND11_NAMESPACE_END(detail)
template <typename T, typename D, typename SFINAE = void> template <typename T, typename D, typename SFINAE = void>
struct property_cpp_function : detail::property_cpp_function_classic<T, D> {}; struct property_cpp_function : detail::property_cpp_function_classic<T, D> {};
#ifdef PYBIND11_SMART_HOLDER_ENABLED
PYBIND11_NAMESPACE_BEGIN(detail) PYBIND11_NAMESPACE_BEGIN(detail)
template <typename T, typename D, typename SFINAE = void> template <typename T, typename D, typename SFINAE = void>
@ -1840,7 +1842,9 @@ struct property_cpp_function<
detail::both_t_and_d_use_type_caster_base<T, typename D::element_type>>::value>> detail::both_t_and_d_use_type_caster_base<T, typename D::element_type>>::value>>
: detail::property_cpp_function_sh_unique_ptr_member<T, D> {}; : detail::property_cpp_function_sh_unique_ptr_member<T, D> {};
#if defined(PYBIND11_USE_SMART_HOLDER_AS_DEFAULT) #endif // PYBIND11_SMART_HOLDER_ENABLED
#if defined(PYBIND11_USE_SMART_HOLDER_AS_DEFAULT) && defined(PYBIND11_SMART_HOLDER_ENABLED)
// NOTE: THIS IS MEANT FOR STRESS-TESTING ONLY! // NOTE: THIS IS MEANT FOR STRESS-TESTING ONLY!
// As of PR #5257, for production use, there is no longer a strong reason to make // As of PR #5257, for production use, there is no longer a strong reason to make
// smart_holder the default holder: // smart_holder the default holder:
@ -1848,6 +1852,7 @@ struct property_cpp_function<
// Running the pybind11 unit tests with smart_holder as the default holder is to ensure // Running the pybind11 unit tests with smart_holder as the default holder is to ensure
// that `py::smart_holder` / `py::classh` is backward-compatible with all pre-existing // that `py::smart_holder` / `py::classh` is backward-compatible with all pre-existing
// functionality. // functionality.
# define PYBIND11_ACTUALLY_USING_SMART_HOLDER_AS_DEFAULT
template <typename> template <typename>
using default_holder_type = smart_holder; using default_holder_type = smart_holder;
#else #else
@ -1906,6 +1911,7 @@ public:
// A more fitting name would be uses_unique_ptr_holder. // A more fitting name would be uses_unique_ptr_holder.
record.default_holder = detail::is_instantiation<std::unique_ptr, holder_type>::value; record.default_holder = detail::is_instantiation<std::unique_ptr, holder_type>::value;
#ifdef PYBIND11_SMART_HOLDER_ENABLED
if (detail::is_instantiation<std::unique_ptr, holder_type>::value) { if (detail::is_instantiation<std::unique_ptr, holder_type>::value) {
record.holder_enum_v = detail::holder_enum_t::std_unique_ptr; record.holder_enum_v = detail::holder_enum_t::std_unique_ptr;
} else if (detail::is_instantiation<std::shared_ptr, holder_type>::value) { } else if (detail::is_instantiation<std::shared_ptr, holder_type>::value) {
@ -1915,6 +1921,7 @@ public:
} else { } else {
record.holder_enum_v = detail::holder_enum_t::custom_holder; record.holder_enum_v = detail::holder_enum_t::custom_holder;
} }
#endif
set_operator_new<type>(&record); set_operator_new<type>(&record);
@ -2256,6 +2263,8 @@ private:
init_holder(inst, v_h, (const holder_type *) holder_ptr, v_h.value_ptr<type>()); init_holder(inst, v_h, (const holder_type *) holder_ptr, v_h.value_ptr<type>());
} }
#ifdef PYBIND11_SMART_HOLDER_ENABLED
template <typename WrappedType> template <typename WrappedType>
static bool try_initialization_using_shared_from_this(holder_type *, WrappedType *, ...) { static bool try_initialization_using_shared_from_this(holder_type *, WrappedType *, ...) {
return false; return false;
@ -2315,6 +2324,8 @@ private:
v_h.set_holder_constructed(); v_h.set_holder_constructed();
} }
#endif // PYBIND11_SMART_HOLDER_ENABLED
// Deallocates an instance; via holder, if constructed; otherwise via operator delete. // Deallocates an instance; via holder, if constructed; otherwise via operator delete.
// NOTE: The Python error indicator needs to cleared BEFORE this function is called. // NOTE: The Python error indicator needs to cleared BEFORE this function is called.
// This is because we could be deallocating while cleaning up after a Python exception. // This is because we could be deallocating while cleaning up after a Python exception.
@ -2380,6 +2391,8 @@ private:
} }
}; };
#ifdef PYBIND11_SMART_HOLDER_ENABLED
// Supports easier switching between py::class_<T> and py::class_<T, py::smart_holder>: // Supports easier switching between py::class_<T> and py::class_<T, py::smart_holder>:
// users can simply replace the `_` in `class_` with `h` or vice versa. // users can simply replace the `_` in `class_` with `h` or vice versa.
template <typename type_, typename... options> template <typename type_, typename... options>
@ -2388,6 +2401,8 @@ public:
using class_<type_, smart_holder, options...>::class_; using class_<type_, smart_holder, options...>::class_;
}; };
#endif
/// Binds an existing constructor taking arguments Args... /// Binds an existing constructor taking arguments Args...
template <typename... Args> template <typename... Args>
detail::initimpl::constructor<Args...> init() { detail::initimpl::constructor<Args...> init() {

View File

@ -4,9 +4,13 @@
#pragma once #pragma once
#include "detail/common.h" #include "detail/internals.h"
#include "detail/using_smart_holder.h"
#include "detail/value_and_holder.h" #ifdef PYBIND11_SMART_HOLDER_ENABLED
# include "detail/common.h"
# include "detail/using_smart_holder.h"
# include "detail/value_and_holder.h"
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
@ -58,3 +62,5 @@ struct trampoline_self_life_support {
}; };
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
#endif // PYBIND11_SMART_HOLDER_ENABLED

View File

@ -109,7 +109,11 @@ TEST_SUBMODULE(class_, m) {
struct ToBeHeldByUniquePtr {}; struct ToBeHeldByUniquePtr {};
py::class_<ToBeHeldByUniquePtr, std::unique_ptr<ToBeHeldByUniquePtr>>(m, "ToBeHeldByUniquePtr") py::class_<ToBeHeldByUniquePtr, std::unique_ptr<ToBeHeldByUniquePtr>>(m, "ToBeHeldByUniquePtr")
.def(py::init<>()); .def(py::init<>());
#ifdef PYBIND11_SMART_HOLDER_ENABLED
m.def("pass_unique_ptr", [](std::unique_ptr<ToBeHeldByUniquePtr> &&) {}); m.def("pass_unique_ptr", [](std::unique_ptr<ToBeHeldByUniquePtr> &&) {});
#else
m.attr("pass_unique_ptr") = py::none();
#endif
// test_inheritance // test_inheritance
class Pet { class Pet {
@ -632,7 +636,7 @@ CHECK_NOALIAS(8);
CHECK_HOLDER(1, unique); CHECK_HOLDER(1, unique);
CHECK_HOLDER(2, unique); CHECK_HOLDER(2, unique);
CHECK_HOLDER(3, unique); CHECK_HOLDER(3, unique);
#ifndef PYBIND11_USE_SMART_HOLDER_AS_DEFAULT #ifndef PYBIND11_ACTUALLY_USING_SMART_HOLDER_AS_DEFAULT
CHECK_HOLDER(4, unique); CHECK_HOLDER(4, unique);
CHECK_HOLDER(5, unique); CHECK_HOLDER(5, unique);
#endif #endif

View File

@ -51,6 +51,8 @@ def test_instance_new():
def test_pass_unique_ptr(): def test_pass_unique_ptr():
obj = m.ToBeHeldByUniquePtr() obj = m.ToBeHeldByUniquePtr()
if m.pass_unique_ptr is None:
pytest.skip("smart_holder not available.")
with pytest.raises(RuntimeError) as execinfo: with pytest.raises(RuntimeError) as execinfo:
m.pass_unique_ptr(obj) m.pass_unique_ptr(obj)
assert str(execinfo.value).startswith( assert str(execinfo.value).startswith(

View File

@ -144,7 +144,24 @@ class LocalUnusualOpRef : UnusualOpRef {}; // To avoid clashing with `py::class_
py::object CastUnusualOpRefConstRef(const LocalUnusualOpRef &cref) { return py::cast(cref); } py::object CastUnusualOpRefConstRef(const LocalUnusualOpRef &cref) { return py::cast(cref); }
py::object CastUnusualOpRefMovable(LocalUnusualOpRef &&mvbl) { return py::cast(std::move(mvbl)); } py::object CastUnusualOpRefMovable(LocalUnusualOpRef &&mvbl) { return py::cast(std::move(mvbl)); }
} // namespace class_sh_basic
} // namespace pybind11_tests
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_basic::atyp)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_basic::uconsumer)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_basic::SharedPtrStash)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_basic::LocalUnusualOpRef)
namespace pybind11_tests {
namespace class_sh_basic {
TEST_SUBMODULE(class_sh_basic, m) { TEST_SUBMODULE(class_sh_basic, m) {
m.attr("defined_PYBIND11_SMART_HOLDER_ENABLED") =
#ifndef PYBIND11_SMART_HOLDER_ENABLED
false;
#else
true;
namespace py = pybind11; namespace py = pybind11;
py::classh<atyp>(m, "atyp").def(py::init<>()).def(py::init([](const std::string &mtxt) { py::classh<atyp>(m, "atyp").def(py::init<>()).def(py::init([](const std::string &mtxt) {
@ -243,6 +260,7 @@ TEST_SUBMODULE(class_sh_basic, m) {
[]() { return CastUnusualOpRefConstRef(LocalUnusualOpRef()); }); []() { return CastUnusualOpRefConstRef(LocalUnusualOpRef()); });
m.def("CallCastUnusualOpRefMovable", m.def("CallCastUnusualOpRefMovable",
[]() { return CastUnusualOpRefMovable(LocalUnusualOpRef()); }); []() { return CastUnusualOpRefMovable(LocalUnusualOpRef()); });
#endif // PYBIND11_SMART_HOLDER_ENABLED
} }
} // namespace class_sh_basic } // namespace class_sh_basic

View File

@ -7,6 +7,9 @@ import pytest
from pybind11_tests import class_sh_basic as m from pybind11_tests import class_sh_basic as m
if not m.defined_PYBIND11_SMART_HOLDER_ENABLED:
pytest.skip("smart_holder not available.", allow_module_level=True)
def test_atyp_constructors(): def test_atyp_constructors():
obj = m.atyp() obj = m.atyp()

View File

@ -28,7 +28,16 @@ int overloaded(std::unique_ptr<Atype<2>> at2, int i) { return at2->get() * 40 +
} // namespace class_sh_disowning } // namespace class_sh_disowning
} // namespace pybind11_tests } // namespace pybind11_tests
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_disowning::Atype<1>)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_disowning::Atype<2>)
TEST_SUBMODULE(class_sh_disowning, m) { TEST_SUBMODULE(class_sh_disowning, m) {
m.attr("defined_PYBIND11_SMART_HOLDER_ENABLED") =
#ifndef PYBIND11_SMART_HOLDER_ENABLED
false;
#else
true;
using namespace pybind11_tests::class_sh_disowning; using namespace pybind11_tests::class_sh_disowning;
py::classh<Atype<1>>(m, "Atype1").def(py::init<int>()).def("get", &Atype<1>::get); py::classh<Atype<1>>(m, "Atype1").def(py::init<int>()).def("get", &Atype<1>::get);
@ -40,4 +49,5 @@ TEST_SUBMODULE(class_sh_disowning, m) {
m.def("overloaded", (int (*)(std::unique_ptr<Atype<1>>, int)) &overloaded); m.def("overloaded", (int (*)(std::unique_ptr<Atype<1>>, int)) &overloaded);
m.def("overloaded", (int (*)(std::unique_ptr<Atype<2>>, int)) &overloaded); m.def("overloaded", (int (*)(std::unique_ptr<Atype<2>>, int)) &overloaded);
#endif // PYBIND11_SMART_HOLDER_ENABLED
} }

View File

@ -4,6 +4,9 @@ import pytest
from pybind11_tests import class_sh_disowning as m from pybind11_tests import class_sh_disowning as m
if not m.defined_PYBIND11_SMART_HOLDER_ENABLED:
pytest.skip("smart_holder not available.", allow_module_level=True)
def is_disowned(obj): def is_disowned(obj):
try: try:

View File

@ -48,7 +48,21 @@ int disown_base2(std::unique_ptr<Base2> b2) { return b2->j * 2000 + 2; }
} // namespace class_sh_disowning_mi } // namespace class_sh_disowning_mi
} // namespace pybind11_tests } // namespace pybind11_tests
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_disowning_mi::B)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_disowning_mi::C0)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_disowning_mi::C1)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_disowning_mi::D)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_disowning_mi::Base1)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_disowning_mi::Base2)
TEST_SUBMODULE(class_sh_disowning_mi, m) { TEST_SUBMODULE(class_sh_disowning_mi, m) {
m.attr("defined_PYBIND11_SMART_HOLDER_ENABLED") =
#ifndef PYBIND11_SMART_HOLDER_ENABLED
false;
#else
true;
using namespace pybind11_tests::class_sh_disowning_mi; using namespace pybind11_tests::class_sh_disowning_mi;
py::classh<B>(m, "B") py::classh<B>(m, "B")
@ -84,4 +98,5 @@ TEST_SUBMODULE(class_sh_disowning_mi, m) {
py::classh<Base2>(m, "Base2").def(py::init<int>()).def("bar", &Base2::bar); py::classh<Base2>(m, "Base2").def(py::init<int>()).def("bar", &Base2::bar);
m.def("disown_base1", disown_base1); m.def("disown_base1", disown_base1);
m.def("disown_base2", disown_base2); m.def("disown_base2", disown_base2);
#endif // PYBIND11_SMART_HOLDER_ENABLED
} }

View File

@ -5,6 +5,9 @@ import pytest
import env # noqa: F401 import env # noqa: F401
from pybind11_tests import class_sh_disowning_mi as m from pybind11_tests import class_sh_disowning_mi as m
if not m.defined_PYBIND11_SMART_HOLDER_ENABLED:
pytest.skip("smart_holder not available.", allow_module_level=True)
def test_diamond_inheritance(): def test_diamond_inheritance():
# Very similar to test_multiple_inheritance.py:test_diamond_inheritance. # Very similar to test_multiple_inheritance.py:test_diamond_inheritance.

View File

@ -72,7 +72,27 @@ struct sddwaa : std::default_delete<with_alias_alias> {};
} // namespace class_sh_factory_constructors } // namespace class_sh_factory_constructors
} // namespace pybind11_tests } // namespace pybind11_tests
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_factory_constructors::atyp_valu)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_factory_constructors::atyp_rref)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_factory_constructors::atyp_cref)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_factory_constructors::atyp_mref)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_factory_constructors::atyp_cptr)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_factory_constructors::atyp_mptr)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_factory_constructors::atyp_shmp)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_factory_constructors::atyp_shcp)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_factory_constructors::atyp_uqmp)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_factory_constructors::atyp_uqcp)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_factory_constructors::atyp_udmp)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_factory_constructors::atyp_udcp)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_factory_constructors::with_alias)
TEST_SUBMODULE(class_sh_factory_constructors, m) { TEST_SUBMODULE(class_sh_factory_constructors, m) {
m.attr("defined_PYBIND11_SMART_HOLDER_ENABLED") =
#ifndef PYBIND11_SMART_HOLDER_ENABLED
false;
#else
true;
using namespace pybind11_tests::class_sh_factory_constructors; using namespace pybind11_tests::class_sh_factory_constructors;
py::classh<atyp_valu>(m, "atyp_valu") py::classh<atyp_valu>(m, "atyp_valu")
@ -163,4 +183,5 @@ TEST_SUBMODULE(class_sh_factory_constructors, m) {
[](int, int, int, int, int) { [](int, int, int, int, int) {
return std::make_shared<with_alias>(); // Invalid alias factory. return std::make_shared<with_alias>(); // Invalid alias factory.
})); }));
#endif // PYBIND11_SMART_HOLDER_ENABLED
} }

View File

@ -4,6 +4,9 @@ import pytest
from pybind11_tests import class_sh_factory_constructors as m from pybind11_tests import class_sh_factory_constructors as m
if not m.defined_PYBIND11_SMART_HOLDER_ENABLED:
pytest.skip("smart_holder not available.", allow_module_level=True)
def test_atyp_factories(): def test_atyp_factories():
assert m.atyp_valu().get_mtxt() == "Valu" assert m.atyp_valu().get_mtxt() == "Valu"

View File

@ -59,7 +59,26 @@ inline int pass_cptr_base2(base2 const *b) { return b->id() + 22; }
inline int pass_cptr_drvd2(drvd2 const *d) { return d->id() + 23; } inline int pass_cptr_drvd2(drvd2 const *d) { return d->id() + 23; }
// clang-format on // clang-format on
} // namespace class_sh_inheritance
} // namespace pybind11_tests
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_inheritance::base)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_inheritance::drvd)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_inheritance::base1)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_inheritance::base2)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_inheritance::drvd2)
namespace pybind11_tests {
namespace class_sh_inheritance {
TEST_SUBMODULE(class_sh_inheritance, m) { TEST_SUBMODULE(class_sh_inheritance, m) {
m.attr("defined_PYBIND11_SMART_HOLDER_ENABLED") =
#ifndef PYBIND11_SMART_HOLDER_ENABLED
false;
#else
true;
py::classh<base>(m, "base"); py::classh<base>(m, "base");
py::classh<drvd, base>(m, "drvd"); py::classh<drvd, base>(m, "drvd");
@ -86,6 +105,7 @@ TEST_SUBMODULE(class_sh_inheritance, m) {
m.def("pass_cptr_base1", pass_cptr_base1); m.def("pass_cptr_base1", pass_cptr_base1);
m.def("pass_cptr_base2", pass_cptr_base2); m.def("pass_cptr_base2", pass_cptr_base2);
m.def("pass_cptr_drvd2", pass_cptr_drvd2); m.def("pass_cptr_drvd2", pass_cptr_drvd2);
#endif // PYBIND11_SMART_HOLDER_ENABLED
} }
} // namespace class_sh_inheritance } // namespace class_sh_inheritance

View File

@ -1,7 +1,12 @@
from __future__ import annotations from __future__ import annotations
import pytest
from pybind11_tests import class_sh_inheritance as m from pybind11_tests import class_sh_inheritance as m
if not m.defined_PYBIND11_SMART_HOLDER_ENABLED:
pytest.skip("smart_holder not available.", allow_module_level=True)
def test_rtrn_mptr_drvd_pass_cptr_base(): def test_rtrn_mptr_drvd_pass_cptr_base():
d = m.rtrn_mptr_drvd() d = m.rtrn_mptr_drvd()

View File

@ -35,7 +35,17 @@ struct Derived : Base1, Base0 {
} // namespace test_class_sh_mi_thunks } // namespace test_class_sh_mi_thunks
PYBIND11_SMART_HOLDER_TYPE_CASTERS(test_class_sh_mi_thunks::Base0)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(test_class_sh_mi_thunks::Base1)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(test_class_sh_mi_thunks::Derived)
TEST_SUBMODULE(class_sh_mi_thunks, m) { TEST_SUBMODULE(class_sh_mi_thunks, m) {
m.attr("defined_PYBIND11_SMART_HOLDER_ENABLED") =
#ifndef PYBIND11_SMART_HOLDER_ENABLED
false;
#else
true;
using namespace test_class_sh_mi_thunks; using namespace test_class_sh_mi_thunks;
m.def("ptrdiff_drvd_base0", []() { m.def("ptrdiff_drvd_base0", []() {
@ -93,4 +103,5 @@ TEST_SUBMODULE(class_sh_mi_thunks, m) {
} }
return obj_der->vec.size(); return obj_der->vec.size();
}); });
#endif // PYBIND11_SMART_HOLDER_ENABLED
} }

View File

@ -4,6 +4,9 @@ import pytest
from pybind11_tests import class_sh_mi_thunks as m from pybind11_tests import class_sh_mi_thunks as m
if not m.defined_PYBIND11_SMART_HOLDER_ENABLED:
pytest.skip("smart_holder not available.", allow_module_level=True)
def test_ptrdiff_drvd_base0(): def test_ptrdiff_drvd_base0():
ptrdiff = m.ptrdiff_drvd_base0() ptrdiff = m.ptrdiff_drvd_base0()

View File

@ -46,7 +46,24 @@ struct WithConstCharPtrMember {
} // namespace test_class_sh_property } // namespace test_class_sh_property
PYBIND11_TYPE_CASTER_BASE_HOLDER(test_class_sh_property::ClassicField,
std::unique_ptr<test_class_sh_property::ClassicField>)
PYBIND11_TYPE_CASTER_BASE_HOLDER(test_class_sh_property::ClassicOuter,
std::unique_ptr<test_class_sh_property::ClassicOuter>)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(test_class_sh_property::Field)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(test_class_sh_property::Outer)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(test_class_sh_property::WithCharArrayMember)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(test_class_sh_property::WithConstCharPtrMember)
TEST_SUBMODULE(class_sh_property, m) { TEST_SUBMODULE(class_sh_property, m) {
m.attr("defined_PYBIND11_SMART_HOLDER_ENABLED") =
#ifndef PYBIND11_SMART_HOLDER_ENABLED
false;
#else
true;
using namespace test_class_sh_property; using namespace test_class_sh_property;
py::class_<ClassicField, std::unique_ptr<ClassicField>>(m, "ClassicField") py::class_<ClassicField, std::unique_ptr<ClassicField>>(m, "ClassicField")
@ -92,4 +109,5 @@ TEST_SUBMODULE(class_sh_property, m) {
py::classh<WithConstCharPtrMember>(m, "WithConstCharPtrMember") py::classh<WithConstCharPtrMember>(m, "WithConstCharPtrMember")
.def(py::init<>()) .def(py::init<>())
.def_readonly("const_char_ptr_member", &WithConstCharPtrMember::const_char_ptr_member); .def_readonly("const_char_ptr_member", &WithConstCharPtrMember::const_char_ptr_member);
#endif // PYBIND11_SMART_HOLDER_ENABLED
} }

View File

@ -7,6 +7,9 @@ import pytest
import env # noqa: F401 import env # noqa: F401
from pybind11_tests import class_sh_property as m from pybind11_tests import class_sh_property as m
if not m.defined_PYBIND11_SMART_HOLDER_ENABLED:
pytest.skip("smart_holder not available.", allow_module_level=True)
@pytest.mark.skipif( @pytest.mark.skipif(
"env.PYPY or env.GRAALPY", reason="gc after `del field` is apparently deferred" "env.PYPY or env.GRAALPY", reason="gc after `del field` is apparently deferred"

View File

@ -46,7 +46,17 @@ public:
using namespace test_class_sh_property_non_owning; using namespace test_class_sh_property_non_owning;
PYBIND11_SMART_HOLDER_TYPE_CASTERS(CoreField)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(DataField)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(DataFieldsHolder)
TEST_SUBMODULE(class_sh_property_non_owning, m) { TEST_SUBMODULE(class_sh_property_non_owning, m) {
m.attr("defined_PYBIND11_SMART_HOLDER_ENABLED") =
#ifndef PYBIND11_SMART_HOLDER_ENABLED
false;
#else
true;
py::classh<CoreField>(m, "CoreField").def_readwrite("int_value", &CoreField::int_value); py::classh<CoreField>(m, "CoreField").def_readwrite("int_value", &CoreField::int_value);
py::classh<DataField>(m, "DataField") py::classh<DataField>(m, "DataField")
@ -61,4 +71,5 @@ TEST_SUBMODULE(class_sh_property_non_owning, m) {
py::classh<DataFieldsHolder>(m, "DataFieldsHolder") py::classh<DataFieldsHolder>(m, "DataFieldsHolder")
.def(py::init<std::size_t>()) .def(py::init<std::size_t>())
.def("vec_at", &DataFieldsHolder::vec_at, py::return_value_policy::reference_internal); .def("vec_at", &DataFieldsHolder::vec_at, py::return_value_policy::reference_internal);
#endif // PYBIND11_SMART_HOLDER_ENABLED
} }

View File

@ -4,6 +4,9 @@ import pytest
from pybind11_tests import class_sh_property_non_owning as m from pybind11_tests import class_sh_property_non_owning as m
if not m.defined_PYBIND11_SMART_HOLDER_ENABLED:
pytest.skip("smart_holder not available.", allow_module_level=True)
@pytest.mark.parametrize("persistent_holder", [True, False]) @pytest.mark.parametrize("persistent_holder", [True, False])
@pytest.mark.parametrize( @pytest.mark.parametrize(

View File

@ -41,8 +41,21 @@ struct Outer {
}; };
} // namespace } // namespace
} // namespace pybind11_tests
PYBIND11_TYPE_CASTER_BASE_HOLDER(pybind11_tests::FooShPtr,
std::shared_ptr<pybind11_tests::FooShPtr>)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::FooSmHld)
namespace pybind11_tests {
TEST_SUBMODULE(class_sh_shared_ptr_copy_move, m) { TEST_SUBMODULE(class_sh_shared_ptr_copy_move, m) {
m.attr("defined_PYBIND11_SMART_HOLDER_ENABLED") =
#ifndef PYBIND11_SMART_HOLDER_ENABLED
false;
#else
true;
namespace py = pybind11; namespace py = pybind11;
py::class_<FooShPtr, std::shared_ptr<FooShPtr>>(m, "FooShPtr") py::class_<FooShPtr, std::shared_ptr<FooShPtr>>(m, "FooShPtr")
@ -50,20 +63,20 @@ TEST_SUBMODULE(class_sh_shared_ptr_copy_move, m) {
py::classh<FooSmHld>(m, "FooSmHld").def("get_history", &FooSmHld::get_history); py::classh<FooSmHld>(m, "FooSmHld").def("get_history", &FooSmHld::get_history);
auto outer = py::class_<Outer>(m, "Outer").def(py::init()); auto outer = py::class_<Outer>(m, "Outer").def(py::init());
#define MAKE_PROP(PropTyp) \ # define MAKE_PROP(PropTyp) \
MAKE_PROP_FOO(ShPtr, PropTyp) \ MAKE_PROP_FOO(ShPtr, PropTyp) \
MAKE_PROP_FOO(SmHld, PropTyp) MAKE_PROP_FOO(SmHld, PropTyp)
#define MAKE_PROP_FOO(FooTyp, PropTyp) \ # define MAKE_PROP_FOO(FooTyp, PropTyp) \
.def_##PropTyp(#FooTyp "_" #PropTyp "_default", &Outer::FooTyp) \ .def_##PropTyp(#FooTyp "_" #PropTyp "_default", &Outer::FooTyp) \
.def_##PropTyp( \ .def_##PropTyp( \
#FooTyp "_" #PropTyp "_copy", &Outer::FooTyp, py::return_value_policy::copy) \ #FooTyp "_" #PropTyp "_copy", &Outer::FooTyp, py::return_value_policy::copy) \
.def_##PropTyp( \ .def_##PropTyp( \
#FooTyp "_" #PropTyp "_move", &Outer::FooTyp, py::return_value_policy::move) #FooTyp "_" #PropTyp "_move", &Outer::FooTyp, py::return_value_policy::move)
outer MAKE_PROP(readonly) MAKE_PROP(readwrite); outer MAKE_PROP(readonly) MAKE_PROP(readwrite);
#undef MAKE_PROP_FOO # undef MAKE_PROP_FOO
#define MAKE_PROP_FOO(FooTyp, PropTyp) \ # define MAKE_PROP_FOO(FooTyp, PropTyp) \
.def_##PropTyp(#FooTyp "_property_" #PropTyp "_default", &Outer::FooTyp) \ .def_##PropTyp(#FooTyp "_property_" #PropTyp "_default", &Outer::FooTyp) \
.def_property_##PropTyp(#FooTyp "_property_" #PropTyp "_copy", \ .def_property_##PropTyp(#FooTyp "_property_" #PropTyp "_copy", \
&Outer::get##FooTyp, \ &Outer::get##FooTyp, \
@ -72,8 +85,8 @@ TEST_SUBMODULE(class_sh_shared_ptr_copy_move, m) {
&Outer::get##FooTyp, \ &Outer::get##FooTyp, \
py::return_value_policy::move) py::return_value_policy::move)
outer MAKE_PROP(readonly); outer MAKE_PROP(readonly);
#undef MAKE_PROP_FOO # undef MAKE_PROP_FOO
#undef MAKE_PROP # undef MAKE_PROP
m.def("test_ShPtr_copy", []() { m.def("test_ShPtr_copy", []() {
auto o = std::make_shared<FooShPtr>("copy"); auto o = std::make_shared<FooShPtr>("copy");
@ -100,6 +113,7 @@ TEST_SUBMODULE(class_sh_shared_ptr_copy_move, m) {
l.append(std::move(o)); l.append(std::move(o));
return l; return l;
}); });
#endif // PYBIND11_SMART_HOLDER_ENABLED
} }
} // namespace pybind11_tests } // namespace pybind11_tests

View File

@ -1,7 +1,12 @@
from __future__ import annotations from __future__ import annotations
import pytest
from pybind11_tests import class_sh_shared_ptr_copy_move as m from pybind11_tests import class_sh_shared_ptr_copy_move as m
if not m.defined_PYBIND11_SMART_HOLDER_ENABLED:
pytest.skip("smart_holder not available.", allow_module_level=True)
def test_shptr_copy(): def test_shptr_copy():
txt = m.test_ShPtr_copy()[0].get_history() txt = m.test_ShPtr_copy()[0].get_history()

View File

@ -34,6 +34,7 @@ struct AbaseAlias : Abase<SerNo> {
} }
}; };
#ifdef PYBIND11_SMART_HOLDER_ENABLED
template <> template <>
struct AbaseAlias<1> : Abase<1>, py::trampoline_self_life_support { struct AbaseAlias<1> : Abase<1>, py::trampoline_self_life_support {
using Abase<1>::Abase; using Abase<1>::Abase;
@ -45,6 +46,7 @@ struct AbaseAlias<1> : Abase<1>, py::trampoline_self_life_support {
other_val); other_val);
} }
}; };
#endif // PYBIND11_SMART_HOLDER_ENABLED
template <int SerNo> template <int SerNo>
int AddInCppRawPtr(const Abase<SerNo> *obj, int other_val) { int AddInCppRawPtr(const Abase<SerNo> *obj, int other_val) {
@ -61,6 +63,7 @@ int AddInCppUniquePtr(std::unique_ptr<Abase<SerNo>> obj, int other_val) {
return obj->Add(other_val) * 100 + 13; return obj->Add(other_val) * 100 + 13;
} }
#ifdef PYBIND11_SMART_HOLDER_ENABLED
template <int SerNo> template <int SerNo>
void wrap(py::module_ m, const char *py_class_name) { void wrap(py::module_ m, const char *py_class_name) {
py::classh<Abase<SerNo>, AbaseAlias<SerNo>>(m, py_class_name) py::classh<Abase<SerNo>, AbaseAlias<SerNo>>(m, py_class_name)
@ -72,13 +75,24 @@ void wrap(py::module_ m, const char *py_class_name) {
m.def("AddInCppSharedPtr", AddInCppSharedPtr<SerNo>, py::arg("obj"), py::arg("other_val")); m.def("AddInCppSharedPtr", AddInCppSharedPtr<SerNo>, py::arg("obj"), py::arg("other_val"));
m.def("AddInCppUniquePtr", AddInCppUniquePtr<SerNo>, py::arg("obj"), py::arg("other_val")); m.def("AddInCppUniquePtr", AddInCppUniquePtr<SerNo>, py::arg("obj"), py::arg("other_val"));
} }
#endif
} // namespace class_sh_trampoline_basic } // namespace class_sh_trampoline_basic
} // namespace pybind11_tests } // namespace pybind11_tests
using namespace pybind11_tests::class_sh_trampoline_basic; using namespace pybind11_tests::class_sh_trampoline_basic;
PYBIND11_SMART_HOLDER_TYPE_CASTERS(Abase<0>)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(Abase<1>)
TEST_SUBMODULE(class_sh_trampoline_basic, m) { TEST_SUBMODULE(class_sh_trampoline_basic, m) {
m.attr("defined_PYBIND11_SMART_HOLDER_ENABLED") =
#ifndef PYBIND11_SMART_HOLDER_ENABLED
false;
#else
true;
wrap<0>(m, "Abase0"); wrap<0>(m, "Abase0");
wrap<1>(m, "Abase1"); wrap<1>(m, "Abase1");
#endif // PYBIND11_SMART_HOLDER_ENABLED
} }

View File

@ -4,6 +4,9 @@ import pytest
from pybind11_tests import class_sh_trampoline_basic as m from pybind11_tests import class_sh_trampoline_basic as m
if not m.defined_PYBIND11_SMART_HOLDER_ENABLED:
pytest.skip("smart_holder not available.", allow_module_level=True)
class PyDrvd0(m.Abase0): class PyDrvd0(m.Abase0):
def __init__(self, val): def __init__(self, val):

View File

@ -38,16 +38,26 @@ protected:
Big5() : history{"DefaultConstructor"} {} Big5() : history{"DefaultConstructor"} {}
}; };
#ifdef PYBIND11_SMART_HOLDER_ENABLED
struct Big5Trampoline : Big5, py::trampoline_self_life_support { struct Big5Trampoline : Big5, py::trampoline_self_life_support {
using Big5::Big5; using Big5::Big5;
}; };
#endif
} // namespace class_sh_trampoline_self_life_support } // namespace class_sh_trampoline_self_life_support
} // namespace pybind11_tests } // namespace pybind11_tests
using namespace pybind11_tests::class_sh_trampoline_self_life_support; using namespace pybind11_tests::class_sh_trampoline_self_life_support;
PYBIND11_SMART_HOLDER_TYPE_CASTERS(Big5)
TEST_SUBMODULE(class_sh_trampoline_self_life_support, m) { TEST_SUBMODULE(class_sh_trampoline_self_life_support, m) {
m.attr("defined_PYBIND11_SMART_HOLDER_ENABLED") =
#ifndef PYBIND11_SMART_HOLDER_ENABLED
false;
#else
true;
py::classh<Big5, Big5Trampoline>(m, "Big5") py::classh<Big5, Big5Trampoline>(m, "Big5")
.def(py::init<std::string>()) .def(py::init<std::string>())
.def_readonly("history", &Big5::history); .def_readonly("history", &Big5::history);
@ -84,4 +94,5 @@ TEST_SUBMODULE(class_sh_trampoline_self_life_support, m) {
py::object o1 = py::cast(std::move(obj)); py::object o1 = py::cast(std::move(obj));
return py::make_tuple(o1, o2); return py::make_tuple(o1, o2);
}); });
#endif // PYBIND11_SMART_HOLDER_ENABLED
} }

View File

@ -4,6 +4,9 @@ import pytest
import pybind11_tests.class_sh_trampoline_self_life_support as m import pybind11_tests.class_sh_trampoline_self_life_support as m
if not m.defined_PYBIND11_SMART_HOLDER_ENABLED:
pytest.skip("smart_holder not available.", allow_module_level=True)
class PyBig5(m.Big5): class PyBig5(m.Big5):
pass pass

View File

@ -71,9 +71,11 @@ struct SftSharedPtrStash {
} }
}; };
#ifdef PYBIND11_SMART_HOLDER_ENABLED
struct SftTrampoline : Sft, py::trampoline_self_life_support { struct SftTrampoline : Sft, py::trampoline_self_life_support {
using Sft::Sft; using Sft::Sft;
}; };
#endif
long use_count(const std::shared_ptr<Sft> &obj) { return obj.use_count(); } long use_count(const std::shared_ptr<Sft> &obj) { return obj.use_count(); }
@ -109,7 +111,16 @@ std::shared_ptr<Sft> pass_through_shd_ptr(const std::shared_ptr<Sft> &obj) { ret
using namespace pybind11_tests::class_sh_trampoline_shared_from_this; using namespace pybind11_tests::class_sh_trampoline_shared_from_this;
PYBIND11_SMART_HOLDER_TYPE_CASTERS(Sft)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(SftSharedPtrStash)
TEST_SUBMODULE(class_sh_trampoline_shared_from_this, m) { TEST_SUBMODULE(class_sh_trampoline_shared_from_this, m) {
m.attr("defined_PYBIND11_SMART_HOLDER_ENABLED") =
#ifndef PYBIND11_SMART_HOLDER_ENABLED
false;
#else
true;
py::classh<Sft, SftTrampoline>(m, "Sft") py::classh<Sft, SftTrampoline>(m, "Sft")
.def(py::init<const std::string &>()) .def(py::init<const std::string &>())
.def(py::init([](const std::string &history, int) { .def(py::init([](const std::string &history, int) {
@ -135,4 +146,5 @@ TEST_SUBMODULE(class_sh_trampoline_shared_from_this, m) {
m.def("make_pure_cpp_sft_unq_ptr", make_pure_cpp_sft_unq_ptr); m.def("make_pure_cpp_sft_unq_ptr", make_pure_cpp_sft_unq_ptr);
m.def("make_pure_cpp_sft_shd_ptr", make_pure_cpp_sft_shd_ptr); m.def("make_pure_cpp_sft_shd_ptr", make_pure_cpp_sft_shd_ptr);
m.def("pass_through_shd_ptr", pass_through_shd_ptr); m.def("pass_through_shd_ptr", pass_through_shd_ptr);
#endif // PYBIND11_SMART_HOLDER_ENABLED
} }

View File

@ -8,6 +8,9 @@ import pytest
import env import env
import pybind11_tests.class_sh_trampoline_shared_from_this as m import pybind11_tests.class_sh_trampoline_shared_from_this as m
if not m.defined_PYBIND11_SMART_HOLDER_ENABLED:
pytest.skip("smart_holder not available.", allow_module_level=True)
class PySft(m.Sft): class PySft(m.Sft):
pass pass

View File

@ -57,7 +57,18 @@ struct SpGoAwayTester {
using namespace pybind11_tests::class_sh_trampoline_shared_ptr_cpp_arg; using namespace pybind11_tests::class_sh_trampoline_shared_ptr_cpp_arg;
PYBIND11_SMART_HOLDER_TYPE_CASTERS(SpBase)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(SpBaseTester)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(SpGoAway)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(SpGoAwayTester)
TEST_SUBMODULE(class_sh_trampoline_shared_ptr_cpp_arg, m) { TEST_SUBMODULE(class_sh_trampoline_shared_ptr_cpp_arg, m) {
m.attr("defined_PYBIND11_SMART_HOLDER_ENABLED") =
#ifndef PYBIND11_SMART_HOLDER_ENABLED
false;
#else
true;
// For testing whether a python subclass of a C++ object dies when the // For testing whether a python subclass of a C++ object dies when the
// last python reference is lost // last python reference is lost
@ -90,4 +101,5 @@ TEST_SUBMODULE(class_sh_trampoline_shared_ptr_cpp_arg, m) {
py::classh<SpGoAwayTester>(m, "SpGoAwayTester") py::classh<SpGoAwayTester>(m, "SpGoAwayTester")
.def(py::init<>()) .def(py::init<>())
.def_readwrite("obj", &SpGoAwayTester::m_obj); .def_readwrite("obj", &SpGoAwayTester::m_obj);
#endif // PYBIND11_SMART_HOLDER_ENABLED
} }

View File

@ -5,6 +5,9 @@ import pytest
import env # noqa: F401 import env # noqa: F401
import pybind11_tests.class_sh_trampoline_shared_ptr_cpp_arg as m import pybind11_tests.class_sh_trampoline_shared_ptr_cpp_arg as m
if not m.defined_PYBIND11_SMART_HOLDER_ENABLED:
pytest.skip("smart_holder not available.", allow_module_level=True)
@pytest.mark.skipif("env.GRAALPY", reason="Cannot reliably trigger GC") @pytest.mark.skipif("env.GRAALPY", reason="Cannot reliably trigger GC")
def test_shared_ptr_cpp_arg(): def test_shared_ptr_cpp_arg():

View File

@ -34,9 +34,12 @@ private:
} // namespace class_sh_trampoline_unique_ptr } // namespace class_sh_trampoline_unique_ptr
} // namespace pybind11_tests } // namespace pybind11_tests
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_trampoline_unique_ptr::Class)
namespace pybind11_tests { namespace pybind11_tests {
namespace class_sh_trampoline_unique_ptr { namespace class_sh_trampoline_unique_ptr {
#ifdef PYBIND11_SMART_HOLDER_ENABLED
class PyClass : public Class, public py::trampoline_self_life_support { class PyClass : public Class, public py::trampoline_self_life_support {
public: public:
std::unique_ptr<Class> clone() const override { std::unique_ptr<Class> clone() const override {
@ -45,11 +48,18 @@ public:
int foo() const override { PYBIND11_OVERRIDE_PURE(int, Class, foo); } int foo() const override { PYBIND11_OVERRIDE_PURE(int, Class, foo); }
}; };
#endif
} // namespace class_sh_trampoline_unique_ptr } // namespace class_sh_trampoline_unique_ptr
} // namespace pybind11_tests } // namespace pybind11_tests
TEST_SUBMODULE(class_sh_trampoline_unique_ptr, m) { TEST_SUBMODULE(class_sh_trampoline_unique_ptr, m) {
m.attr("defined_PYBIND11_SMART_HOLDER_ENABLED") =
#ifndef PYBIND11_SMART_HOLDER_ENABLED
false;
#else
true;
using namespace pybind11_tests::class_sh_trampoline_unique_ptr; using namespace pybind11_tests::class_sh_trampoline_unique_ptr;
py::classh<Class, PyClass>(m, "Class") py::classh<Class, PyClass>(m, "Class")
@ -61,4 +71,5 @@ TEST_SUBMODULE(class_sh_trampoline_unique_ptr, m) {
m.def("clone", [](const Class &obj) { return obj.clone(); }); m.def("clone", [](const Class &obj) { return obj.clone(); });
m.def("clone_and_foo", [](const Class &obj) { return obj.clone()->foo(); }); m.def("clone_and_foo", [](const Class &obj) { return obj.clone()->foo(); });
#endif // PYBIND11_SMART_HOLDER_ENABLED
} }

View File

@ -1,7 +1,12 @@
from __future__ import annotations from __future__ import annotations
import pytest
import pybind11_tests.class_sh_trampoline_unique_ptr as m import pybind11_tests.class_sh_trampoline_unique_ptr as m
if not m.defined_PYBIND11_SMART_HOLDER_ENABLED:
pytest.skip("smart_holder not available.", allow_module_level=True)
class MyClass(m.Class): class MyClass(m.Class):
def foo(self): def foo(self):

View File

@ -22,10 +22,25 @@ private:
explicit Pet(const std::string &name) : name(name) {} explicit Pet(const std::string &name) : name(name) {}
}; };
} // namespace class_sh_unique_ptr_custom_deleter
} // namespace pybind11_tests
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_unique_ptr_custom_deleter::Pet)
namespace pybind11_tests {
namespace class_sh_unique_ptr_custom_deleter {
TEST_SUBMODULE(class_sh_unique_ptr_custom_deleter, m) { TEST_SUBMODULE(class_sh_unique_ptr_custom_deleter, m) {
m.attr("defined_PYBIND11_SMART_HOLDER_ENABLED") =
#ifndef PYBIND11_SMART_HOLDER_ENABLED
false;
#else
true;
py::classh<Pet>(m, "Pet").def_readwrite("name", &Pet::name); py::classh<Pet>(m, "Pet").def_readwrite("name", &Pet::name);
m.def("create", &Pet::New); m.def("create", &Pet::New);
#endif // PYBIND11_SMART_HOLDER_ENABLED
} }
} // namespace class_sh_unique_ptr_custom_deleter } // namespace class_sh_unique_ptr_custom_deleter

View File

@ -1,7 +1,12 @@
from __future__ import annotations from __future__ import annotations
import pytest
from pybind11_tests import class_sh_unique_ptr_custom_deleter as m from pybind11_tests import class_sh_unique_ptr_custom_deleter as m
if not m.defined_PYBIND11_SMART_HOLDER_ENABLED:
pytest.skip("smart_holder not available.", allow_module_level=True)
def test_create(): def test_create():
pet = m.create("abc") pet = m.create("abc")

View File

@ -36,7 +36,21 @@ private:
std::unique_ptr<pointee> ptr_; std::unique_ptr<pointee> ptr_;
}; };
} // namespace class_sh_unique_ptr_member
} // namespace pybind11_tests
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_unique_ptr_member::pointee)
namespace pybind11_tests {
namespace class_sh_unique_ptr_member {
TEST_SUBMODULE(class_sh_unique_ptr_member, m) { TEST_SUBMODULE(class_sh_unique_ptr_member, m) {
m.attr("defined_PYBIND11_SMART_HOLDER_ENABLED") =
#ifndef PYBIND11_SMART_HOLDER_ENABLED
false;
#else
true;
py::classh<pointee>(m, "pointee").def(py::init<>()).def("get_int", &pointee::get_int); py::classh<pointee>(m, "pointee").def(py::init<>()).def("get_int", &pointee::get_int);
m.def("make_unique_pointee", make_unique_pointee); m.def("make_unique_pointee", make_unique_pointee);
@ -46,6 +60,7 @@ TEST_SUBMODULE(class_sh_unique_ptr_member, m) {
.def("is_owner", &ptr_owner::is_owner) .def("is_owner", &ptr_owner::is_owner)
.def("give_up_ownership_via_unique_ptr", &ptr_owner::give_up_ownership_via_unique_ptr) .def("give_up_ownership_via_unique_ptr", &ptr_owner::give_up_ownership_via_unique_ptr)
.def("give_up_ownership_via_shared_ptr", &ptr_owner::give_up_ownership_via_shared_ptr); .def("give_up_ownership_via_shared_ptr", &ptr_owner::give_up_ownership_via_shared_ptr);
#endif // PYBIND11_SMART_HOLDER_ENABLED
} }
} // namespace class_sh_unique_ptr_member } // namespace class_sh_unique_ptr_member

View File

@ -4,6 +4,9 @@ import pytest
from pybind11_tests import class_sh_unique_ptr_member as m from pybind11_tests import class_sh_unique_ptr_member as m
if not m.defined_PYBIND11_SMART_HOLDER_ENABLED:
pytest.skip("smart_holder not available.", allow_module_level=True)
def test_make_unique_pointee(): def test_make_unique_pointee():
obj = m.make_unique_pointee() obj = m.make_unique_pointee()

View File

@ -31,6 +31,8 @@ int get_from_cpp_plainc_ptr(const Base *b) { return b->get() + 4000; }
int get_from_cpp_unique_ptr(std::unique_ptr<Base> b) { return b->get() + 5000; } int get_from_cpp_unique_ptr(std::unique_ptr<Base> b) { return b->get() + 5000; }
#ifdef PYBIND11_SMART_HOLDER_ENABLED
struct BaseVirtualOverrider : Base, py::trampoline_self_life_support { struct BaseVirtualOverrider : Base, py::trampoline_self_life_support {
using Base::Base; using Base::Base;
@ -43,12 +45,24 @@ struct CppDerivedVirtualOverrider : CppDerived, py::trampoline_self_life_support
int get() const override { PYBIND11_OVERRIDE(int, CppDerived, get); } int get() const override { PYBIND11_OVERRIDE(int, CppDerived, get); }
}; };
#endif
} // namespace class_sh_virtual_py_cpp_mix } // namespace class_sh_virtual_py_cpp_mix
} // namespace pybind11_tests } // namespace pybind11_tests
using namespace pybind11_tests::class_sh_virtual_py_cpp_mix; using namespace pybind11_tests::class_sh_virtual_py_cpp_mix;
PYBIND11_SMART_HOLDER_TYPE_CASTERS(Base)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(CppDerivedPlain)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(CppDerived)
TEST_SUBMODULE(class_sh_virtual_py_cpp_mix, m) { TEST_SUBMODULE(class_sh_virtual_py_cpp_mix, m) {
m.attr("defined_PYBIND11_SMART_HOLDER_ENABLED") =
#ifndef PYBIND11_SMART_HOLDER_ENABLED
false;
#else
true;
py::classh<Base, BaseVirtualOverrider>(m, "Base").def(py::init<>()).def("get", &Base::get); py::classh<Base, BaseVirtualOverrider>(m, "Base").def(py::init<>()).def("get", &Base::get);
py::classh<CppDerivedPlain, Base>(m, "CppDerivedPlain").def(py::init<>()); py::classh<CppDerivedPlain, Base>(m, "CppDerivedPlain").def(py::init<>());
@ -57,4 +71,5 @@ TEST_SUBMODULE(class_sh_virtual_py_cpp_mix, m) {
m.def("get_from_cpp_plainc_ptr", get_from_cpp_plainc_ptr, py::arg("b")); m.def("get_from_cpp_plainc_ptr", get_from_cpp_plainc_ptr, py::arg("b"));
m.def("get_from_cpp_unique_ptr", get_from_cpp_unique_ptr, py::arg("b")); m.def("get_from_cpp_unique_ptr", get_from_cpp_unique_ptr, py::arg("b"));
#endif // PYBIND11_SMART_HOLDER_ENABLED
} }

View File

@ -4,6 +4,9 @@ import pytest
from pybind11_tests import class_sh_virtual_py_cpp_mix as m from pybind11_tests import class_sh_virtual_py_cpp_mix as m
if not m.defined_PYBIND11_SMART_HOLDER_ENABLED:
pytest.skip("smart_holder not available.", allow_module_level=True)
class PyBase(m.Base): # Avoiding name PyDerived, for more systematic naming. class PyBase(m.Base): # Avoiding name PyDerived, for more systematic naming.
def __init__(self): def __init__(self):

View File

@ -440,8 +440,4 @@ TEST_SUBMODULE(eigen_matrix, m) {
py::module_::import("numpy").attr("ones")(10); py::module_::import("numpy").attr("ones")(10);
return v[0](5); return v[0](5);
}); });
m.def("round_trip_vector", [](const Eigen::VectorXf &x) -> Eigen::VectorXf { return x; });
m.def("round_trip_dense", [](const DenseMatrixR &m) -> DenseMatrixR { return m; });
m.def("round_trip_dense_ref",
[](const Eigen::Ref<DenseMatrixR> &m) -> Eigen::Ref<DenseMatrixR> { return m; });
} }

View File

@ -95,20 +95,19 @@ def test_mutator_descriptors():
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.fixed_mutator_r(zc) m.fixed_mutator_r(zc)
assert ( assert (
'(arg0: typing.Annotated[numpy.typing.NDArray[numpy.float32], "[5, 6]",' "(arg0: numpy.ndarray[numpy.float32[5, 6],"
' "flags.writeable", "flags.c_contiguous"]) -> None' in str(excinfo.value) " flags.writeable, flags.c_contiguous]) -> None" in str(excinfo.value)
) )
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.fixed_mutator_c(zr) m.fixed_mutator_c(zr)
assert ( assert (
'(arg0: typing.Annotated[numpy.typing.NDArray[numpy.float32], "[5, 6]",' "(arg0: numpy.ndarray[numpy.float32[5, 6],"
' "flags.writeable", "flags.f_contiguous"]) -> None' in str(excinfo.value) " flags.writeable, flags.f_contiguous]) -> None" in str(excinfo.value)
) )
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.fixed_mutator_a(np.array([[1, 2], [3, 4]], dtype="float32")) m.fixed_mutator_a(np.array([[1, 2], [3, 4]], dtype="float32"))
assert ( assert "(arg0: numpy.ndarray[numpy.float32[5, 6], flags.writeable]) -> None" in str(
'(arg0: typing.Annotated[numpy.typing.NDArray[numpy.float32], "[5, 6]", "flags.writeable"]) -> None' excinfo.value
in str(excinfo.value)
) )
zr.flags.writeable = False zr.flags.writeable = False
with pytest.raises(TypeError): with pytest.raises(TypeError):
@ -202,7 +201,7 @@ def test_negative_stride_from_python(msg):
msg(excinfo.value) msg(excinfo.value)
== """ == """
double_threer(): incompatible function arguments. The following argument types are supported: double_threer(): incompatible function arguments. The following argument types are supported:
1. (arg0: typing.Annotated[numpy.typing.NDArray[numpy.float32], "[1, 3]", "flags.writeable"]) -> None 1. (arg0: numpy.ndarray[numpy.float32[1, 3], flags.writeable]) -> None
Invoked with: """ Invoked with: """
+ repr(np.array([5.0, 4.0, 3.0], dtype="float32")) + repr(np.array([5.0, 4.0, 3.0], dtype="float32"))
@ -214,7 +213,7 @@ def test_negative_stride_from_python(msg):
msg(excinfo.value) msg(excinfo.value)
== """ == """
double_threec(): incompatible function arguments. The following argument types are supported: double_threec(): incompatible function arguments. The following argument types are supported:
1. (arg0: typing.Annotated[numpy.typing.NDArray[numpy.float32], "[3, 1]", "flags.writeable"]) -> None 1. (arg0: numpy.ndarray[numpy.float32[3, 1], flags.writeable]) -> None
Invoked with: """ Invoked with: """
+ repr(np.array([7.0, 4.0, 1.0], dtype="float32")) + repr(np.array([7.0, 4.0, 1.0], dtype="float32"))
@ -635,16 +634,16 @@ def test_nocopy_wrapper():
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.get_elem_nocopy(int_matrix_colmajor) m.get_elem_nocopy(int_matrix_colmajor)
assert "get_elem_nocopy(): incompatible function arguments." in str(excinfo.value) assert "get_elem_nocopy(): incompatible function arguments." in str(excinfo.value)
assert ', "flags.f_contiguous"' in str(excinfo.value) assert ", flags.f_contiguous" in str(excinfo.value)
assert m.get_elem_nocopy(dbl_matrix_colmajor) == 8 assert m.get_elem_nocopy(dbl_matrix_colmajor) == 8
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.get_elem_nocopy(int_matrix_rowmajor) m.get_elem_nocopy(int_matrix_rowmajor)
assert "get_elem_nocopy(): incompatible function arguments." in str(excinfo.value) assert "get_elem_nocopy(): incompatible function arguments." in str(excinfo.value)
assert ', "flags.f_contiguous"' in str(excinfo.value) assert ", flags.f_contiguous" in str(excinfo.value)
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.get_elem_nocopy(dbl_matrix_rowmajor) m.get_elem_nocopy(dbl_matrix_rowmajor)
assert "get_elem_nocopy(): incompatible function arguments." in str(excinfo.value) assert "get_elem_nocopy(): incompatible function arguments." in str(excinfo.value)
assert ', "flags.f_contiguous"' in str(excinfo.value) assert ", flags.f_contiguous" in str(excinfo.value)
# For the row-major test, we take a long matrix in row-major, so only the third is allowed: # For the row-major test, we take a long matrix in row-major, so only the third is allowed:
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
@ -652,20 +651,20 @@ def test_nocopy_wrapper():
assert "get_elem_rm_nocopy(): incompatible function arguments." in str( assert "get_elem_rm_nocopy(): incompatible function arguments." in str(
excinfo.value excinfo.value
) )
assert ', "flags.c_contiguous"' in str(excinfo.value) assert ", flags.c_contiguous" in str(excinfo.value)
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.get_elem_rm_nocopy(dbl_matrix_colmajor) m.get_elem_rm_nocopy(dbl_matrix_colmajor)
assert "get_elem_rm_nocopy(): incompatible function arguments." in str( assert "get_elem_rm_nocopy(): incompatible function arguments." in str(
excinfo.value excinfo.value
) )
assert ', "flags.c_contiguous"' in str(excinfo.value) assert ", flags.c_contiguous" in str(excinfo.value)
assert m.get_elem_rm_nocopy(int_matrix_rowmajor) == 8 assert m.get_elem_rm_nocopy(int_matrix_rowmajor) == 8
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.get_elem_rm_nocopy(dbl_matrix_rowmajor) m.get_elem_rm_nocopy(dbl_matrix_rowmajor)
assert "get_elem_rm_nocopy(): incompatible function arguments." in str( assert "get_elem_rm_nocopy(): incompatible function arguments." in str(
excinfo.value excinfo.value
) )
assert ', "flags.c_contiguous"' in str(excinfo.value) assert ", flags.c_contiguous" in str(excinfo.value)
def test_eigen_ref_life_support(): def test_eigen_ref_life_support():
@ -701,25 +700,25 @@ def test_dense_signature(doc):
assert ( assert (
doc(m.double_col) doc(m.double_col)
== """ == """
double_col(arg0: typing.Annotated[numpy.typing.ArrayLike, numpy.float32, "[m, 1]"]) -> typing.Annotated[numpy.typing.NDArray[numpy.float32], "[m, 1]"] double_col(arg0: numpy.ndarray[numpy.float32[m, 1]]) -> numpy.ndarray[numpy.float32[m, 1]]
""" """
) )
assert ( assert (
doc(m.double_row) doc(m.double_row)
== """ == """
double_row(arg0: typing.Annotated[numpy.typing.ArrayLike, numpy.float32, "[1, n]"]) -> typing.Annotated[numpy.typing.NDArray[numpy.float32], "[1, n]"] double_row(arg0: numpy.ndarray[numpy.float32[1, n]]) -> numpy.ndarray[numpy.float32[1, n]]
""" """
) )
assert doc(m.double_complex) == ( assert doc(m.double_complex) == (
""" """
double_complex(arg0: typing.Annotated[numpy.typing.ArrayLike, numpy.complex64, "[m, 1]"])""" double_complex(arg0: numpy.ndarray[numpy.complex64[m, 1]])"""
""" -> typing.Annotated[numpy.typing.NDArray[numpy.complex64], "[m, 1]"] """ -> numpy.ndarray[numpy.complex64[m, 1]]
""" """
) )
assert doc(m.double_mat_rm) == ( assert doc(m.double_mat_rm) == (
""" """
double_mat_rm(arg0: typing.Annotated[numpy.typing.ArrayLike, numpy.float32, "[m, n]"])""" double_mat_rm(arg0: numpy.ndarray[numpy.float32[m, n]])"""
""" -> typing.Annotated[numpy.typing.NDArray[numpy.float32], "[m, n]"] """ -> numpy.ndarray[numpy.float32[m, n]]
""" """
) )
@ -818,22 +817,3 @@ def test_custom_operator_new():
o = m.CustomOperatorNew() o = m.CustomOperatorNew()
np.testing.assert_allclose(o.a, 0.0) np.testing.assert_allclose(o.a, 0.0)
np.testing.assert_allclose(o.b.diagonal(), 1.0) np.testing.assert_allclose(o.b.diagonal(), 1.0)
def test_arraylike_signature(doc):
assert doc(m.round_trip_vector) == (
'round_trip_vector(arg0: typing.Annotated[numpy.typing.ArrayLike, numpy.float32, "[m, 1]"])'
' -> typing.Annotated[numpy.typing.NDArray[numpy.float32], "[m, 1]"]'
)
assert doc(m.round_trip_dense) == (
'round_trip_dense(arg0: typing.Annotated[numpy.typing.ArrayLike, numpy.float32, "[m, n]"])'
' -> typing.Annotated[numpy.typing.NDArray[numpy.float32], "[m, n]"]'
)
assert doc(m.round_trip_dense_ref) == (
'round_trip_dense_ref(arg0: typing.Annotated[numpy.typing.NDArray[numpy.float32], "[m, n]", "flags.writeable", "flags.c_contiguous"])'
' -> typing.Annotated[numpy.typing.NDArray[numpy.float32], "[m, n]", "flags.writeable", "flags.c_contiguous"]'
)
m.round_trip_vector([1.0, 2.0])
m.round_trip_dense([[1.0, 2.0], [3.0, 4.0]])
with pytest.raises(TypeError, match="incompatible function arguments"):
m.round_trip_dense_ref([[1.0, 2.0], [3.0, 4.0]])

View File

@ -271,46 +271,23 @@ def test_round_trip_references_actually_refer(m):
@pytest.mark.parametrize("m", submodules) @pytest.mark.parametrize("m", submodules)
def test_doc_string(m, doc): def test_doc_string(m, doc):
assert ( assert (
doc(m.copy_tensor) doc(m.copy_tensor) == "copy_tensor() -> numpy.ndarray[numpy.float64[?, ?, ?]]"
== 'copy_tensor() -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[?, ?, ?]"]'
) )
assert ( assert (
doc(m.copy_fixed_tensor) doc(m.copy_fixed_tensor)
== 'copy_fixed_tensor() -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[3, 5, 2]"]' == "copy_fixed_tensor() -> numpy.ndarray[numpy.float64[3, 5, 2]]"
) )
assert ( assert (
doc(m.reference_const_tensor) doc(m.reference_const_tensor)
== 'reference_const_tensor() -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[?, ?, ?]"]' == "reference_const_tensor() -> numpy.ndarray[numpy.float64[?, ?, ?]]"
) )
order_flag = f'"flags.{m.needed_options.lower()}_contiguous"' order_flag = f"flags.{m.needed_options.lower()}_contiguous"
assert doc(m.round_trip_view_tensor) == ( assert doc(m.round_trip_view_tensor) == (
f'round_trip_view_tensor(arg0: typing.Annotated[numpy.typing.NDArray[numpy.float64], "[?, ?, ?]", "flags.writeable", {order_flag}])' f"round_trip_view_tensor(arg0: numpy.ndarray[numpy.float64[?, ?, ?], flags.writeable, {order_flag}])"
f' -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[?, ?, ?]", "flags.writeable", {order_flag}]' f" -> numpy.ndarray[numpy.float64[?, ?, ?], flags.writeable, {order_flag}]"
) )
assert doc(m.round_trip_const_view_tensor) == ( assert doc(m.round_trip_const_view_tensor) == (
f'round_trip_const_view_tensor(arg0: typing.Annotated[numpy.typing.NDArray[numpy.float64], "[?, ?, ?]", {order_flag}])' f"round_trip_const_view_tensor(arg0: numpy.ndarray[numpy.float64[?, ?, ?], {order_flag}])"
' -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[?, ?, ?]"]' " -> numpy.ndarray[numpy.float64[?, ?, ?]]"
) )
@pytest.mark.parametrize("m", submodules)
def test_arraylike_signature(m, doc):
order_flag = f'"flags.{m.needed_options.lower()}_contiguous"'
assert doc(m.round_trip_tensor) == (
'round_trip_tensor(arg0: typing.Annotated[numpy.typing.ArrayLike, numpy.float64, "[?, ?, ?]"])'
' -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[?, ?, ?]"]'
)
assert doc(m.round_trip_tensor_noconvert) == (
'round_trip_tensor_noconvert(tensor: typing.Annotated[numpy.typing.NDArray[numpy.float64], "[?, ?, ?]"])'
' -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[?, ?, ?]"]'
)
assert doc(m.round_trip_view_tensor) == (
f'round_trip_view_tensor(arg0: typing.Annotated[numpy.typing.NDArray[numpy.float64], "[?, ?, ?]", "flags.writeable", {order_flag}])'
f' -> typing.Annotated[numpy.typing.NDArray[numpy.float64], "[?, ?, ?]", "flags.writeable", {order_flag}]'
)
m.round_trip_tensor(tensor_ref.tolist())
with pytest.raises(TypeError, match="incompatible function arguments"):
m.round_trip_tensor_noconvert(tensor_ref.tolist())
with pytest.raises(TypeError, match="incompatible function arguments"):
m.round_trip_view_tensor(tensor_ref.tolist())

View File

@ -586,13 +586,4 @@ TEST_SUBMODULE(numpy_array, sm) {
sm.def("return_array_pyobject_ptr_from_list", return_array_from_list<PyObject *>); sm.def("return_array_pyobject_ptr_from_list", return_array_from_list<PyObject *>);
sm.def("return_array_handle_from_list", return_array_from_list<py::handle>); sm.def("return_array_handle_from_list", return_array_from_list<py::handle>);
sm.def("return_array_object_from_list", return_array_from_list<py::object>); sm.def("return_array_object_from_list", return_array_from_list<py::object>);
sm.def(
"round_trip_array_t",
[](const py::array_t<float> &x) -> py::array_t<float> { return x; },
py::arg("x"));
sm.def(
"round_trip_array_t_noconvert",
[](const py::array_t<float> &x) -> py::array_t<float> { return x; },
py::arg("x").noconvert());
} }

View File

@ -321,13 +321,13 @@ def test_overload_resolution(msg):
msg(excinfo.value) msg(excinfo.value)
== """ == """
overloaded(): incompatible function arguments. The following argument types are supported: overloaded(): incompatible function arguments. The following argument types are supported:
1. (arg0: typing.Annotated[numpy.typing.ArrayLike, numpy.float64]) -> str 1. (arg0: numpy.ndarray[numpy.float64]) -> str
2. (arg0: typing.Annotated[numpy.typing.ArrayLike, numpy.float32]) -> str 2. (arg0: numpy.ndarray[numpy.float32]) -> str
3. (arg0: typing.Annotated[numpy.typing.ArrayLike, numpy.int32]) -> str 3. (arg0: numpy.ndarray[numpy.int32]) -> str
4. (arg0: typing.Annotated[numpy.typing.ArrayLike, numpy.uint16]) -> str 4. (arg0: numpy.ndarray[numpy.uint16]) -> str
5. (arg0: typing.Annotated[numpy.typing.ArrayLike, numpy.int64]) -> str 5. (arg0: numpy.ndarray[numpy.int64]) -> str
6. (arg0: typing.Annotated[numpy.typing.ArrayLike, numpy.complex128]) -> str 6. (arg0: numpy.ndarray[numpy.complex128]) -> str
7. (arg0: typing.Annotated[numpy.typing.ArrayLike, numpy.complex64]) -> str 7. (arg0: numpy.ndarray[numpy.complex64]) -> str
Invoked with: 'not an array' Invoked with: 'not an array'
""" """
@ -343,8 +343,8 @@ def test_overload_resolution(msg):
assert m.overloaded3(np.array([1], dtype="intc")) == "int" assert m.overloaded3(np.array([1], dtype="intc")) == "int"
expected_exc = """ expected_exc = """
overloaded3(): incompatible function arguments. The following argument types are supported: overloaded3(): incompatible function arguments. The following argument types are supported:
1. (arg0: numpy.typing.NDArray[numpy.int32]) -> str 1. (arg0: numpy.ndarray[numpy.int32]) -> str
2. (arg0: numpy.typing.NDArray[numpy.float64]) -> str 2. (arg0: numpy.ndarray[numpy.float64]) -> str
Invoked with: """ Invoked with: """
@ -528,7 +528,7 @@ def test_index_using_ellipsis():
], ],
) )
def test_format_descriptors_for_floating_point_types(test_func): def test_format_descriptors_for_floating_point_types(test_func):
assert "numpy.typing.ArrayLike, numpy.float" in test_func.__doc__ assert "numpy.ndarray[numpy.float" in test_func.__doc__
@pytest.mark.parametrize("forcecast", [False, True]) @pytest.mark.parametrize("forcecast", [False, True])
@ -687,17 +687,3 @@ def test_return_array_object_cpp_loop(return_array, unwrap):
assert isinstance(arr_from_list, np.ndarray) assert isinstance(arr_from_list, np.ndarray)
assert arr_from_list.dtype == np.dtype("O") assert arr_from_list.dtype == np.dtype("O")
assert unwrap(arr_from_list) == [6, "seven", -8.0] assert unwrap(arr_from_list) == [6, "seven", -8.0]
def test_arraylike_signature(doc):
assert (
doc(m.round_trip_array_t)
== "round_trip_array_t(x: typing.Annotated[numpy.typing.ArrayLike, numpy.float32]) -> numpy.typing.NDArray[numpy.float32]"
)
assert (
doc(m.round_trip_array_t_noconvert)
== "round_trip_array_t_noconvert(x: numpy.typing.NDArray[numpy.float32]) -> numpy.typing.NDArray[numpy.float32]"
)
m.round_trip_array_t([1, 2, 3])
with pytest.raises(TypeError, match="incompatible function arguments"):
m.round_trip_array_t_noconvert([1, 2, 3])

View File

@ -373,7 +373,7 @@ def test_complex_array():
def test_signature(doc): def test_signature(doc):
assert ( assert (
doc(m.create_rec_nested) doc(m.create_rec_nested)
== "create_rec_nested(arg0: int) -> numpy.typing.NDArray[NestedStruct]" == "create_rec_nested(arg0: int) -> numpy.ndarray[NestedStruct]"
) )

View File

@ -150,7 +150,7 @@ def test_docs(doc):
assert ( assert (
doc(m.vectorized_func) doc(m.vectorized_func)
== """ == """
vectorized_func(arg0: typing.Annotated[numpy.typing.ArrayLike, numpy.int32], arg1: typing.Annotated[numpy.typing.ArrayLike, numpy.float32], arg2: typing.Annotated[numpy.typing.ArrayLike, numpy.float64]) -> object vectorized_func(arg0: numpy.ndarray[numpy.int32], arg1: numpy.ndarray[numpy.float32], arg2: numpy.ndarray[numpy.float64]) -> object
""" """
) )
@ -212,12 +212,12 @@ def test_passthrough_arguments(doc):
+ ", ".join( + ", ".join(
[ [
"arg0: float", "arg0: float",
"arg1: typing.Annotated[numpy.typing.ArrayLike, numpy.float64]", "arg1: numpy.ndarray[numpy.float64]",
"arg2: typing.Annotated[numpy.typing.ArrayLike, numpy.float64]", "arg2: numpy.ndarray[numpy.float64]",
"arg3: typing.Annotated[numpy.typing.ArrayLike, numpy.int32]", "arg3: numpy.ndarray[numpy.int32]",
"arg4: int", "arg4: int",
"arg5: m.numpy_vectorize.NonPODClass", "arg5: m.numpy_vectorize.NonPODClass",
"arg6: typing.Annotated[numpy.typing.ArrayLike, numpy.float64]", "arg6: numpy.ndarray[numpy.float64]",
] ]
) )
+ ") -> object" + ") -> object"

View File

@ -22,6 +22,8 @@ void wrap_number_bucket(py::module m, const char *class_name) {
.def("add", &WrappedType::add, py::arg("other")); .def("add", &WrappedType::add, py::arg("other"));
} }
#ifdef PYBIND11_SMART_HOLDER_ENABLED
template <typename T> template <typename T>
class padded_unique_ptr { class padded_unique_ptr {
std::unique_ptr<T> ptr; std::unique_ptr<T> ptr;
@ -35,15 +37,21 @@ public:
static_assert(sizeof(padded_unique_ptr<nb_pu>) == sizeof(py::smart_holder), static_assert(sizeof(padded_unique_ptr<nb_pu>) == sizeof(py::smart_holder),
"Unexpected sizeof mismatch."); "Unexpected sizeof mismatch.");
#endif
} // namespace hc } // namespace hc
#ifdef PYBIND11_SMART_HOLDER_ENABLED
PYBIND11_DECLARE_HOLDER_TYPE(T, hc::padded_unique_ptr<T>); PYBIND11_DECLARE_HOLDER_TYPE(T, hc::padded_unique_ptr<T>);
#endif
PYBIND11_MODULE(pybind11_ubench_holder_comparison, m) { PYBIND11_MODULE(pybind11_ubench_holder_comparison, m) {
using namespace hc; using namespace hc;
wrap_number_bucket<nb_up, std::unique_ptr<nb_up>>(m, "number_bucket_up"); wrap_number_bucket<nb_up, std::unique_ptr<nb_up>>(m, "number_bucket_up");
wrap_number_bucket<nb_sp, std::shared_ptr<nb_sp>>(m, "number_bucket_sp"); wrap_number_bucket<nb_sp, std::shared_ptr<nb_sp>>(m, "number_bucket_sp");
#ifdef PYBIND11_SMART_HOLDER_ENABLED
m.def("sizeof_smart_holder", []() { return sizeof(py::smart_holder); }); m.def("sizeof_smart_holder", []() { return sizeof(py::smart_holder); });
wrap_number_bucket<nb_pu, padded_unique_ptr<nb_pu>>(m, "number_bucket_pu"); wrap_number_bucket<nb_pu, padded_unique_ptr<nb_pu>>(m, "number_bucket_pu");
wrap_number_bucket<nb_sh, py::smart_holder>(m, "number_bucket_sh"); wrap_number_bucket<nb_sh, py::smart_holder>(m, "number_bucket_sh");
#endif
} }