mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-22 05:05:11 +00:00
nicer type_caster::load() calling conventions
This commit is contained in:
parent
5984baafd0
commit
178c8a899d
@ -903,7 +903,7 @@ its popularity and widespread adoption, pybind11 provides transparent
|
||||
conversion support between Eigen and Scientific Python linear algebra data types.
|
||||
|
||||
Specifically, when including the optional header file :file:`pybind11/eigen.h`,
|
||||
pybind11 will automatically and transparently convert
|
||||
pybind11 will automatically and transparently convert
|
||||
|
||||
1. Static and dynamic Eigen dense vectors and matrices to instances of
|
||||
``numpy.ndarray`` (and vice versa).
|
||||
@ -1250,11 +1250,31 @@ The reverse direction uses the following syntax:
|
||||
MyClass *cls = obj.cast<MyClass *>();
|
||||
|
||||
When conversion fails, both directions throw the exception :class:`cast_error`.
|
||||
It is also possible to call python functions via ``operator()``.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
py::function f = <...>;
|
||||
py::object result_py = f(1234, "hello", some_instance);
|
||||
MyClass &result = result_py.cast<MyClass>();
|
||||
|
||||
The special ``f(*args)`` and ``f(*args, **kwargs)`` syntax is also supported to
|
||||
supply arbitrary argument and keyword lists, although these cannot be mixed
|
||||
with other parameters.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
py::function f = <...>;
|
||||
py::tuple args = py::make_tuple(1234);
|
||||
py::dict kwargs;
|
||||
kwargs["y"] = py::cast(5678);
|
||||
py::object result = f(*args, **kwargs);
|
||||
|
||||
.. seealso::
|
||||
|
||||
The file :file:`example/example2.cpp` contains a complete example that
|
||||
demonstrates passing native Python types in more detail.
|
||||
demonstrates passing native Python types in more detail. The file
|
||||
:file:`example/example11.cpp` discusses usage of ``args`` and ``kwargs``.
|
||||
|
||||
Default arguments revisited
|
||||
===========================
|
||||
@ -1303,6 +1323,36 @@ like so:
|
||||
py::class_<MyClass>("MyClass")
|
||||
.def("myFunction", py::arg("arg") = (SomeType *) nullptr);
|
||||
|
||||
Binding functions that accept arbitrary numbers of arguments and keywords arguments
|
||||
===================================================================================
|
||||
|
||||
Python provides a useful mechanism to define functions that accept arbitrary
|
||||
numbers of arguments and keyword arguments:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
def generic(*args, **kwargs):
|
||||
# .. do something with args and kwargs
|
||||
|
||||
Such functions can also be created using pybind11:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
void generic(py::args args, py::kwargs kwargs) {
|
||||
/// .. do something with args
|
||||
if (kwargs)
|
||||
/// .. do something with kwargs
|
||||
}
|
||||
|
||||
/// Binding code
|
||||
m.def("generic", &generic);
|
||||
|
||||
(See ``example/example11.cpp``). The class ``py::args`` derives from
|
||||
``py::list`` and ``py::kwargs`` derives from ``py::dict`` Note that the
|
||||
``kwargs`` argument is invalid if no keyword arguments were actually provided.
|
||||
Please refer to the other examples for details on how to iterate over these,
|
||||
and on how to cast their entries into C++ objects.
|
||||
|
||||
Partitioning code over multiple extension modules
|
||||
=================================================
|
||||
|
||||
|
@ -9,7 +9,7 @@ To release a new version of pybind11:
|
||||
- ``git push --tags``.
|
||||
- ``python setup.py sdist upload``.
|
||||
- ``python setup.py bdist_wheel upload``.
|
||||
- Update conda-forge
|
||||
- Update conda-forge (https://github.com/conda-forge/pybind11-feedstock)
|
||||
- change version number in ``meta.yml``
|
||||
- update checksum to match the one computed by pypi
|
||||
- Get back to work
|
||||
|
@ -19,11 +19,25 @@ void kw_func4(const std::vector<int> &entries) {
|
||||
std::cout << endl;
|
||||
}
|
||||
|
||||
void call_kw_func(py::function f) {
|
||||
py::object call_kw_func(py::function f) {
|
||||
py::tuple args = py::make_tuple(1234);
|
||||
py::dict kwargs;
|
||||
kwargs["y"] = py::cast(5678);
|
||||
f(*args, **kwargs);
|
||||
return f(*args, **kwargs);
|
||||
}
|
||||
|
||||
void args_function(py::args args) {
|
||||
for (auto item : args)
|
||||
std::cout << "got argument: " << item << std::endl;
|
||||
}
|
||||
|
||||
void args_kwargs_function(py::args args, py::kwargs kwargs) {
|
||||
for (auto item : args)
|
||||
std::cout << "got argument: " << item << std::endl;
|
||||
if (kwargs) {
|
||||
for (auto item : kwargs)
|
||||
std::cout << "got keyword argument: " << item.first << " -> " << item.second << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void init_ex11(py::module &m) {
|
||||
@ -38,4 +52,7 @@ void init_ex11(py::module &m) {
|
||||
|
||||
m.def("kw_func4", &kw_func4, py::arg("myList") = list);
|
||||
m.def("call_kw_func", &call_kw_func);
|
||||
|
||||
m.def("args_function", &args_function);
|
||||
m.def("args_kwargs_function", &args_kwargs_function);
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import pydoc
|
||||
sys.path.append('.')
|
||||
|
||||
from example import kw_func, kw_func2, kw_func3, kw_func4, call_kw_func
|
||||
from example import args_function, args_kwargs_function
|
||||
|
||||
print(pydoc.render_doc(kw_func, "Help on %s"))
|
||||
print(pydoc.render_doc(kw_func2, "Help on %s"))
|
||||
@ -32,6 +33,9 @@ except Exception as e:
|
||||
print("Caught expected exception: " + str(e))
|
||||
|
||||
kw_func4()
|
||||
kw_func4(myList = [1, 2, 3])
|
||||
kw_func4(myList=[1, 2, 3])
|
||||
|
||||
call_kw_func(kw_func2)
|
||||
|
||||
args_function('arg1_value', 'arg2_value', 3)
|
||||
args_kwargs_function('arg1_value', 'arg2_value', arg3='arg3_value', arg4=4)
|
||||
|
@ -33,3 +33,10 @@ Caught expected exception: Incompatible function arguments. The following argume
|
||||
kw_func4: 13 17
|
||||
kw_func4: 1 2 3
|
||||
kw_func(x=1234, y=5678)
|
||||
got argument: arg1_value
|
||||
got argument: arg2_value
|
||||
got argument: 3
|
||||
got argument: arg1_value
|
||||
got argument: arg2_value
|
||||
got keyword argument: arg3 -> arg3_value
|
||||
got keyword argument: arg4 -> 4
|
||||
|
@ -92,7 +92,7 @@ struct function_record {
|
||||
std::vector<argument_record> args;
|
||||
|
||||
/// Pointer to lambda function which converts arguments and performs the actual call
|
||||
handle (*impl) (function_record *, handle, handle) = nullptr;
|
||||
handle (*impl) (function_record *, handle, handle, handle) = nullptr;
|
||||
|
||||
/// Storage for the wrapped function pointer and captured data, if any
|
||||
void *data[3] = { };
|
||||
@ -104,7 +104,16 @@ struct function_record {
|
||||
return_value_policy policy = return_value_policy::automatic;
|
||||
|
||||
/// True if name == '__init__'
|
||||
bool is_constructor = false;
|
||||
bool is_constructor : 1;
|
||||
|
||||
/// True if the function has a '*args' argument
|
||||
bool has_args : 1;
|
||||
|
||||
/// True if the function has a '**kwargs' argument
|
||||
bool has_kwargs : 1;
|
||||
|
||||
/// Number of arguments
|
||||
uint16_t nargs;
|
||||
|
||||
/// Python method object
|
||||
PyMethodDef *def = nullptr;
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "descr.h"
|
||||
#include <array>
|
||||
#include <limits>
|
||||
#include <iostream>
|
||||
|
||||
NAMESPACE_BEGIN(pybind11)
|
||||
NAMESPACE_BEGIN(detail)
|
||||
@ -320,7 +321,9 @@ public:
|
||||
bool load(handle src, bool) {
|
||||
py_type py_value;
|
||||
|
||||
if (std::is_floating_point<T>::value) {
|
||||
if (!src) {
|
||||
return false;
|
||||
} if (std::is_floating_point<T>::value) {
|
||||
py_value = (py_type) PyFloat_AsDouble(src.ptr());
|
||||
} else if (sizeof(T) <= sizeof(long)) {
|
||||
if (std::is_signed<T>::value)
|
||||
@ -394,7 +397,9 @@ public:
|
||||
using type_caster<void_type>::cast;
|
||||
|
||||
bool load(handle h, bool) {
|
||||
if (h.ptr() == Py_None) {
|
||||
if (!h) {
|
||||
return false;
|
||||
} else if (h.ptr() == Py_None) {
|
||||
value = nullptr;
|
||||
return true;
|
||||
}
|
||||
@ -435,7 +440,8 @@ template <> class type_caster<std::nullptr_t> : public type_caster<void_type> {
|
||||
template <> class type_caster<bool> {
|
||||
public:
|
||||
bool load(handle src, bool) {
|
||||
if (src.ptr() == Py_True) { value = true; return true; }
|
||||
if (!src) return false;
|
||||
else if (src.ptr() == Py_True) { value = true; return true; }
|
||||
else if (src.ptr() == Py_False) { value = false; return true; }
|
||||
else return false;
|
||||
}
|
||||
@ -450,7 +456,9 @@ public:
|
||||
bool load(handle src, bool) {
|
||||
object temp;
|
||||
handle load_src = src;
|
||||
if (PyUnicode_Check(load_src.ptr())) {
|
||||
if (!src) {
|
||||
return false;
|
||||
} else if (PyUnicode_Check(load_src.ptr())) {
|
||||
temp = object(PyUnicode_AsUTF8String(load_src.ptr()), false);
|
||||
if (!temp) { PyErr_Clear(); return false; } // UnicodeEncodeError
|
||||
load_src = temp;
|
||||
@ -489,7 +497,9 @@ public:
|
||||
bool load(handle src, bool) {
|
||||
object temp;
|
||||
handle load_src = src;
|
||||
if (!PyUnicode_Check(load_src.ptr())) {
|
||||
if (!src) {
|
||||
return false;
|
||||
} else if (!PyUnicode_Check(load_src.ptr())) {
|
||||
temp = object(PyUnicode_FromObject(load_src.ptr()), false);
|
||||
if (!temp) { PyErr_Clear(); return false; }
|
||||
load_src = temp;
|
||||
@ -527,7 +537,7 @@ protected:
|
||||
template <> class type_caster<char> : public type_caster<std::string> {
|
||||
public:
|
||||
bool load(handle src, bool convert) {
|
||||
if (src.ptr() == Py_None) { return true; }
|
||||
if (src.ptr() == Py_None) return true;
|
||||
return type_caster<std::string>::load(src, convert);
|
||||
}
|
||||
|
||||
@ -550,7 +560,7 @@ public:
|
||||
template <> class type_caster<wchar_t> : public type_caster<std::wstring> {
|
||||
public:
|
||||
bool load(handle src, bool convert) {
|
||||
if (src.ptr() == Py_None) { return true; }
|
||||
if (src.ptr() == Py_None) return true;
|
||||
return type_caster<std::wstring>::load(src, convert);
|
||||
}
|
||||
|
||||
@ -574,7 +584,9 @@ template <typename T1, typename T2> class type_caster<std::pair<T1, T2>> {
|
||||
typedef std::pair<T1, T2> type;
|
||||
public:
|
||||
bool load(handle src, bool convert) {
|
||||
if (!PyTuple_Check(src.ptr()) || PyTuple_Size(src.ptr()) != 2)
|
||||
if (!src)
|
||||
return false;
|
||||
else if (!PyTuple_Check(src.ptr()) || PyTuple_Size(src.ptr()) != 2)
|
||||
return false;
|
||||
return first.load(PyTuple_GET_ITEM(src.ptr(), 0), convert) &&
|
||||
second.load(PyTuple_GET_ITEM(src.ptr(), 1), convert);
|
||||
@ -610,13 +622,41 @@ protected:
|
||||
|
||||
template <typename... Tuple> class type_caster<std::tuple<Tuple...>> {
|
||||
typedef std::tuple<Tuple...> type;
|
||||
typedef std::tuple<typename intrinsic_type<Tuple>::type...> itype;
|
||||
typedef std::tuple<args> args_type;
|
||||
typedef std::tuple<args, kwargs> args_kwargs_type;
|
||||
public:
|
||||
enum { size = sizeof...(Tuple) };
|
||||
|
||||
static constexpr const bool has_kwargs = std::is_same<itype, args_kwargs_type>::value;
|
||||
static constexpr const bool has_args = has_kwargs || std::is_same<itype, args_type>::value;
|
||||
|
||||
bool load(handle src, bool convert) {
|
||||
if (!src || !PyTuple_Check(src.ptr()) || PyTuple_GET_SIZE(src.ptr()) != size)
|
||||
return false;
|
||||
return load(src, convert, typename make_index_sequence<sizeof...(Tuple)>::type());
|
||||
}
|
||||
|
||||
template <typename T = itype, typename std::enable_if<
|
||||
!std::is_same<T, args_type>::value &&
|
||||
!std::is_same<T, args_kwargs_type>::value, int>::type = 0>
|
||||
bool load_args(handle args, handle, bool convert) {
|
||||
return load(args, convert, typename make_index_sequence<sizeof...(Tuple)>::type());
|
||||
}
|
||||
|
||||
template <typename T = itype, typename std::enable_if<std::is_same<T, args_type>::value, int>::type = 0>
|
||||
bool load_args(handle args, handle, bool convert) {
|
||||
std::get<0>(value).load(args, convert);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T = itype, typename std::enable_if<std::is_same<T, args_kwargs_type>::value, int>::type = 0>
|
||||
bool load_args(handle args, handle kwargs, bool convert) {
|
||||
std::get<0>(value).load(args, convert);
|
||||
std::get<1>(value).load(kwargs, convert);
|
||||
return true;
|
||||
}
|
||||
|
||||
static handle cast(const type &src, return_value_policy policy, handle parent) {
|
||||
return cast(src, policy, parent, typename make_index_sequence<size>::type());
|
||||
}
|
||||
@ -655,10 +695,8 @@ protected:
|
||||
}
|
||||
|
||||
template <size_t ... Indices> bool load(handle src, bool convert, index_sequence<Indices...>) {
|
||||
if (!PyTuple_Check(src.ptr()) || PyTuple_Size(src.ptr()) != size)
|
||||
return false;
|
||||
std::array<bool, size> success {{
|
||||
(PyTuple_GET_ITEM(src.ptr(), Indices) != nullptr ? std::get<Indices>(value).load(PyTuple_GET_ITEM(src.ptr(), Indices), convert) : false)...
|
||||
std::get<Indices>(value).load(PyTuple_GET_ITEM(src.ptr(), Indices), convert)...
|
||||
}};
|
||||
(void) convert; /* avoid a warning when the tuple is empty */
|
||||
for (bool r : success)
|
||||
@ -742,14 +780,16 @@ protected:
|
||||
|
||||
template <typename T> struct handle_type_name { static PYBIND11_DESCR name() { return _<T>(); } };
|
||||
template <> struct handle_type_name<bytes> { static PYBIND11_DESCR name() { return _(PYBIND11_BYTES_NAME); } };
|
||||
template <> struct handle_type_name<args> { static PYBIND11_DESCR name() { return _("*args"); } };
|
||||
template <> struct handle_type_name<kwargs> { static PYBIND11_DESCR name() { return _("**kwargs"); } };
|
||||
|
||||
template <typename type>
|
||||
struct type_caster<type, typename std::enable_if<std::is_base_of<handle, type>::value>::type> {
|
||||
public:
|
||||
template <typename T = type, typename std::enable_if<std::is_same<T, handle>::value, int>::type = 0>
|
||||
bool load(handle src, bool /* convert */) { value = src; return value.check(); }
|
||||
template <typename T = type, typename std::enable_if<!std::is_base_of<object, T>::value, int>::type = 0>
|
||||
bool load(handle src, bool /* convert */) { value = type(src); return value.check(); }
|
||||
|
||||
template <typename T = type, typename std::enable_if<!std::is_same<T, handle>::value, int>::type = 0>
|
||||
template <typename T = type, typename std::enable_if<std::is_base_of<object, T>::value, int>::type = 0>
|
||||
bool load(handle src, bool /* convert */) { value = type(src, true); return value.check(); }
|
||||
|
||||
static handle cast(const handle &src, return_value_policy /* policy */, handle /* parent */) {
|
||||
@ -768,7 +808,9 @@ template <typename T> T cast(handle handle) {
|
||||
return conv.operator typename type_caster::template cast_op_type<T>();
|
||||
}
|
||||
|
||||
template <typename T> object cast(const T &value, return_value_policy policy = return_value_policy::automatic_reference, handle parent = handle()) {
|
||||
template <typename T> object cast(const T &value,
|
||||
return_value_policy policy = return_value_policy::automatic_reference,
|
||||
handle parent = handle()) {
|
||||
if (policy == return_value_policy::automatic)
|
||||
policy = std::is_pointer<T>::value ? return_value_policy::take_ownership : return_value_policy::copy;
|
||||
else if (policy == return_value_policy::automatic_reference)
|
||||
@ -808,14 +850,14 @@ template <typename... Args> object handle::call(Args &&... args) const {
|
||||
return operator()(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
inline object handle::operator()(detail::args args) const {
|
||||
inline object handle::operator()(detail::args_proxy args) const {
|
||||
object result(PyObject_CallObject(m_ptr, args.ptr()), false);
|
||||
if (!result)
|
||||
throw error_already_set();
|
||||
return result;
|
||||
}
|
||||
|
||||
inline object handle::operator()(detail::args args, detail::kwargs kwargs) const {
|
||||
inline object handle::operator()(detail::args_proxy args, detail::kwargs_proxy kwargs) const {
|
||||
object result(PyObject_Call(m_ptr, args.ptr(), kwargs.ptr()), false);
|
||||
if (!result)
|
||||
throw error_already_set();
|
||||
|
@ -142,7 +142,7 @@ NAMESPACE_BEGIN(pybind11)
|
||||
typedef Py_ssize_t ssize_t;
|
||||
|
||||
/// Approach used to cast a previously unknown C++ instance into a Python object
|
||||
enum class return_value_policy : int {
|
||||
enum class return_value_policy : uint8_t {
|
||||
/** This is the default return value policy, which falls back to the policy
|
||||
return_value_policy::take_ownership when the return value is a pointer.
|
||||
Otherwise, it uses return_value::move or return_value::copy for rvalue
|
||||
|
@ -26,6 +26,8 @@ NAMESPACE_BEGIN(detail)
|
||||
template <typename T> class type_caster<std::complex<T>> {
|
||||
public:
|
||||
bool load(handle src, bool) {
|
||||
if (!src)
|
||||
return false;
|
||||
Py_complex result = PyComplex_AsCComplex(src.ptr());
|
||||
if (result.real == -1.0 && PyErr_Occurred()) {
|
||||
PyErr_Clear();
|
||||
|
@ -138,6 +138,9 @@ struct type_caster<Type, typename std::enable_if<is_eigen_sparse<Type>::value>::
|
||||
static constexpr bool rowMajor = Type::Flags & Eigen::RowMajorBit;
|
||||
|
||||
bool load(handle src, bool) {
|
||||
if (!src)
|
||||
return false;
|
||||
|
||||
object obj(src, true);
|
||||
object sparse_module = module::import("scipy.sparse");
|
||||
object matrix_type = sparse_module.attr(
|
||||
|
@ -92,11 +92,11 @@ protected:
|
||||
typename detail::intrinsic_type<Return>::type>::type> cast_out;
|
||||
|
||||
/* Dispatch code which converts function arguments and performs the actual function call */
|
||||
rec->impl = [](detail::function_record *rec, handle args, handle parent) -> handle {
|
||||
rec->impl = [](detail::function_record *rec, handle args, handle kwargs, handle parent) -> handle {
|
||||
cast_in args_converter;
|
||||
|
||||
/* Try to cast the function arguments into the C++ domain */
|
||||
if (!args_converter.load(args, true))
|
||||
if (!args_converter.load_args(args, kwargs, true))
|
||||
return PYBIND11_TRY_NEXT_OVERLOAD;
|
||||
|
||||
/* Invoke call policy pre-call hook */
|
||||
@ -106,7 +106,7 @@ protected:
|
||||
capture *cap = (capture *) (sizeof(capture) <= sizeof(rec->data)
|
||||
? &rec->data : rec->data[0]);
|
||||
|
||||
/* Perform the functionc all */
|
||||
/* Perform the functioncall */
|
||||
handle result = cast_out::cast(args_converter.template call<Return>(cap->f),
|
||||
rec->policy, parent);
|
||||
|
||||
@ -125,6 +125,9 @@ protected:
|
||||
|
||||
/* Register the function with Python from generic (non-templated) code */
|
||||
initialize_generic(rec, signature.text(), signature.types(), sizeof...(Args));
|
||||
|
||||
if (cast_in::has_args) rec->has_args = true;
|
||||
if (cast_in::has_kwargs) rec->has_kwargs = true;
|
||||
}
|
||||
|
||||
/// Register a function call with Python (generic non-templated code goes here)
|
||||
@ -204,9 +207,12 @@ protected:
|
||||
std::to_string(args) + " arguments, but " + std::to_string(rec->args.size()) +
|
||||
" pybind11::arg entries were specified!");
|
||||
|
||||
rec->is_constructor = !strcmp(rec->name, "__init__");
|
||||
rec->signature = strdup(signature.c_str());
|
||||
rec->args.shrink_to_fit();
|
||||
rec->is_constructor = !strcmp(rec->name, "__init__");
|
||||
rec->has_args = false;
|
||||
rec->has_kwargs = false;
|
||||
rec->nargs = args;
|
||||
|
||||
#if PY_MAJOR_VERSION < 3
|
||||
if (rec->sibling && PyMethod_Check(rec->sibling.ptr()))
|
||||
@ -325,15 +331,15 @@ protected:
|
||||
*it = overloads;
|
||||
|
||||
/* Need to know how many arguments + keyword arguments there are to pick the right overload */
|
||||
int nargs = (int) PyTuple_Size(args),
|
||||
nkwargs = kwargs ? (int) PyDict_Size(kwargs) : 0;
|
||||
size_t nargs = PyTuple_GET_SIZE(args),
|
||||
nkwargs = kwargs ? PyDict_Size(kwargs) : 0;
|
||||
|
||||
handle parent = nargs > 0 ? PyTuple_GetItem(args, 0) : nullptr,
|
||||
handle parent = nargs > 0 ? PyTuple_GET_ITEM(args, 0) : nullptr,
|
||||
result = PYBIND11_TRY_NEXT_OVERLOAD;
|
||||
try {
|
||||
for (; it != nullptr; it = it->next) {
|
||||
tuple args_(args, true);
|
||||
int kwargs_consumed = 0;
|
||||
size_t kwargs_consumed = 0;
|
||||
|
||||
/* For each overload:
|
||||
1. If the required list of arguments is longer than the
|
||||
@ -342,10 +348,11 @@ protected:
|
||||
2. Ensure that all keyword arguments were "consumed"
|
||||
3. Call the function call dispatcher (function_record::impl)
|
||||
*/
|
||||
|
||||
if (nargs < (int) it->args.size()) {
|
||||
args_ = tuple(it->args.size());
|
||||
for (int i = 0; i < nargs; ++i) {
|
||||
size_t nargs_ = nargs;
|
||||
if (nargs < it->args.size()) {
|
||||
nargs_ = it->args.size();
|
||||
args_ = tuple(nargs_);
|
||||
for (size_t i = 0; i < nargs; ++i) {
|
||||
handle item = PyTuple_GET_ITEM(args, i);
|
||||
PyTuple_SET_ITEM(args_.ptr(), i, item.inc_ref().ptr());
|
||||
}
|
||||
@ -368,15 +375,16 @@ protected:
|
||||
if (value) {
|
||||
PyTuple_SET_ITEM(args_.ptr(), index, value.inc_ref().ptr());
|
||||
} else {
|
||||
kwargs_consumed = -1; /* definite failure */
|
||||
kwargs_consumed = (size_t) -1; /* definite failure */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (kwargs_consumed == nkwargs)
|
||||
result = it->impl(it, args_, parent);
|
||||
if ((kwargs_consumed == nkwargs || it->has_kwargs) &&
|
||||
(nargs_ == it->nargs || it->has_args))
|
||||
result = it->impl(it, args_, kwargs, parent);
|
||||
} catch (cast_error &) {
|
||||
result = PYBIND11_TRY_NEXT_OVERLOAD;
|
||||
}
|
||||
@ -420,7 +428,7 @@ protected:
|
||||
if (overloads->is_constructor) {
|
||||
/* When a constructor ran successfully, the corresponding
|
||||
holder type (e.g. std::unique_ptr) must still be initialized. */
|
||||
PyObject *inst = PyTuple_GetItem(args, 0);
|
||||
PyObject *inst = PyTuple_GET_ITEM(args, 0);
|
||||
auto tinfo = detail::get_type_info(Py_TYPE(inst));
|
||||
tinfo->init_holder(inst, nullptr);
|
||||
}
|
||||
|
@ -16,12 +16,8 @@
|
||||
NAMESPACE_BEGIN(pybind11)
|
||||
|
||||
/* A few forward declarations */
|
||||
class object;
|
||||
class str;
|
||||
class object;
|
||||
class dict;
|
||||
class iterator;
|
||||
namespace detail { class accessor; class args; class kwargs; }
|
||||
class object; class str; class object; class dict; class iterator;
|
||||
namespace detail { class accessor; class args_proxy; class kwargs_proxy; }
|
||||
|
||||
/// Holds a reference to a Python object (no reference counting)
|
||||
class handle {
|
||||
@ -43,17 +39,17 @@ public:
|
||||
inline detail::accessor attr(const char *key) const;
|
||||
inline pybind11::str str() const;
|
||||
template <typename T> T cast() const;
|
||||
template <typename ... Args>
|
||||
template <typename ... Args>
|
||||
[[deprecated("call(...) was deprecated in favor of operator()(...)")]]
|
||||
object call(Args&&... args) const;
|
||||
template <typename ... Args> object operator()(Args&&... args) const;
|
||||
inline object operator()(detail::args args) const;
|
||||
inline object operator()(detail::args args, detail::kwargs kwargs) const;
|
||||
inline object operator()(detail::args_proxy args) const;
|
||||
inline object operator()(detail::args_proxy f_args, detail::kwargs_proxy kwargs) const;
|
||||
operator bool() const { return m_ptr != nullptr; }
|
||||
bool operator==(const handle &h) const { return m_ptr == h.m_ptr; }
|
||||
bool operator!=(const handle &h) const { return m_ptr != h.m_ptr; }
|
||||
bool check() const { return m_ptr != nullptr; }
|
||||
inline detail::args operator*() const;
|
||||
inline detail::args_proxy operator*() const;
|
||||
protected:
|
||||
PyObject *m_ptr;
|
||||
};
|
||||
@ -218,17 +214,6 @@ private:
|
||||
ssize_t pos = 0;
|
||||
};
|
||||
|
||||
class kwargs : public handle {
|
||||
public:
|
||||
kwargs(handle h) : handle(h) { }
|
||||
};
|
||||
|
||||
class args : public handle {
|
||||
public:
|
||||
args(handle h) : handle(h) { }
|
||||
kwargs operator*() const { return kwargs(*this); }
|
||||
};
|
||||
|
||||
inline bool PyIterable_Check(PyObject *obj) {
|
||||
PyObject *iter = PyObject_GetIter(obj);
|
||||
if (iter) {
|
||||
@ -239,20 +224,32 @@ inline bool PyIterable_Check(PyObject *obj) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline bool PyNone_Check(PyObject *o) { return o == Py_None; }
|
||||
|
||||
inline bool PyUnicode_Check_Permissive(PyObject *o) { return PyUnicode_Check(o) || PYBIND11_BYTES_CHECK(o); }
|
||||
|
||||
class kwargs_proxy : public handle {
|
||||
public:
|
||||
kwargs_proxy(handle h) : handle(h) { }
|
||||
};
|
||||
|
||||
class args_proxy : public handle {
|
||||
public:
|
||||
args_proxy(handle h) : handle(h) { }
|
||||
kwargs_proxy operator*() const { return kwargs_proxy(*this); }
|
||||
};
|
||||
|
||||
NAMESPACE_END(detail)
|
||||
|
||||
#define PYBIND11_OBJECT_CVT(Name, Parent, CheckFun, CvtStmt) \
|
||||
Name(const handle &h, bool borrowed) : Parent(h, borrowed) { CvtStmt; } \
|
||||
Name(const object& o): Parent(o) { CvtStmt; } \
|
||||
Name(object&& o) noexcept : Parent(std::move(o)) { CvtStmt; } \
|
||||
Name& operator=(object&& o) noexcept { (void) object::operator=(std::move(o)); CvtStmt; return *this; } \
|
||||
Name& operator=(const object& o) { return static_cast<Name&>(object::operator=(o)); CvtStmt; } \
|
||||
bool check() const { return m_ptr != nullptr && (bool) CheckFun(m_ptr); }
|
||||
public: \
|
||||
Name(const handle &h, bool borrowed) : Parent(h, borrowed) { CvtStmt; } \
|
||||
Name(const object& o): Parent(o) { CvtStmt; } \
|
||||
Name(object&& o) noexcept : Parent(std::move(o)) { CvtStmt; } \
|
||||
Name& operator=(object&& o) noexcept { (void) object::operator=(std::move(o)); CvtStmt; return *this; } \
|
||||
Name& operator=(const object& o) { return static_cast<Name&>(object::operator=(o)); CvtStmt; } \
|
||||
bool check() const { return m_ptr != nullptr && (bool) CheckFun(m_ptr); }
|
||||
|
||||
#define PYBIND11_OBJECT(Name, Parent, CheckFun) \
|
||||
PYBIND11_OBJECT_CVT(Name, Parent, CheckFun, )
|
||||
@ -332,7 +329,7 @@ inline detail::accessor handle::attr(handle key) const { return detail::accessor
|
||||
inline detail::accessor handle::attr(const char *key) const { return detail::accessor(ptr(), key, true); }
|
||||
inline iterator handle::begin() const { return iterator(PyObject_GetIter(ptr()), false); }
|
||||
inline iterator handle::end() const { return iterator(nullptr, false); }
|
||||
inline detail::args handle::operator*() const { return detail::args(*this); }
|
||||
inline detail::args_proxy handle::operator*() const { return detail::args_proxy(*this); }
|
||||
|
||||
class str : public object {
|
||||
public:
|
||||
@ -520,6 +517,9 @@ public:
|
||||
void append(const object &object) const { PyList_Append(m_ptr, object.ptr()); }
|
||||
};
|
||||
|
||||
class args : public list { PYBIND11_OBJECT_DEFAULT(args, list, PyList_Check) };
|
||||
class kwargs : public dict { PYBIND11_OBJECT_DEFAULT(kwargs, dict, PyDict_Check) };
|
||||
|
||||
class set : public object {
|
||||
public:
|
||||
PYBIND11_OBJECT(set, object, PySet_Check)
|
||||
|
Loading…
Reference in New Issue
Block a user