mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-29 00:22:00 +00:00
Merge branch 'master' into pybind11_platform_abi_id_cont
This commit is contained in:
commit
e46982c2f0
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
@ -145,6 +145,7 @@ jobs:
|
|||||||
-DPYBIND11_DISABLE_HANDLE_TYPE_NAME_DEFAULT_IMPLEMENTATION=ON
|
-DPYBIND11_DISABLE_HANDLE_TYPE_NAME_DEFAULT_IMPLEMENTATION=ON
|
||||||
-DPYBIND11_SIMPLE_GIL_MANAGEMENT=ON
|
-DPYBIND11_SIMPLE_GIL_MANAGEMENT=ON
|
||||||
-DPYBIND11_NUMPY_1_ONLY=ON
|
-DPYBIND11_NUMPY_1_ONLY=ON
|
||||||
|
-DPYBIND11_PYTEST_ARGS=-v
|
||||||
-DDOWNLOAD_CATCH=ON
|
-DDOWNLOAD_CATCH=ON
|
||||||
-DDOWNLOAD_EIGEN=ON
|
-DDOWNLOAD_EIGEN=ON
|
||||||
-DCMAKE_CXX_STANDARD=11
|
-DCMAKE_CXX_STANDARD=11
|
||||||
@ -174,6 +175,7 @@ jobs:
|
|||||||
-DPYBIND11_WERROR=ON
|
-DPYBIND11_WERROR=ON
|
||||||
-DPYBIND11_SIMPLE_GIL_MANAGEMENT=OFF
|
-DPYBIND11_SIMPLE_GIL_MANAGEMENT=OFF
|
||||||
-DPYBIND11_NUMPY_1_ONLY=ON
|
-DPYBIND11_NUMPY_1_ONLY=ON
|
||||||
|
-DPYBIND11_PYTEST_ARGS=-v
|
||||||
-DDOWNLOAD_CATCH=ON
|
-DDOWNLOAD_CATCH=ON
|
||||||
-DDOWNLOAD_EIGEN=ON
|
-DDOWNLOAD_EIGEN=ON
|
||||||
-DCMAKE_CXX_STANDARD=17
|
-DCMAKE_CXX_STANDARD=17
|
||||||
@ -193,6 +195,7 @@ jobs:
|
|||||||
run: >
|
run: >
|
||||||
cmake -S . -B build3
|
cmake -S . -B build3
|
||||||
-DPYBIND11_WERROR=ON
|
-DPYBIND11_WERROR=ON
|
||||||
|
-DPYBIND11_PYTEST_ARGS=-v
|
||||||
-DDOWNLOAD_CATCH=ON
|
-DDOWNLOAD_CATCH=ON
|
||||||
-DDOWNLOAD_EIGEN=ON
|
-DDOWNLOAD_EIGEN=ON
|
||||||
-DCMAKE_CXX_STANDARD=17
|
-DCMAKE_CXX_STANDARD=17
|
||||||
@ -1016,7 +1019,6 @@ jobs:
|
|||||||
git
|
git
|
||||||
mingw-w64-${{matrix.env}}-gcc
|
mingw-w64-${{matrix.env}}-gcc
|
||||||
mingw-w64-${{matrix.env}}-python-pip
|
mingw-w64-${{matrix.env}}-python-pip
|
||||||
mingw-w64-${{matrix.env}}-python-numpy
|
|
||||||
mingw-w64-${{matrix.env}}-cmake
|
mingw-w64-${{matrix.env}}-cmake
|
||||||
mingw-w64-${{matrix.env}}-make
|
mingw-w64-${{matrix.env}}-make
|
||||||
mingw-w64-${{matrix.env}}-python-pytest
|
mingw-w64-${{matrix.env}}-python-pytest
|
||||||
@ -1028,7 +1030,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
msystem: ${{matrix.sys}}
|
msystem: ${{matrix.sys}}
|
||||||
install: >-
|
install: >-
|
||||||
git
|
mingw-w64-${{matrix.env}}-python-numpy
|
||||||
mingw-w64-${{matrix.env}}-python-scipy
|
mingw-w64-${{matrix.env}}-python-scipy
|
||||||
mingw-w64-${{matrix.env}}-eigen3
|
mingw-w64-${{matrix.env}}-eigen3
|
||||||
|
|
||||||
|
2
.github/workflows/pip.yml
vendored
2
.github/workflows/pip.yml
vendored
@ -103,7 +103,7 @@ jobs:
|
|||||||
- uses: actions/download-artifact@v4
|
- uses: actions/download-artifact@v4
|
||||||
|
|
||||||
- name: Generate artifact attestation for sdist and wheel
|
- name: Generate artifact attestation for sdist and wheel
|
||||||
uses: actions/attest-build-provenance@1c608d11d69870c2092266b3f9a6f3abbf17002c # v1.4.3
|
uses: actions/attest-build-provenance@ef244123eb79f2f7a7e75d99086184180e6d0018 # v1.4.4
|
||||||
with:
|
with:
|
||||||
subject-path: "*/pybind11*"
|
subject-path: "*/pybind11*"
|
||||||
|
|
||||||
|
@ -1012,10 +1012,18 @@ template <>
|
|||||||
struct handle_type_name<args> {
|
struct handle_type_name<args> {
|
||||||
static constexpr auto name = const_name("*args");
|
static constexpr auto name = const_name("*args");
|
||||||
};
|
};
|
||||||
|
template <typename T>
|
||||||
|
struct handle_type_name<Args<T>> {
|
||||||
|
static constexpr auto name = const_name("*args: ") + make_caster<T>::name;
|
||||||
|
};
|
||||||
template <>
|
template <>
|
||||||
struct handle_type_name<kwargs> {
|
struct handle_type_name<kwargs> {
|
||||||
static constexpr auto name = const_name("**kwargs");
|
static constexpr auto name = const_name("**kwargs");
|
||||||
};
|
};
|
||||||
|
template <typename T>
|
||||||
|
struct handle_type_name<KWArgs<T>> {
|
||||||
|
static constexpr auto name = const_name("**kwargs: ") + make_caster<T>::name;
|
||||||
|
};
|
||||||
template <>
|
template <>
|
||||||
struct handle_type_name<obj_attr_accessor> {
|
struct handle_type_name<obj_attr_accessor> {
|
||||||
static constexpr auto name = const_name<obj_attr_accessor>();
|
static constexpr auto name = const_name<obj_attr_accessor>();
|
||||||
|
@ -410,7 +410,7 @@ struct pickle_factory<Get, Set, RetState(Self), NewInstance(ArgState)> {
|
|||||||
|
|
||||||
template <typename Class, typename... Extra>
|
template <typename Class, typename... Extra>
|
||||||
void execute(Class &cl, const Extra &...extra) && {
|
void execute(Class &cl, const Extra &...extra) && {
|
||||||
cl.def("__getstate__", std::move(get));
|
cl.def("__getstate__", std::move(get), pos_only());
|
||||||
|
|
||||||
#if defined(PYBIND11_CPP14)
|
#if defined(PYBIND11_CPP14)
|
||||||
cl.def(
|
cl.def(
|
||||||
|
@ -212,6 +212,7 @@ constexpr int platform_lookup(int I, Ints... Is) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct npy_api {
|
struct npy_api {
|
||||||
|
// If you change this code, please review `normalized_dtype_num` below.
|
||||||
enum constants {
|
enum constants {
|
||||||
NPY_ARRAY_C_CONTIGUOUS_ = 0x0001,
|
NPY_ARRAY_C_CONTIGUOUS_ = 0x0001,
|
||||||
NPY_ARRAY_F_CONTIGUOUS_ = 0x0002,
|
NPY_ARRAY_F_CONTIGUOUS_ = 0x0002,
|
||||||
@ -384,6 +385,74 @@ private:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// This table normalizes typenums by mapping NPY_INT_, NPY_LONG, ... to NPY_INT32_, NPY_INT64, ...
|
||||||
|
// This is needed to correctly handle situations where multiple typenums map to the same type,
|
||||||
|
// e.g. NPY_LONG_ may be equivalent to NPY_INT_ or NPY_LONGLONG_ despite having a different
|
||||||
|
// typenum. The normalized typenum should always match the values used in npy_format_descriptor.
|
||||||
|
// If you change this code, please review `enum constants` above.
|
||||||
|
static constexpr int normalized_dtype_num[npy_api::NPY_VOID_ + 1] = {
|
||||||
|
// NPY_BOOL_ =>
|
||||||
|
npy_api::NPY_BOOL_,
|
||||||
|
// NPY_BYTE_ =>
|
||||||
|
npy_api::NPY_BYTE_,
|
||||||
|
// NPY_UBYTE_ =>
|
||||||
|
npy_api::NPY_UBYTE_,
|
||||||
|
// NPY_SHORT_ =>
|
||||||
|
npy_api::NPY_INT16_,
|
||||||
|
// NPY_USHORT_ =>
|
||||||
|
npy_api::NPY_UINT16_,
|
||||||
|
// NPY_INT_ =>
|
||||||
|
sizeof(int) == sizeof(std::int16_t) ? npy_api::NPY_INT16_
|
||||||
|
: sizeof(int) == sizeof(std::int32_t) ? npy_api::NPY_INT32_
|
||||||
|
: sizeof(int) == sizeof(std::int64_t) ? npy_api::NPY_INT64_
|
||||||
|
: npy_api::NPY_INT_,
|
||||||
|
// NPY_UINT_ =>
|
||||||
|
sizeof(unsigned int) == sizeof(std::uint16_t) ? npy_api::NPY_UINT16_
|
||||||
|
: sizeof(unsigned int) == sizeof(std::uint32_t) ? npy_api::NPY_UINT32_
|
||||||
|
: sizeof(unsigned int) == sizeof(std::uint64_t) ? npy_api::NPY_UINT64_
|
||||||
|
: npy_api::NPY_UINT_,
|
||||||
|
// NPY_LONG_ =>
|
||||||
|
sizeof(long) == sizeof(std::int16_t) ? npy_api::NPY_INT16_
|
||||||
|
: sizeof(long) == sizeof(std::int32_t) ? npy_api::NPY_INT32_
|
||||||
|
: sizeof(long) == sizeof(std::int64_t) ? npy_api::NPY_INT64_
|
||||||
|
: npy_api::NPY_LONG_,
|
||||||
|
// NPY_ULONG_ =>
|
||||||
|
sizeof(unsigned long) == sizeof(std::uint16_t) ? npy_api::NPY_UINT16_
|
||||||
|
: sizeof(unsigned long) == sizeof(std::uint32_t) ? npy_api::NPY_UINT32_
|
||||||
|
: sizeof(unsigned long) == sizeof(std::uint64_t) ? npy_api::NPY_UINT64_
|
||||||
|
: npy_api::NPY_ULONG_,
|
||||||
|
// NPY_LONGLONG_ =>
|
||||||
|
sizeof(long long) == sizeof(std::int16_t) ? npy_api::NPY_INT16_
|
||||||
|
: sizeof(long long) == sizeof(std::int32_t) ? npy_api::NPY_INT32_
|
||||||
|
: sizeof(long long) == sizeof(std::int64_t) ? npy_api::NPY_INT64_
|
||||||
|
: npy_api::NPY_LONGLONG_,
|
||||||
|
// NPY_ULONGLONG_ =>
|
||||||
|
sizeof(unsigned long long) == sizeof(std::uint16_t) ? npy_api::NPY_UINT16_
|
||||||
|
: sizeof(unsigned long long) == sizeof(std::uint32_t) ? npy_api::NPY_UINT32_
|
||||||
|
: sizeof(unsigned long long) == sizeof(std::uint64_t) ? npy_api::NPY_UINT64_
|
||||||
|
: npy_api::NPY_ULONGLONG_,
|
||||||
|
// NPY_FLOAT_ =>
|
||||||
|
npy_api::NPY_FLOAT_,
|
||||||
|
// NPY_DOUBLE_ =>
|
||||||
|
npy_api::NPY_DOUBLE_,
|
||||||
|
// NPY_LONGDOUBLE_ =>
|
||||||
|
npy_api::NPY_LONGDOUBLE_,
|
||||||
|
// NPY_CFLOAT_ =>
|
||||||
|
npy_api::NPY_CFLOAT_,
|
||||||
|
// NPY_CDOUBLE_ =>
|
||||||
|
npy_api::NPY_CDOUBLE_,
|
||||||
|
// NPY_CLONGDOUBLE_ =>
|
||||||
|
npy_api::NPY_CLONGDOUBLE_,
|
||||||
|
// NPY_OBJECT_ =>
|
||||||
|
npy_api::NPY_OBJECT_,
|
||||||
|
// NPY_STRING_ =>
|
||||||
|
npy_api::NPY_STRING_,
|
||||||
|
// NPY_UNICODE_ =>
|
||||||
|
npy_api::NPY_UNICODE_,
|
||||||
|
// NPY_VOID_ =>
|
||||||
|
npy_api::NPY_VOID_,
|
||||||
|
};
|
||||||
|
|
||||||
inline PyArray_Proxy *array_proxy(void *ptr) { return reinterpret_cast<PyArray_Proxy *>(ptr); }
|
inline PyArray_Proxy *array_proxy(void *ptr) { return reinterpret_cast<PyArray_Proxy *>(ptr); }
|
||||||
|
|
||||||
inline const PyArray_Proxy *array_proxy(const void *ptr) {
|
inline const PyArray_Proxy *array_proxy(const void *ptr) {
|
||||||
@ -684,6 +753,13 @@ public:
|
|||||||
return detail::npy_format_descriptor<typename std::remove_cv<T>::type>::dtype();
|
return detail::npy_format_descriptor<typename std::remove_cv<T>::type>::dtype();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the type number associated with a C++ type.
|
||||||
|
/// This is the constexpr equivalent of `dtype::of<T>().num()`.
|
||||||
|
template <typename T>
|
||||||
|
static constexpr int num_of() {
|
||||||
|
return detail::npy_format_descriptor<typename std::remove_cv<T>::type>::value;
|
||||||
|
}
|
||||||
|
|
||||||
/// Size of the data type in bytes.
|
/// Size of the data type in bytes.
|
||||||
#ifdef PYBIND11_NUMPY_1_ONLY
|
#ifdef PYBIND11_NUMPY_1_ONLY
|
||||||
ssize_t itemsize() const { return detail::array_descriptor_proxy(m_ptr)->elsize; }
|
ssize_t itemsize() const { return detail::array_descriptor_proxy(m_ptr)->elsize; }
|
||||||
@ -725,7 +801,9 @@ public:
|
|||||||
return detail::array_descriptor_proxy(m_ptr)->type;
|
return detail::array_descriptor_proxy(m_ptr)->type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// type number of dtype.
|
/// Type number of dtype. Note that different values may be returned for equivalent types,
|
||||||
|
/// e.g. even though ``long`` may be equivalent to ``int`` or ``long long``, they still have
|
||||||
|
/// different type numbers. Consider using `normalized_num` to avoid this.
|
||||||
int num() const {
|
int num() const {
|
||||||
// Note: The signature, `dtype::num` follows the naming of NumPy's public
|
// Note: The signature, `dtype::num` follows the naming of NumPy's public
|
||||||
// Python API (i.e., ``dtype.num``), rather than its internal
|
// Python API (i.e., ``dtype.num``), rather than its internal
|
||||||
@ -733,6 +811,17 @@ public:
|
|||||||
return detail::array_descriptor_proxy(m_ptr)->type_num;
|
return detail::array_descriptor_proxy(m_ptr)->type_num;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Type number of dtype, normalized to match the return value of `num_of` for equivalent
|
||||||
|
/// types. This function can be used to write switch statements that correctly handle
|
||||||
|
/// equivalent types with different type numbers.
|
||||||
|
int normalized_num() const {
|
||||||
|
int value = num();
|
||||||
|
if (value >= 0 && value <= detail::npy_api::NPY_VOID_) {
|
||||||
|
return detail::normalized_dtype_num[value];
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
/// Single character for byteorder
|
/// Single character for byteorder
|
||||||
char byteorder() const { return detail::array_descriptor_proxy(m_ptr)->byteorder; }
|
char byteorder() const { return detail::array_descriptor_proxy(m_ptr)->byteorder; }
|
||||||
|
|
||||||
@ -1428,7 +1517,11 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct npy_format_descriptor<T, enable_if_t<is_same_ignoring_cvref<T, PyObject *>::value>> {
|
struct npy_format_descriptor<
|
||||||
|
T,
|
||||||
|
enable_if_t<is_same_ignoring_cvref<T, PyObject *>::value
|
||||||
|
|| ((std::is_same<T, handle>::value || std::is_same<T, object>::value)
|
||||||
|
&& sizeof(T) == sizeof(PyObject *))>> {
|
||||||
static constexpr auto name = const_name("object");
|
static constexpr auto name = const_name("object");
|
||||||
|
|
||||||
static constexpr int value = npy_api::NPY_OBJECT_;
|
static constexpr int value = npy_api::NPY_OBJECT_;
|
||||||
|
@ -301,9 +301,20 @@ protected:
|
|||||||
constexpr bool has_kw_only_args = any_of<std::is_same<kw_only, Extra>...>::value,
|
constexpr bool has_kw_only_args = any_of<std::is_same<kw_only, Extra>...>::value,
|
||||||
has_pos_only_args = any_of<std::is_same<pos_only, Extra>...>::value,
|
has_pos_only_args = any_of<std::is_same<pos_only, Extra>...>::value,
|
||||||
has_arg_annotations = any_of<is_keyword<Extra>...>::value;
|
has_arg_annotations = any_of<is_keyword<Extra>...>::value;
|
||||||
|
constexpr bool has_is_method = any_of<std::is_same<is_method, Extra>...>::value;
|
||||||
|
// The implicit `self` argument is not present and not counted in method definitions.
|
||||||
|
constexpr bool has_args = cast_in::args_pos >= 0;
|
||||||
|
constexpr bool is_method_with_self_arg_only = has_is_method && !has_args;
|
||||||
static_assert(has_arg_annotations || !has_kw_only_args,
|
static_assert(has_arg_annotations || !has_kw_only_args,
|
||||||
"py::kw_only requires the use of argument annotations");
|
"py::kw_only requires the use of argument annotations");
|
||||||
static_assert(has_arg_annotations || !has_pos_only_args,
|
static_assert(((/* Need `py::arg("arg_name")` annotation in function/method. */
|
||||||
|
has_arg_annotations)
|
||||||
|
|| (/* Allow methods with no arguments `def method(self, /): ...`.
|
||||||
|
* A method has at least one argument `self`. There can be no
|
||||||
|
* `py::arg` annotation. E.g. `class.def("method", py::pos_only())`.
|
||||||
|
*/
|
||||||
|
is_method_with_self_arg_only))
|
||||||
|
|| !has_pos_only_args,
|
||||||
"py::pos_only requires the use of argument annotations (for docstrings "
|
"py::pos_only requires the use of argument annotations (for docstrings "
|
||||||
"and aligning the annotations to the argument)");
|
"and aligning the annotations to the argument)");
|
||||||
|
|
||||||
@ -2022,9 +2033,11 @@ struct enum_base {
|
|||||||
.format(std::move(type_name), enum_name(arg), int_(arg));
|
.format(std::move(type_name), enum_name(arg), int_(arg));
|
||||||
},
|
},
|
||||||
name("__repr__"),
|
name("__repr__"),
|
||||||
is_method(m_base));
|
is_method(m_base),
|
||||||
|
pos_only());
|
||||||
|
|
||||||
m_base.attr("name") = property(cpp_function(&enum_name, name("name"), is_method(m_base)));
|
m_base.attr("name")
|
||||||
|
= property(cpp_function(&enum_name, name("name"), is_method(m_base), pos_only()));
|
||||||
|
|
||||||
m_base.attr("__str__") = cpp_function(
|
m_base.attr("__str__") = cpp_function(
|
||||||
[](handle arg) -> str {
|
[](handle arg) -> str {
|
||||||
@ -2032,7 +2045,8 @@ struct enum_base {
|
|||||||
return pybind11::str("{}.{}").format(std::move(type_name), enum_name(arg));
|
return pybind11::str("{}.{}").format(std::move(type_name), enum_name(arg));
|
||||||
},
|
},
|
||||||
name("__str__"),
|
name("__str__"),
|
||||||
is_method(m_base));
|
is_method(m_base),
|
||||||
|
pos_only());
|
||||||
|
|
||||||
if (options::show_enum_members_docstring()) {
|
if (options::show_enum_members_docstring()) {
|
||||||
m_base.attr("__doc__") = static_property(
|
m_base.attr("__doc__") = static_property(
|
||||||
@ -2087,7 +2101,8 @@ struct enum_base {
|
|||||||
}, \
|
}, \
|
||||||
name(op), \
|
name(op), \
|
||||||
is_method(m_base), \
|
is_method(m_base), \
|
||||||
arg("other"))
|
arg("other"), \
|
||||||
|
pos_only())
|
||||||
|
|
||||||
#define PYBIND11_ENUM_OP_CONV(op, expr) \
|
#define PYBIND11_ENUM_OP_CONV(op, expr) \
|
||||||
m_base.attr(op) = cpp_function( \
|
m_base.attr(op) = cpp_function( \
|
||||||
@ -2097,7 +2112,8 @@ struct enum_base {
|
|||||||
}, \
|
}, \
|
||||||
name(op), \
|
name(op), \
|
||||||
is_method(m_base), \
|
is_method(m_base), \
|
||||||
arg("other"))
|
arg("other"), \
|
||||||
|
pos_only())
|
||||||
|
|
||||||
#define PYBIND11_ENUM_OP_CONV_LHS(op, expr) \
|
#define PYBIND11_ENUM_OP_CONV_LHS(op, expr) \
|
||||||
m_base.attr(op) = cpp_function( \
|
m_base.attr(op) = cpp_function( \
|
||||||
@ -2107,7 +2123,8 @@ struct enum_base {
|
|||||||
}, \
|
}, \
|
||||||
name(op), \
|
name(op), \
|
||||||
is_method(m_base), \
|
is_method(m_base), \
|
||||||
arg("other"))
|
arg("other"), \
|
||||||
|
pos_only())
|
||||||
|
|
||||||
if (is_convertible) {
|
if (is_convertible) {
|
||||||
PYBIND11_ENUM_OP_CONV_LHS("__eq__", !b.is_none() && a.equal(b));
|
PYBIND11_ENUM_OP_CONV_LHS("__eq__", !b.is_none() && a.equal(b));
|
||||||
@ -2127,7 +2144,8 @@ struct enum_base {
|
|||||||
m_base.attr("__invert__")
|
m_base.attr("__invert__")
|
||||||
= cpp_function([](const object &arg) { return ~(int_(arg)); },
|
= cpp_function([](const object &arg) { return ~(int_(arg)); },
|
||||||
name("__invert__"),
|
name("__invert__"),
|
||||||
is_method(m_base));
|
is_method(m_base),
|
||||||
|
pos_only());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
PYBIND11_ENUM_OP_STRICT("__eq__", int_(a).equal(int_(b)), return false);
|
PYBIND11_ENUM_OP_STRICT("__eq__", int_(a).equal(int_(b)), return false);
|
||||||
@ -2147,11 +2165,15 @@ struct enum_base {
|
|||||||
#undef PYBIND11_ENUM_OP_CONV
|
#undef PYBIND11_ENUM_OP_CONV
|
||||||
#undef PYBIND11_ENUM_OP_STRICT
|
#undef PYBIND11_ENUM_OP_STRICT
|
||||||
|
|
||||||
m_base.attr("__getstate__") = cpp_function(
|
m_base.attr("__getstate__") = cpp_function([](const object &arg) { return int_(arg); },
|
||||||
[](const object &arg) { return int_(arg); }, name("__getstate__"), is_method(m_base));
|
name("__getstate__"),
|
||||||
|
is_method(m_base),
|
||||||
|
pos_only());
|
||||||
|
|
||||||
m_base.attr("__hash__") = cpp_function(
|
m_base.attr("__hash__") = cpp_function([](const object &arg) { return int_(arg); },
|
||||||
[](const object &arg) { return int_(arg); }, name("__hash__"), is_method(m_base));
|
name("__hash__"),
|
||||||
|
is_method(m_base),
|
||||||
|
pos_only());
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_NOINLINE void value(char const *name_, object value, const char *doc = nullptr) {
|
PYBIND11_NOINLINE void value(char const *name_, object value, const char *doc = nullptr) {
|
||||||
@ -2243,9 +2265,9 @@ public:
|
|||||||
m_base.init(is_arithmetic, is_convertible);
|
m_base.init(is_arithmetic, is_convertible);
|
||||||
|
|
||||||
def(init([](Scalar i) { return static_cast<Type>(i); }), arg("value"));
|
def(init([](Scalar i) { return static_cast<Type>(i); }), arg("value"));
|
||||||
def_property_readonly("value", [](Type value) { return (Scalar) value; });
|
def_property_readonly("value", [](Type value) { return (Scalar) value; }, pos_only());
|
||||||
def("__int__", [](Type value) { return (Scalar) value; });
|
def("__int__", [](Type value) { return (Scalar) value; }, pos_only());
|
||||||
def("__index__", [](Type value) { return (Scalar) value; });
|
def("__index__", [](Type value) { return (Scalar) value; }, pos_only());
|
||||||
attr("__setstate__") = cpp_function(
|
attr("__setstate__") = cpp_function(
|
||||||
[](detail::value_and_holder &v_h, Scalar arg) {
|
[](detail::value_and_holder &v_h, Scalar arg) {
|
||||||
detail::initimpl::setstate<Base>(
|
detail::initimpl::setstate<Base>(
|
||||||
@ -2254,7 +2276,8 @@ public:
|
|||||||
detail::is_new_style_constructor(),
|
detail::is_new_style_constructor(),
|
||||||
pybind11::name("__setstate__"),
|
pybind11::name("__setstate__"),
|
||||||
is_method(*this),
|
is_method(*this),
|
||||||
arg("state"));
|
arg("state"),
|
||||||
|
pos_only());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Export enumeration entries into the parent scope
|
/// Export enumeration entries into the parent scope
|
||||||
@ -2440,7 +2463,8 @@ iterator make_iterator_impl(Iterator first, Sentinel last, Extra &&...extra) {
|
|||||||
|
|
||||||
if (!detail::get_type_info(typeid(state), false)) {
|
if (!detail::get_type_info(typeid(state), false)) {
|
||||||
class_<state>(handle(), "iterator", pybind11::module_local())
|
class_<state>(handle(), "iterator", pybind11::module_local())
|
||||||
.def("__iter__", [](state &s) -> state & { return s; })
|
.def(
|
||||||
|
"__iter__", [](state &s) -> state & { return s; }, pos_only())
|
||||||
.def(
|
.def(
|
||||||
"__next__",
|
"__next__",
|
||||||
[](state &s) -> ValueType {
|
[](state &s) -> ValueType {
|
||||||
@ -2457,6 +2481,7 @@ iterator make_iterator_impl(Iterator first, Sentinel last, Extra &&...extra) {
|
|||||||
// NOLINTNEXTLINE(readability-const-return-type) // PR #3263
|
// NOLINTNEXTLINE(readability-const-return-type) // PR #3263
|
||||||
},
|
},
|
||||||
std::forward<Extra>(extra)...,
|
std::forward<Extra>(extra)...,
|
||||||
|
pos_only(),
|
||||||
Policy);
|
Policy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2226,6 +2226,18 @@ class kwargs : public dict {
|
|||||||
PYBIND11_OBJECT_DEFAULT(kwargs, dict, PyDict_Check)
|
PYBIND11_OBJECT_DEFAULT(kwargs, dict, PyDict_Check)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Subclasses of args and kwargs to support type hinting
|
||||||
|
// as defined in PEP 484. See #5357 for more info.
|
||||||
|
template <typename T>
|
||||||
|
class Args : public args {
|
||||||
|
using args::args;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class KWArgs : public kwargs {
|
||||||
|
using kwargs::kwargs;
|
||||||
|
};
|
||||||
|
|
||||||
class anyset : public object {
|
class anyset : public object {
|
||||||
public:
|
public:
|
||||||
PYBIND11_OBJECT(anyset, object, PyAnySet_Check)
|
PYBIND11_OBJECT(anyset, object, PyAnySet_Check)
|
||||||
|
@ -198,10 +198,11 @@ def pytest_assertrepr_compare(op, left, right): # noqa: ARG001
|
|||||||
|
|
||||||
|
|
||||||
def gc_collect():
|
def gc_collect():
|
||||||
"""Run the garbage collector twice (needed when running
|
"""Run the garbage collector three times (needed when running
|
||||||
reference counting tests with PyPy)"""
|
reference counting tests with PyPy)"""
|
||||||
gc.collect()
|
gc.collect()
|
||||||
gc.collect()
|
gc.collect()
|
||||||
|
gc.collect()
|
||||||
|
|
||||||
|
|
||||||
def pytest_configure():
|
def pytest_configure():
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
# ruff: noqa: SIM201 SIM300 SIM202
|
# ruff: noqa: SIM201 SIM300 SIM202
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import env # noqa: F401
|
import env # noqa: F401
|
||||||
@ -271,3 +273,61 @@ def test_docstring_signatures():
|
|||||||
def test_str_signature():
|
def test_str_signature():
|
||||||
for enum_type in [m.ScopedEnum, m.UnscopedEnum]:
|
for enum_type in [m.ScopedEnum, m.UnscopedEnum]:
|
||||||
assert enum_type.__str__.__doc__.startswith("__str__")
|
assert enum_type.__str__.__doc__.startswith("__str__")
|
||||||
|
|
||||||
|
|
||||||
|
def test_generated_dunder_methods_pos_only():
|
||||||
|
for enum_type in [m.ScopedEnum, m.UnscopedEnum]:
|
||||||
|
for binary_op in [
|
||||||
|
"__eq__",
|
||||||
|
"__ne__",
|
||||||
|
"__ge__",
|
||||||
|
"__gt__",
|
||||||
|
"__lt__",
|
||||||
|
"__le__",
|
||||||
|
"__and__",
|
||||||
|
"__rand__",
|
||||||
|
# "__or__", # fail with some compilers (__doc__ = "Return self|value.")
|
||||||
|
# "__ror__", # fail with some compilers (__doc__ = "Return value|self.")
|
||||||
|
"__xor__",
|
||||||
|
"__rxor__",
|
||||||
|
"__rxor__",
|
||||||
|
]:
|
||||||
|
method = getattr(enum_type, binary_op, None)
|
||||||
|
if method is not None:
|
||||||
|
assert (
|
||||||
|
re.match(
|
||||||
|
rf"^{binary_op}\(self: [\w\.]+, other: [\w\.]+, /\)",
|
||||||
|
method.__doc__,
|
||||||
|
)
|
||||||
|
is not None
|
||||||
|
)
|
||||||
|
for unary_op in [
|
||||||
|
"__int__",
|
||||||
|
"__index__",
|
||||||
|
"__hash__",
|
||||||
|
"__str__",
|
||||||
|
"__repr__",
|
||||||
|
]:
|
||||||
|
method = getattr(enum_type, unary_op, None)
|
||||||
|
if method is not None:
|
||||||
|
assert (
|
||||||
|
re.match(
|
||||||
|
rf"^{unary_op}\(self: [\w\.]+, /\)",
|
||||||
|
method.__doc__,
|
||||||
|
)
|
||||||
|
is not None
|
||||||
|
)
|
||||||
|
assert (
|
||||||
|
re.match(
|
||||||
|
r"^__getstate__\(self: [\w\.]+, /\)",
|
||||||
|
enum_type.__getstate__.__doc__,
|
||||||
|
)
|
||||||
|
is not None
|
||||||
|
)
|
||||||
|
assert (
|
||||||
|
re.match(
|
||||||
|
r"^__setstate__\(self: [\w\.]+, state: [\w\.]+, /\)",
|
||||||
|
enum_type.__setstate__.__doc__,
|
||||||
|
)
|
||||||
|
is not None
|
||||||
|
)
|
||||||
|
@ -14,26 +14,6 @@
|
|||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
// Classes needed for subclass test.
|
|
||||||
class ArgsSubclass : public py::args {
|
|
||||||
using py::args::args;
|
|
||||||
};
|
|
||||||
class KWArgsSubclass : public py::kwargs {
|
|
||||||
using py::kwargs::kwargs;
|
|
||||||
};
|
|
||||||
namespace pybind11 {
|
|
||||||
namespace detail {
|
|
||||||
template <>
|
|
||||||
struct handle_type_name<ArgsSubclass> {
|
|
||||||
static constexpr auto name = const_name("*Args");
|
|
||||||
};
|
|
||||||
template <>
|
|
||||||
struct handle_type_name<KWArgsSubclass> {
|
|
||||||
static constexpr auto name = const_name("**KWArgs");
|
|
||||||
};
|
|
||||||
} // namespace detail
|
|
||||||
} // namespace pybind11
|
|
||||||
|
|
||||||
TEST_SUBMODULE(kwargs_and_defaults, m) {
|
TEST_SUBMODULE(kwargs_and_defaults, m) {
|
||||||
auto kw_func
|
auto kw_func
|
||||||
= [](int x, int y) { return "x=" + std::to_string(x) + ", y=" + std::to_string(y); };
|
= [](int x, int y) { return "x=" + std::to_string(x) + ", y=" + std::to_string(y); };
|
||||||
@ -345,7 +325,7 @@ TEST_SUBMODULE(kwargs_and_defaults, m) {
|
|||||||
|
|
||||||
// Test support for args and kwargs subclasses
|
// Test support for args and kwargs subclasses
|
||||||
m.def("args_kwargs_subclass_function",
|
m.def("args_kwargs_subclass_function",
|
||||||
[](const ArgsSubclass &args, const KWArgsSubclass &kwargs) {
|
[](const py::Args<std::string> &args, const py::KWArgs<std::string> &kwargs) {
|
||||||
return py::make_tuple(args, kwargs);
|
return py::make_tuple(args, kwargs);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ def test_function_signatures(doc):
|
|||||||
)
|
)
|
||||||
assert (
|
assert (
|
||||||
doc(m.args_kwargs_subclass_function)
|
doc(m.args_kwargs_subclass_function)
|
||||||
== "args_kwargs_subclass_function(*Args, **KWArgs) -> tuple"
|
== "args_kwargs_subclass_function(*args: str, **kwargs: str) -> tuple"
|
||||||
)
|
)
|
||||||
assert (
|
assert (
|
||||||
doc(m.KWClass.foo0)
|
doc(m.KWClass.foo0)
|
||||||
|
@ -294,7 +294,7 @@ TEST_SUBMODULE(methods_and_attributes, m) {
|
|||||||
static_cast<py::str (ExampleMandA::*)(int, int)>(
|
static_cast<py::str (ExampleMandA::*)(int, int)>(
|
||||||
&ExampleMandA::overloaded));
|
&ExampleMandA::overloaded));
|
||||||
})
|
})
|
||||||
.def("__str__", &ExampleMandA::toString)
|
.def("__str__", &ExampleMandA::toString, py::pos_only())
|
||||||
.def_readwrite("value", &ExampleMandA::value);
|
.def_readwrite("value", &ExampleMandA::value);
|
||||||
|
|
||||||
// test_copy_method
|
// test_copy_method
|
||||||
|
@ -19,6 +19,13 @@ NO_DELETER_MSG = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_self_only_pos_only():
|
||||||
|
assert (
|
||||||
|
m.ExampleMandA.__str__.__doc__
|
||||||
|
== "__str__(self: pybind11_tests.methods_and_attributes.ExampleMandA, /) -> str\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_methods_and_attributes():
|
def test_methods_and_attributes():
|
||||||
instance1 = m.ExampleMandA()
|
instance1 = m.ExampleMandA()
|
||||||
instance2 = m.ExampleMandA(32)
|
instance2 = m.ExampleMandA(32)
|
||||||
|
@ -156,6 +156,55 @@ py::handle auxiliaries(T &&r, T2 &&r2) {
|
|||||||
return l.release();
|
return l.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename PyObjectType>
|
||||||
|
PyObjectType convert_to_pyobjecttype(py::object obj);
|
||||||
|
|
||||||
|
template <>
|
||||||
|
PyObject *convert_to_pyobjecttype<PyObject *>(py::object obj) {
|
||||||
|
return obj.release().ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
py::handle convert_to_pyobjecttype<py::handle>(py::object obj) {
|
||||||
|
return obj.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
py::object convert_to_pyobjecttype<py::object>(py::object obj) {
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename PyObjectType>
|
||||||
|
std::string pass_array_return_sum_str_values(const py::array_t<PyObjectType> &objs) {
|
||||||
|
std::string sum_str_values;
|
||||||
|
for (const auto &obj : objs) {
|
||||||
|
sum_str_values += py::str(obj.attr("value"));
|
||||||
|
}
|
||||||
|
return sum_str_values;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename PyObjectType>
|
||||||
|
py::list pass_array_return_as_list(const py::array_t<PyObjectType> &objs) {
|
||||||
|
return objs;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename PyObjectType>
|
||||||
|
py::array_t<PyObjectType> return_array_cpp_loop(const py::list &objs) {
|
||||||
|
py::size_t arr_size = py::len(objs);
|
||||||
|
py::array_t<PyObjectType> arr_from_list(static_cast<py::ssize_t>(arr_size));
|
||||||
|
PyObjectType *data = arr_from_list.mutable_data();
|
||||||
|
for (py::size_t i = 0; i < arr_size; i++) {
|
||||||
|
assert(!data[i]);
|
||||||
|
data[i] = convert_to_pyobjecttype<PyObjectType>(objs[i].attr("value"));
|
||||||
|
}
|
||||||
|
return arr_from_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename PyObjectType>
|
||||||
|
py::array_t<PyObjectType> return_array_from_list(const py::list &objs) {
|
||||||
|
return objs;
|
||||||
|
}
|
||||||
|
|
||||||
// note: declaration at local scope would create a dangling reference!
|
// note: declaration at local scope would create a dangling reference!
|
||||||
static int data_i = 42;
|
static int data_i = 42;
|
||||||
|
|
||||||
@ -520,28 +569,21 @@ TEST_SUBMODULE(numpy_array, sm) {
|
|||||||
sm.def("round_trip_float", [](double d) { return d; });
|
sm.def("round_trip_float", [](double d) { return d; });
|
||||||
|
|
||||||
sm.def("pass_array_pyobject_ptr_return_sum_str_values",
|
sm.def("pass_array_pyobject_ptr_return_sum_str_values",
|
||||||
[](const py::array_t<PyObject *> &objs) {
|
pass_array_return_sum_str_values<PyObject *>);
|
||||||
std::string sum_str_values;
|
sm.def("pass_array_handle_return_sum_str_values",
|
||||||
for (const auto &obj : objs) {
|
pass_array_return_sum_str_values<py::handle>);
|
||||||
sum_str_values += py::str(obj.attr("value"));
|
sm.def("pass_array_object_return_sum_str_values",
|
||||||
}
|
pass_array_return_sum_str_values<py::object>);
|
||||||
return sum_str_values;
|
|
||||||
});
|
|
||||||
|
|
||||||
sm.def("pass_array_pyobject_ptr_return_as_list",
|
sm.def("pass_array_pyobject_ptr_return_as_list", pass_array_return_as_list<PyObject *>);
|
||||||
[](const py::array_t<PyObject *> &objs) -> py::list { return objs; });
|
sm.def("pass_array_handle_return_as_list", pass_array_return_as_list<py::handle>);
|
||||||
|
sm.def("pass_array_object_return_as_list", pass_array_return_as_list<py::object>);
|
||||||
|
|
||||||
sm.def("return_array_pyobject_ptr_cpp_loop", [](const py::list &objs) {
|
sm.def("return_array_pyobject_ptr_cpp_loop", return_array_cpp_loop<PyObject *>);
|
||||||
py::size_t arr_size = py::len(objs);
|
sm.def("return_array_handle_cpp_loop", return_array_cpp_loop<py::handle>);
|
||||||
py::array_t<PyObject *> arr_from_list(static_cast<py::ssize_t>(arr_size));
|
sm.def("return_array_object_cpp_loop", return_array_cpp_loop<py::object>);
|
||||||
PyObject **data = arr_from_list.mutable_data();
|
|
||||||
for (py::size_t i = 0; i < arr_size; i++) {
|
|
||||||
assert(data[i] == nullptr);
|
|
||||||
data[i] = py::cast<PyObject *>(objs[i].attr("value"));
|
|
||||||
}
|
|
||||||
return arr_from_list;
|
|
||||||
});
|
|
||||||
|
|
||||||
sm.def("return_array_pyobject_ptr_from_list",
|
sm.def("return_array_pyobject_ptr_from_list", return_array_from_list<PyObject *>);
|
||||||
[](const py::list &objs) -> py::array_t<PyObject *> { return objs; });
|
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>);
|
||||||
}
|
}
|
||||||
|
@ -629,45 +629,61 @@ def UnwrapPyValueHolder(vhs):
|
|||||||
return [vh.value for vh in vhs]
|
return [vh.value for vh in vhs]
|
||||||
|
|
||||||
|
|
||||||
def test_pass_array_pyobject_ptr_return_sum_str_values_ndarray():
|
PASS_ARRAY_PYOBJECT_RETURN_SUM_STR_VALUES_FUNCTIONS = [
|
||||||
|
m.pass_array_pyobject_ptr_return_sum_str_values,
|
||||||
|
m.pass_array_handle_return_sum_str_values,
|
||||||
|
m.pass_array_object_return_sum_str_values,
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"pass_array", PASS_ARRAY_PYOBJECT_RETURN_SUM_STR_VALUES_FUNCTIONS
|
||||||
|
)
|
||||||
|
def test_pass_array_object_return_sum_str_values_ndarray(pass_array):
|
||||||
# Intentionally all temporaries, do not change.
|
# Intentionally all temporaries, do not change.
|
||||||
assert (
|
assert (
|
||||||
m.pass_array_pyobject_ptr_return_sum_str_values(
|
pass_array(np.array(WrapWithPyValueHolder(-3, "four", 5.0), dtype=object))
|
||||||
np.array(WrapWithPyValueHolder(-3, "four", 5.0), dtype=object)
|
|
||||||
)
|
|
||||||
== "-3four5.0"
|
== "-3four5.0"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_pass_array_pyobject_ptr_return_sum_str_values_list():
|
@pytest.mark.parametrize(
|
||||||
|
"pass_array", PASS_ARRAY_PYOBJECT_RETURN_SUM_STR_VALUES_FUNCTIONS
|
||||||
|
)
|
||||||
|
def test_pass_array_object_return_sum_str_values_list(pass_array):
|
||||||
# Intentionally all temporaries, do not change.
|
# Intentionally all temporaries, do not change.
|
||||||
assert (
|
assert pass_array(WrapWithPyValueHolder(2, "three", -4.0)) == "2three-4.0"
|
||||||
m.pass_array_pyobject_ptr_return_sum_str_values(
|
|
||||||
WrapWithPyValueHolder(2, "three", -4.0)
|
|
||||||
)
|
|
||||||
== "2three-4.0"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def test_pass_array_pyobject_ptr_return_as_list():
|
@pytest.mark.parametrize(
|
||||||
|
"pass_array",
|
||||||
|
[
|
||||||
|
m.pass_array_pyobject_ptr_return_as_list,
|
||||||
|
m.pass_array_handle_return_as_list,
|
||||||
|
m.pass_array_object_return_as_list,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_pass_array_object_return_as_list(pass_array):
|
||||||
# Intentionally all temporaries, do not change.
|
# Intentionally all temporaries, do not change.
|
||||||
assert UnwrapPyValueHolder(
|
assert UnwrapPyValueHolder(
|
||||||
m.pass_array_pyobject_ptr_return_as_list(
|
pass_array(np.array(WrapWithPyValueHolder(-1, "two", 3.0), dtype=object))
|
||||||
np.array(WrapWithPyValueHolder(-1, "two", 3.0), dtype=object)
|
|
||||||
)
|
|
||||||
) == [-1, "two", 3.0]
|
) == [-1, "two", 3.0]
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("return_array_pyobject_ptr", "unwrap"),
|
("return_array", "unwrap"),
|
||||||
[
|
[
|
||||||
(m.return_array_pyobject_ptr_cpp_loop, list),
|
(m.return_array_pyobject_ptr_cpp_loop, list),
|
||||||
|
(m.return_array_handle_cpp_loop, list),
|
||||||
|
(m.return_array_object_cpp_loop, list),
|
||||||
(m.return_array_pyobject_ptr_from_list, UnwrapPyValueHolder),
|
(m.return_array_pyobject_ptr_from_list, UnwrapPyValueHolder),
|
||||||
|
(m.return_array_handle_from_list, UnwrapPyValueHolder),
|
||||||
|
(m.return_array_object_from_list, UnwrapPyValueHolder),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_return_array_pyobject_ptr_cpp_loop(return_array_pyobject_ptr, unwrap):
|
def test_return_array_object_cpp_loop(return_array, unwrap):
|
||||||
# Intentionally all temporaries, do not change.
|
# Intentionally all temporaries, do not change.
|
||||||
arr_from_list = return_array_pyobject_ptr(WrapWithPyValueHolder(6, "seven", -8.0))
|
arr_from_list = return_array(WrapWithPyValueHolder(6, "seven", -8.0))
|
||||||
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]
|
||||||
|
@ -11,6 +11,9 @@
|
|||||||
|
|
||||||
#include "pybind11_tests.h"
|
#include "pybind11_tests.h"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
# define PYBIND11_PACKED(cls) cls __attribute__((__packed__))
|
# define PYBIND11_PACKED(cls) cls __attribute__((__packed__))
|
||||||
#else
|
#else
|
||||||
@ -297,6 +300,15 @@ py::list test_dtype_ctors() {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
py::array_t<T> dispatch_array_increment(py::array_t<T> arr) {
|
||||||
|
py::array_t<T> res(arr.shape(0));
|
||||||
|
for (py::ssize_t i = 0; i < arr.shape(0); ++i) {
|
||||||
|
res.mutable_at(i) = T(arr.at(i) + 1);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
struct A {};
|
struct A {};
|
||||||
struct B {};
|
struct B {};
|
||||||
|
|
||||||
@ -496,6 +508,98 @@ TEST_SUBMODULE(numpy_dtypes, m) {
|
|||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
});
|
});
|
||||||
|
m.def("test_dtype_num_of", []() -> py::list {
|
||||||
|
py::list res;
|
||||||
|
#define TEST_DTYPE(T) res.append(py::make_tuple(py::dtype::of<T>().num(), py::dtype::num_of<T>()));
|
||||||
|
TEST_DTYPE(bool)
|
||||||
|
TEST_DTYPE(char)
|
||||||
|
TEST_DTYPE(unsigned char)
|
||||||
|
TEST_DTYPE(short)
|
||||||
|
TEST_DTYPE(unsigned short)
|
||||||
|
TEST_DTYPE(int)
|
||||||
|
TEST_DTYPE(unsigned int)
|
||||||
|
TEST_DTYPE(long)
|
||||||
|
TEST_DTYPE(unsigned long)
|
||||||
|
TEST_DTYPE(long long)
|
||||||
|
TEST_DTYPE(unsigned long long)
|
||||||
|
TEST_DTYPE(float)
|
||||||
|
TEST_DTYPE(double)
|
||||||
|
TEST_DTYPE(long double)
|
||||||
|
TEST_DTYPE(std::complex<float>)
|
||||||
|
TEST_DTYPE(std::complex<double>)
|
||||||
|
TEST_DTYPE(std::complex<long double>)
|
||||||
|
TEST_DTYPE(int8_t)
|
||||||
|
TEST_DTYPE(uint8_t)
|
||||||
|
TEST_DTYPE(int16_t)
|
||||||
|
TEST_DTYPE(uint16_t)
|
||||||
|
TEST_DTYPE(int32_t)
|
||||||
|
TEST_DTYPE(uint32_t)
|
||||||
|
TEST_DTYPE(int64_t)
|
||||||
|
TEST_DTYPE(uint64_t)
|
||||||
|
#undef TEST_DTYPE
|
||||||
|
return res;
|
||||||
|
});
|
||||||
|
m.def("test_dtype_normalized_num", []() -> py::list {
|
||||||
|
py::list res;
|
||||||
|
#define TEST_DTYPE(NT, T) \
|
||||||
|
res.append(py::make_tuple(py::dtype(py::detail::npy_api::NT).normalized_num(), \
|
||||||
|
py::dtype::num_of<T>()));
|
||||||
|
TEST_DTYPE(NPY_BOOL_, bool)
|
||||||
|
TEST_DTYPE(NPY_BYTE_, char);
|
||||||
|
TEST_DTYPE(NPY_UBYTE_, unsigned char);
|
||||||
|
TEST_DTYPE(NPY_SHORT_, short);
|
||||||
|
TEST_DTYPE(NPY_USHORT_, unsigned short);
|
||||||
|
TEST_DTYPE(NPY_INT_, int);
|
||||||
|
TEST_DTYPE(NPY_UINT_, unsigned int);
|
||||||
|
TEST_DTYPE(NPY_LONG_, long);
|
||||||
|
TEST_DTYPE(NPY_ULONG_, unsigned long);
|
||||||
|
TEST_DTYPE(NPY_LONGLONG_, long long);
|
||||||
|
TEST_DTYPE(NPY_ULONGLONG_, unsigned long long);
|
||||||
|
TEST_DTYPE(NPY_FLOAT_, float);
|
||||||
|
TEST_DTYPE(NPY_DOUBLE_, double);
|
||||||
|
TEST_DTYPE(NPY_LONGDOUBLE_, long double);
|
||||||
|
TEST_DTYPE(NPY_CFLOAT_, std::complex<float>);
|
||||||
|
TEST_DTYPE(NPY_CDOUBLE_, std::complex<double>);
|
||||||
|
TEST_DTYPE(NPY_CLONGDOUBLE_, std::complex<long double>);
|
||||||
|
TEST_DTYPE(NPY_INT8_, int8_t);
|
||||||
|
TEST_DTYPE(NPY_UINT8_, uint8_t);
|
||||||
|
TEST_DTYPE(NPY_INT16_, int16_t);
|
||||||
|
TEST_DTYPE(NPY_UINT16_, uint16_t);
|
||||||
|
TEST_DTYPE(NPY_INT32_, int32_t);
|
||||||
|
TEST_DTYPE(NPY_UINT32_, uint32_t);
|
||||||
|
TEST_DTYPE(NPY_INT64_, int64_t);
|
||||||
|
TEST_DTYPE(NPY_UINT64_, uint64_t);
|
||||||
|
#undef TEST_DTYPE
|
||||||
|
return res;
|
||||||
|
});
|
||||||
|
m.def("test_dtype_switch", [](const py::array &arr) -> py::array {
|
||||||
|
switch (arr.dtype().normalized_num()) {
|
||||||
|
case py::dtype::num_of<int8_t>():
|
||||||
|
return dispatch_array_increment<int8_t>(arr);
|
||||||
|
case py::dtype::num_of<uint8_t>():
|
||||||
|
return dispatch_array_increment<uint8_t>(arr);
|
||||||
|
case py::dtype::num_of<int16_t>():
|
||||||
|
return dispatch_array_increment<int16_t>(arr);
|
||||||
|
case py::dtype::num_of<uint16_t>():
|
||||||
|
return dispatch_array_increment<uint16_t>(arr);
|
||||||
|
case py::dtype::num_of<int32_t>():
|
||||||
|
return dispatch_array_increment<int32_t>(arr);
|
||||||
|
case py::dtype::num_of<uint32_t>():
|
||||||
|
return dispatch_array_increment<uint32_t>(arr);
|
||||||
|
case py::dtype::num_of<int64_t>():
|
||||||
|
return dispatch_array_increment<int64_t>(arr);
|
||||||
|
case py::dtype::num_of<uint64_t>():
|
||||||
|
return dispatch_array_increment<uint64_t>(arr);
|
||||||
|
case py::dtype::num_of<float>():
|
||||||
|
return dispatch_array_increment<float>(arr);
|
||||||
|
case py::dtype::num_of<double>():
|
||||||
|
return dispatch_array_increment<double>(arr);
|
||||||
|
case py::dtype::num_of<long double>():
|
||||||
|
return dispatch_array_increment<long double>(arr);
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("Unsupported dtype");
|
||||||
|
}
|
||||||
|
});
|
||||||
m.def("test_dtype_methods", []() {
|
m.def("test_dtype_methods", []() {
|
||||||
py::list list;
|
py::list list;
|
||||||
auto dt1 = py::dtype::of<int32_t>();
|
auto dt1 = py::dtype::of<int32_t>();
|
||||||
|
@ -188,6 +188,28 @@ def test_dtype(simple_dtype):
|
|||||||
chr(np.dtype(ch).flags) for ch in expected_chars
|
chr(np.dtype(ch).flags) for ch in expected_chars
|
||||||
]
|
]
|
||||||
|
|
||||||
|
for a, b in m.test_dtype_num_of():
|
||||||
|
assert a == b
|
||||||
|
|
||||||
|
for a, b in m.test_dtype_normalized_num():
|
||||||
|
assert a == b
|
||||||
|
|
||||||
|
arr = np.array([4, 84, 21, 36])
|
||||||
|
# Note: "ulong" does not work in NumPy 1.x, so we use "L"
|
||||||
|
assert (m.test_dtype_switch(arr.astype("byte")) == arr + 1).all()
|
||||||
|
assert (m.test_dtype_switch(arr.astype("ubyte")) == arr + 1).all()
|
||||||
|
assert (m.test_dtype_switch(arr.astype("short")) == arr + 1).all()
|
||||||
|
assert (m.test_dtype_switch(arr.astype("ushort")) == arr + 1).all()
|
||||||
|
assert (m.test_dtype_switch(arr.astype("intc")) == arr + 1).all()
|
||||||
|
assert (m.test_dtype_switch(arr.astype("uintc")) == arr + 1).all()
|
||||||
|
assert (m.test_dtype_switch(arr.astype("long")) == arr + 1).all()
|
||||||
|
assert (m.test_dtype_switch(arr.astype("L")) == arr + 1).all()
|
||||||
|
assert (m.test_dtype_switch(arr.astype("longlong")) == arr + 1).all()
|
||||||
|
assert (m.test_dtype_switch(arr.astype("ulonglong")) == arr + 1).all()
|
||||||
|
assert (m.test_dtype_switch(arr.astype("single")) == arr + 1).all()
|
||||||
|
assert (m.test_dtype_switch(arr.astype("double")) == arr + 1).all()
|
||||||
|
assert (m.test_dtype_switch(arr.astype("longdouble")) == arr + 1).all()
|
||||||
|
|
||||||
|
|
||||||
def test_recarray(simple_dtype, packed_dtype):
|
def test_recarray(simple_dtype, packed_dtype):
|
||||||
elements = [(False, 0, 0.0, -0.0), (True, 1, 1.5, -2.5), (False, 2, 3.0, -5.0)]
|
elements = [(False, 0, 0.0, -0.0), (True, 1, 1.5, -2.5), (False, 2, 3.0, -5.0)]
|
||||||
|
@ -93,3 +93,20 @@ def test_roundtrip_simple_cpp_derived():
|
|||||||
# Issue #3062: pickleable base C++ classes can incur object slicing
|
# Issue #3062: pickleable base C++ classes can incur object slicing
|
||||||
# if derived typeid is not registered with pybind11
|
# if derived typeid is not registered with pybind11
|
||||||
assert not m.check_dynamic_cast_SimpleCppDerived(p2)
|
assert not m.check_dynamic_cast_SimpleCppDerived(p2)
|
||||||
|
|
||||||
|
|
||||||
|
def test_new_style_pickle_getstate_pos_only():
|
||||||
|
assert (
|
||||||
|
re.match(
|
||||||
|
r"^__getstate__\(self: [\w\.]+, /\)", m.PickleableNew.__getstate__.__doc__
|
||||||
|
)
|
||||||
|
is not None
|
||||||
|
)
|
||||||
|
if hasattr(m, "PickleableWithDictNew"):
|
||||||
|
assert (
|
||||||
|
re.match(
|
||||||
|
r"^__getstate__\(self: [\w\.]+, /\)",
|
||||||
|
m.PickleableWithDictNew.__getstate__.__doc__,
|
||||||
|
)
|
||||||
|
is not None
|
||||||
|
)
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from pytest import approx # noqa: PT013
|
from pytest import approx # noqa: PT013
|
||||||
|
|
||||||
@ -253,16 +255,12 @@ def test_python_iterator_in_cpp():
|
|||||||
|
|
||||||
def test_iterator_passthrough():
|
def test_iterator_passthrough():
|
||||||
"""#181: iterator passthrough did not compile"""
|
"""#181: iterator passthrough did not compile"""
|
||||||
from pybind11_tests.sequences_and_iterators import iterator_passthrough
|
|
||||||
|
|
||||||
values = [3, 5, 7, 9, 11, 13, 15]
|
values = [3, 5, 7, 9, 11, 13, 15]
|
||||||
assert list(iterator_passthrough(iter(values))) == values
|
assert list(m.iterator_passthrough(iter(values))) == values
|
||||||
|
|
||||||
|
|
||||||
def test_iterator_rvp():
|
def test_iterator_rvp():
|
||||||
"""#388: Can't make iterators via make_iterator() with different r/v policies"""
|
"""#388: Can't make iterators via make_iterator() with different r/v policies"""
|
||||||
import pybind11_tests.sequences_and_iterators as m
|
|
||||||
|
|
||||||
assert list(m.make_iterator_1()) == [1, 2, 3]
|
assert list(m.make_iterator_1()) == [1, 2, 3]
|
||||||
assert list(m.make_iterator_2()) == [1, 2, 3]
|
assert list(m.make_iterator_2()) == [1, 2, 3]
|
||||||
assert not isinstance(m.make_iterator_1(), type(m.make_iterator_2()))
|
assert not isinstance(m.make_iterator_1(), type(m.make_iterator_2()))
|
||||||
@ -274,3 +272,25 @@ def test_carray_iterator():
|
|||||||
arr_h = m.CArrayHolder(*args_gt)
|
arr_h = m.CArrayHolder(*args_gt)
|
||||||
args = list(arr_h)
|
args = list(arr_h)
|
||||||
assert args_gt == args
|
assert args_gt == args
|
||||||
|
|
||||||
|
|
||||||
|
def test_generated_dunder_methods_pos_only():
|
||||||
|
string_map = m.StringMap({"hi": "bye", "black": "white"})
|
||||||
|
for it in (
|
||||||
|
m.make_iterator_1(),
|
||||||
|
m.make_iterator_2(),
|
||||||
|
m.iterator_passthrough(iter([3, 5, 7])),
|
||||||
|
iter(m.Sequence(5)),
|
||||||
|
iter(string_map),
|
||||||
|
string_map.items(),
|
||||||
|
string_map.values(),
|
||||||
|
iter(m.CArrayHolder(*[float(i) for i in range(3)])),
|
||||||
|
):
|
||||||
|
assert (
|
||||||
|
re.match(r"^__iter__\(self: [\w\.]+, /\)", type(it).__iter__.__doc__)
|
||||||
|
is not None
|
||||||
|
)
|
||||||
|
assert (
|
||||||
|
re.match(r"^__next__\(self: [\w\.]+, /\)", type(it).__next__.__doc__)
|
||||||
|
is not None
|
||||||
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user