Commit 48548ea4 by Wenzel Jakob

general cleanup of the codebase

- new pybind11::base<> attribute to indicate a subclass relationship
- unified infrastructure for parsing variadic arguments in class_ and cpp_function
- use 'handle' and 'object' more consistently everywhere
parent 9180519d
...@@ -80,6 +80,7 @@ include_directories(${PYTHON_INCLUDE_DIR}) ...@@ -80,6 +80,7 @@ include_directories(${PYTHON_INCLUDE_DIR})
include_directories(include) include_directories(include)
set(PYBIND11_HEADERS set(PYBIND11_HEADERS
include/pybind11/attr.h
include/pybind11/cast.h include/pybind11/cast.h
include/pybind11/common.h include/pybind11/common.h
include/pybind11/complex.h include/pybind11/complex.h
...@@ -167,7 +168,7 @@ elseif (UNIX) ...@@ -167,7 +168,7 @@ elseif (UNIX)
# Strip unnecessary sections of the binary on Linux/Mac OS # Strip unnecessary sections of the binary on Linux/Mac OS
if(APPLE) if(APPLE)
set_target_properties(example PROPERTIES MACOSX_RPATH ".") set_target_properties(example PROPERTIES MACOSX_RPATH ".")
set_target_properties(example PROPERTIES LINK_FLAGS "-undefined dynamic_lookup -dead_strip") set_target_properties(example PROPERTIES LINK_FLAGS "-undefined dynamic_lookup ")
if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG) if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG)
add_custom_command(TARGET example POST_BUILD COMMAND strip -u -r ${PROJECT_SOURCE_DIR}/example/example.so) add_custom_command(TARGET example POST_BUILD COMMAND strip -u -r ${PROJECT_SOURCE_DIR}/example/example.so)
endif() endif()
......
...@@ -925,7 +925,7 @@ If not available, the signature may not be very helpful, e.g.: ...@@ -925,7 +925,7 @@ If not available, the signature may not be very helpful, e.g.:
FUNCTIONS FUNCTIONS
... ...
| myFunction(...) | myFunction(...)
| Signature : (MyClass, arg : SomeType = <SomeType object at 0x101b7b080>) -> None | Signature : (MyClass, arg : SomeType = <SomeType object at 0x101b7b080>) -> NoneType
... ...
The first way of addressing this is by defining ``SomeType.__repr__``. The first way of addressing this is by defining ``SomeType.__repr__``.
......
...@@ -5,15 +5,19 @@ Changelog ...@@ -5,15 +5,19 @@ Changelog
1.2 (not yet released) 1.2 (not yet released)
-------------------------- --------------------------
* Optional: efficient generation of function signatures at compile time using C++14 * Optional: efficient generation of function signatures at compile time using C++14
* Switched to a simpler and more general way of dealing with function default arguments * Switched to a simpler and more general way of dealing with function default
Unused keyword arguments in function calls are now detected and cause errors as expected arguments. Unused keyword arguments in function calls are now detected and
cause errors as expected
* New ``keep_alive`` call policy analogous to Boost.Python's ``with_custodian_and_ward`` * New ``keep_alive`` call policy analogous to Boost.Python's ``with_custodian_and_ward``
* New ``pybind11::base<>`` attribute to indicate a subclass relationship
* Improved interface for RAII type wrappers in ``pytypes.h`` * Improved interface for RAII type wrappers in ``pytypes.h``
* Use RAII type wrappers consistently within pybind11 itself. This * Use RAII type wrappers consistently within pybind11 itself. This
fixes various potential refcount leaks when exceptions occur fixes various potential refcount leaks when exceptions occur
* Added new ``bytes`` RAII type wrapper (maps to ``string`` in Python 2.7). * Added new ``bytes`` RAII type wrapper (maps to ``string`` in Python 2.7).
* Made handle and related RAII classes const correct * Made handle and related RAII classes const correct, using them more
consistently everywhere now
* Got rid of the ugly ``__pybind11__`` attributes on the Python side---they are * Got rid of the ugly ``__pybind11__`` attributes on the Python side---they are
now stored in a C++ hash table that is not visible in Python now stored in a C++ hash table that is not visible in Python
* Fixed refcount leaks involving NumPy arrays and bound functions * Fixed refcount leaks involving NumPy arrays and bound functions
...@@ -21,7 +25,9 @@ Changelog ...@@ -21,7 +25,9 @@ Changelog
* Removed an unnecessary copy operation in ``pybind11::vectorize`` * Removed an unnecessary copy operation in ``pybind11::vectorize``
* Fixed naming clashes when both pybind11 and NumPy headers are included * Fixed naming clashes when both pybind11 and NumPy headers are included
* Added conversions for additional exception types * Added conversions for additional exception types
* Documentation improvements (using multiple extension modules, smart pointers, other minor clarifications) * Documentation improvements (using multiple extension modules, smart pointers,
other minor clarifications)
* unified infrastructure for parsing variadic arguments in class_ and cpp_function
* Fixed license text (was: ZLIB, should have been: 3-clause BSD) * Fixed license text (was: ZLIB, should have been: 3-clause BSD)
* Python 3.2 compatibility * Python 3.2 compatibility
......
...@@ -177,9 +177,22 @@ inheritance relationship: ...@@ -177,9 +177,22 @@ inheritance relationship:
std::string bark() const { return "woof!"; } std::string bark() const { return "woof!"; }
}; };
To capture the hierarchical relationship in pybind11, we must assign a name to There are two different ways of indicating a hierarchical relationship to
the ``Pet`` :class:`class_` instance and reference it when binding the ``Dog`` pybind11: the first is by specifying the C++ base class explicitly during
class. construction using the ``base`` attribute:
.. code-block:: cpp
py::class_<Pet>(m, "Pet")
.def(py::init<const std::string &>())
.def_readwrite("name", &Pet::name);
py::class_<Dog>(m, "Dog", py::base<Pet>() /* <- specify C++ parent type */)
.def(py::init<const std::string &>())
.def("bark", &Dog::bark);
Alternatively, we can also assign a name to the previously bound ``Pet``
:class:`class_` object and reference it when binding the ``Dog`` class:
.. code-block:: cpp .. code-block:: cpp
...@@ -187,11 +200,12 @@ class. ...@@ -187,11 +200,12 @@ class.
pet.def(py::init<const std::string &>()) pet.def(py::init<const std::string &>())
.def_readwrite("name", &Pet::name); .def_readwrite("name", &Pet::name);
py::class_<Dog>(m, "Dog", pet /* <- specify parent */) py::class_<Dog>(m, "Dog", pet /* <- specify Python parent type */)
.def(py::init<const std::string &>()) .def(py::init<const std::string &>())
.def("bark", &Dog::bark); .def("bark", &Dog::bark);
Instances then expose fields and methods of both types: Functionality-wise, both approaches are completely equivalent. Afterwards,
instances will expose fields and methods of both types:
.. code-block:: python .. code-block:: python
...@@ -242,14 +256,14 @@ The overload signatures are also visible in the method's docstring: ...@@ -242,14 +256,14 @@ The overload signatures are also visible in the method's docstring:
| Methods defined here: | Methods defined here:
| |
| __init__(...) | __init__(...)
| Signature : (Pet, str, int) -> None | Signature : (Pet, str, int) -> NoneType
| |
| set(...) | set(...)
| 1. Signature : (Pet, int) -> None | 1. Signature : (Pet, int) -> NoneType
| |
| Set the pet's age | Set the pet's age
| |
| 2. Signature : (Pet, str) -> None | 2. Signature : (Pet, str) -> NoneType
| |
| Set the pet's name | Set the pet's name
......
...@@ -30,10 +30,14 @@ and that the pybind11 repository is located in a subdirectory named :file:`pybin ...@@ -30,10 +30,14 @@ and that the pybind11 repository is located in a subdirectory named :file:`pybin
# Try to autodetect Python (can be overridden manually if needed) # Try to autodetect Python (can be overridden manually if needed)
set(Python_ADDITIONAL_VERSIONS 3.4 3.5 3.6 3.7) set(Python_ADDITIONAL_VERSIONS 3.4 3.5 3.6 3.7)
if (NOT ${PYBIND11_PYTHON_VERSION} STREQUAL "") if (NOT ${PYBIND11_PYTHON_VERSION} STREQUAL "")
find_package(PythonLibs ${PYBIND11_PYTHON_VERSION} EXACT REQUIRED) find_package(PythonLibs ${PYBIND11_PYTHON_VERSION} EXACT)
if (NOT PythonLibs_FOUND)
find_package(PythonLibs ${PYBIND11_PYTHON_VERSION} REQUIRED)
endif()
else() else()
find_package(PythonLibs REQUIRED) find_package(PythonLibs REQUIRED)
endif() endif()
find_package(PythonInterp ${PYTHONLIBS_VERSION_STRING} EXACT REQUIRED)
# Uncomment the following line if you will also require a matching Python interpreter # Uncomment the following line if you will also require a matching Python interpreter
# find_package(PythonInterp ${PYTHONLIBS_VERSION_STRING} EXACT REQUIRED) # find_package(PythonInterp ${PYTHONLIBS_VERSION_STRING} EXACT REQUIRED)
...@@ -115,7 +119,7 @@ and that the pybind11 repository is located in a subdirectory named :file:`pybin ...@@ -115,7 +119,7 @@ and that the pybind11 repository is located in a subdirectory named :file:`pybin
# Strip unnecessary sections of the binary on Linux/Mac OS # Strip unnecessary sections of the binary on Linux/Mac OS
if(APPLE) if(APPLE)
set_target_properties(example PROPERTIES MACOSX_RPATH ".") set_target_properties(example PROPERTIES MACOSX_RPATH ".")
set_target_properties(example PROPERTIES LINK_FLAGS "-undefined dynamic_lookup -dead_strip") set_target_properties(example PROPERTIES LINK_FLAGS "-undefined dynamic_lookup ")
if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG) if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG)
add_custom_command(TARGET example POST_BUILD COMMAND strip -u -r ${PROJECT_BINARY_DIR}/example.so) add_custom_command(TARGET example POST_BUILD COMMAND strip -u -r ${PROJECT_BINARY_DIR}/example.so)
endif() endif()
......
...@@ -63,17 +63,19 @@ Without reference counting ...@@ -63,17 +63,19 @@ Without reference counting
Return the ``PyObject *`` underlying a :class:`handle`. Return the ``PyObject *`` underlying a :class:`handle`.
.. function:: void handle::inc_ref() const .. function:: const handle& handle::inc_ref() const
Manually increase the reference count of the Python object. Usually, it is Manually increase the reference count of the Python object. Usually, it is
preferable to use the :class:`object` class which derives from preferable to use the :class:`object` class which derives from
:class:`handle` and calls this function automatically. :class:`handle` and calls this function automatically. Returns a reference
to itself.
.. function:: void handle::dec_ref() const .. function:: const handle& handle::dec_ref() const
Manually decrease the reference count of the Python object. Usually, it is Manually decrease the reference count of the Python object. Usually, it is
preferable to use the :class:`object` class which derives from preferable to use the :class:`object` class which derives from
:class:`handle` and calls this function automatically. :class:`handle` and calls this function automatically. Returns a reference
to itself.
.. function:: void handle::ref_count() const .. function:: void handle::ref_count() const
...@@ -167,11 +169,11 @@ With reference counting ...@@ -167,11 +169,11 @@ With reference counting
Move constructor; steals the object from ``other`` and preserves its Move constructor; steals the object from ``other`` and preserves its
reference count. reference count.
.. function:: PyObject* object::release() .. function:: handle object::release()
Release ownership of underlying ``PyObject *``. Returns raw Python object Resets the internal pointer to ``nullptr`` without without decreasing the
pointer without decreasing its reference count and resets handle to object's reference count. The function returns a raw handle to the original
``nullptr``-valued pointer. Python object.
.. function:: object::~object() .. function:: object::~object()
......
...@@ -29,6 +29,11 @@ public: ...@@ -29,6 +29,11 @@ public:
void bark() const { std::cout << "Woof!" << std::endl; } void bark() const { std::cout << "Woof!" << std::endl; }
}; };
class Rabbit : public Pet {
public:
Rabbit(const std::string &name) : Pet(name, "parrot") {}
};
void pet_print(const Pet &pet) { void pet_print(const Pet &pet) {
std::cout << pet.name() + " is a " + pet.species() << std::endl; std::cout << pet.name() + " is a " + pet.species() << std::endl;
} }
...@@ -62,9 +67,14 @@ void init_ex5(py::module &m) { ...@@ -62,9 +67,14 @@ void init_ex5(py::module &m) {
.def("name", &Pet::name) .def("name", &Pet::name)
.def("species", &Pet::species); .def("species", &Pet::species);
/* One way of declaring a subclass relationship: reference parent's class_ object */
py::class_<Dog>(m, "Dog", pet_class) py::class_<Dog>(m, "Dog", pet_class)
.def(py::init<std::string>()); .def(py::init<std::string>());
/* Another way of declaring a subclass relationship: reference parent's C++ type */
py::class_<Rabbit>(m, "Rabbit", py::base<Pet>())
.def(py::init<std::string>());
m.def("pet_print", pet_print); m.def("pet_print", pet_print);
m.def("dog_bark", dog_bark); m.def("dog_bark", dog_bark);
......
...@@ -5,11 +5,15 @@ sys.path.append('.') ...@@ -5,11 +5,15 @@ sys.path.append('.')
from example import Pet from example import Pet
from example import Dog from example import Dog
from example import Rabbit
from example import dog_bark from example import dog_bark
from example import pet_print from example import pet_print
polly = Pet('Polly', 'parrot') polly = Pet('Polly', 'parrot')
molly = Dog('Molly') molly = Dog('Molly')
roger = Rabbit('Rabbit')
print(roger.name() + " is a " + roger.species())
pet_print(roger)
print(polly.name() + " is a " + polly.species()) print(polly.name() + " is a " + polly.species())
pet_print(polly) pet_print(polly)
print(molly.name() + " is a " + molly.species()) print(molly.name() + " is a " + molly.species())
......
Rabbit is a parrot
Polly is a parrot Polly is a parrot
Polly is a parrot
Molly is a dog
Molly is a dog Molly is a dog
Woof! Woof!
The following error is expected: Incompatible function arguments. The following argument types are supported:
1. (Dog) -> NoneType
Callback function 1 called!
False
Callback function 2 called : Hello, x, True, 5
5
func(43) = 44
func(43) = 44 func(43) = 44
Payload constructor Payload constructor
Payload copy constructor Payload copy constructor
...@@ -18,3 +9,14 @@ Payload move constructor ...@@ -18,3 +9,14 @@ Payload move constructor
Payload destructor Payload destructor
Payload destructor Payload destructor
Payload destructor Payload destructor
Rabbit is a parrot
Polly is a parrot
Molly is a dog
The following error is expected: Incompatible function arguments. The following argument types are supported:
1. (example.Dog) -> NoneType
Callback function 1 called!
False
Callback function 2 called : Hello, x, True, 5
5
func(43) = 44
...@@ -73,6 +73,7 @@ ...@@ -73,6 +73,7 @@
#include <memory> #include <memory>
#if PY_MAJOR_VERSION >= 3 /// Compatibility macros for various Python versions #if PY_MAJOR_VERSION >= 3 /// Compatibility macros for various Python versions
#define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyInstanceMethod_New(ptr)
#define PYBIND11_BYTES_CHECK PyBytes_Check #define PYBIND11_BYTES_CHECK PyBytes_Check
#define PYBIND11_BYTES_FROM_STRING PyBytes_FromString #define PYBIND11_BYTES_FROM_STRING PyBytes_FromString
#define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyBytes_FromStringAndSize #define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyBytes_FromStringAndSize
...@@ -89,6 +90,7 @@ ...@@ -89,6 +90,7 @@
#define PYBIND11_PLUGIN_IMPL(name) \ #define PYBIND11_PLUGIN_IMPL(name) \
extern "C" PYBIND11_EXPORT PyObject *PyInit_##name() extern "C" PYBIND11_EXPORT PyObject *PyInit_##name()
#else #else
#define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyMethod_New(ptr, nullptr, class_)
#define PYBIND11_BYTES_CHECK PyString_Check #define PYBIND11_BYTES_CHECK PyString_Check
#define PYBIND11_BYTES_FROM_STRING PyString_FromString #define PYBIND11_BYTES_FROM_STRING PyString_FromString
#define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyString_FromStringAndSize #define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyString_FromStringAndSize
...@@ -200,16 +202,6 @@ template <typename type, typename holder_type = std::unique_ptr<type>> struct in ...@@ -200,16 +202,6 @@ template <typename type, typename holder_type = std::unique_ptr<type>> struct in
holder_type holder; holder_type holder;
}; };
/// Additional type information which does not fit into the PyTypeObject
struct type_info {
PyTypeObject *type;
size_t type_size;
void (*init_holder)(PyObject *, const void *);
std::vector<PyObject *(*)(PyObject *, PyTypeObject *)> implicit_conversions;
buffer_info *(*get_buffer)(PyObject *, void *) = nullptr;
void *get_buffer_data = nullptr;
};
struct overload_hash { struct overload_hash {
inline std::size_t operator()(const std::pair<const PyObject *, const char *>& v) const { inline std::size_t operator()(const std::pair<const PyObject *, const char *>& v) const {
size_t value = std::hash<const void *>()(v.first); size_t value = std::hash<const void *>()(v.first);
...@@ -218,16 +210,6 @@ struct overload_hash { ...@@ -218,16 +210,6 @@ struct overload_hash {
} }
}; };
/// Stores information about a keyword argument
struct argument_entry {
const char *name; ///< Argument name
const char *descr; ///< Human-readable version of the argument value
PyObject *value; ///< Associated Python object
argument_entry(const char *name, const char *descr, PyObject *value)
: name(name), descr(descr), value(value) { }
};
/// Internal data struture used to track registered instances and types /// Internal data struture used to track registered instances and types
struct internals { struct internals {
std::unordered_map<const void *, void*> registered_types_cpp; // std::type_info* -> type_info std::unordered_map<const void *, void*> registered_types_cpp; // std::type_info* -> type_info
......
...@@ -20,8 +20,8 @@ PYBIND11_DECL_FMT(std::complex<double>, "Zd"); ...@@ -20,8 +20,8 @@ PYBIND11_DECL_FMT(std::complex<double>, "Zd");
NAMESPACE_BEGIN(detail) NAMESPACE_BEGIN(detail)
template <typename T> class type_caster<std::complex<T>> { template <typename T> class type_caster<std::complex<T>> {
public: public:
bool load(PyObject *src, bool) { bool load(handle src, bool) {
Py_complex result = PyComplex_AsCComplex(src); Py_complex result = PyComplex_AsCComplex(src.ptr());
if (result.real == -1.0 && PyErr_Occurred()) { if (result.real == -1.0 && PyErr_Occurred()) {
PyErr_Clear(); PyErr_Clear();
return false; return false;
...@@ -30,7 +30,7 @@ public: ...@@ -30,7 +30,7 @@ public:
return true; return true;
} }
static PyObject *cast(const std::complex<T> &src, return_value_policy /* policy */, PyObject * /* parent */) { static handle cast(const std::complex<T> &src, return_value_policy /* policy */, handle /* parent */) {
return PyComplex_FromDoubles((double) src.real(), (double) src.imag()); return PyComplex_FromDoubles((double) src.real(), (double) src.imag());
} }
......
...@@ -18,14 +18,13 @@ NAMESPACE_BEGIN(detail) ...@@ -18,14 +18,13 @@ NAMESPACE_BEGIN(detail)
template <typename Return, typename... Args> struct type_caster<std::function<Return(Args...)>> { template <typename Return, typename... Args> struct type_caster<std::function<Return(Args...)>> {
typedef std::function<Return(Args...)> type; typedef std::function<Return(Args...)> type;
public: public:
bool load(handle src_, bool) {
bool load(PyObject *src_, bool) {
src_ = detail::get_function(src_); src_ = detail::get_function(src_);
if (!src_ || !(PyFunction_Check(src_) || PyCFunction_Check(src_))) if (!src_ || !(PyFunction_Check(src_.ptr()) || PyCFunction_Check(src_.ptr())))
return false; return false;
object src(src_, true); object src(src_, true);
value = [src](Args... args) -> Return { value = [src](Args... args) -> Return {
object retval(pybind11::handle(src).call(std::move(args)...)); object retval(src.call(std::move(args)...));
/* Visual studio 2015 parser issue: need parentheses around this expression */ /* Visual studio 2015 parser issue: need parentheses around this expression */
return (retval.template cast<Return>()); return (retval.template cast<Return>());
}; };
...@@ -33,10 +32,8 @@ public: ...@@ -33,10 +32,8 @@ public:
} }
template <typename Func> template <typename Func>
static PyObject *cast(Func &&f_, return_value_policy policy, PyObject *) { static handle cast(Func &&f_, return_value_policy policy, handle /* parent */) {
cpp_function f(std::forward<Func>(f_), policy); return cpp_function(std::forward<Func>(f_), policy).release();
f.inc_ref();
return f.ptr();
} }
PYBIND11_TYPE_CASTER(type, _("function<") + PYBIND11_TYPE_CASTER(type, _("function<") +
......
...@@ -79,36 +79,36 @@ public: ...@@ -79,36 +79,36 @@ public:
API& api = lookup_api(); API& api = lookup_api();
PyObject *descr = api.PyArray_DescrFromType_(npy_format_descriptor<Type>::value); PyObject *descr = api.PyArray_DescrFromType_(npy_format_descriptor<Type>::value);
if (descr == nullptr) if (descr == nullptr)
throw std::runtime_error("NumPy: unsupported buffer format!"); pybind11_fail("NumPy: unsupported buffer format!");
Py_intptr_t shape = (Py_intptr_t) size; Py_intptr_t shape = (Py_intptr_t) size;
object tmp = object(api.PyArray_NewFromDescr_( object tmp = object(api.PyArray_NewFromDescr_(
api.PyArray_Type_, descr, 1, &shape, nullptr, (void *) ptr, 0, nullptr), false); api.PyArray_Type_, descr, 1, &shape, nullptr, (void *) ptr, 0, nullptr), false);
if (ptr && tmp) if (ptr && tmp)
tmp = object(api.PyArray_NewCopy_(tmp.ptr(), -1 /* any order */), false); tmp = object(api.PyArray_NewCopy_(tmp.ptr(), -1 /* any order */), false);
if (!tmp) if (!tmp)
throw std::runtime_error("NumPy: unable to create array!"); pybind11_fail("NumPy: unable to create array!");
m_ptr = tmp.release(); m_ptr = tmp.release().ptr();
} }
array(const buffer_info &info) { array(const buffer_info &info) {
API& api = lookup_api(); API& api = lookup_api();
if ((info.format.size() < 1) || (info.format.size() > 2)) if ((info.format.size() < 1) || (info.format.size() > 2))
throw std::runtime_error("Unsupported buffer format!"); pybind11_fail("Unsupported buffer format!");
int fmt = (int) info.format[0]; int fmt = (int) info.format[0];
if (info.format == "Zd") fmt = API::NPY_CDOUBLE_; if (info.format == "Zd") fmt = API::NPY_CDOUBLE_;
else if (info.format == "Zf") fmt = API::NPY_CFLOAT_; else if (info.format == "Zf") fmt = API::NPY_CFLOAT_;
PyObject *descr = api.PyArray_DescrFromType_(fmt); PyObject *descr = api.PyArray_DescrFromType_(fmt);
if (descr == nullptr) if (descr == nullptr)
throw std::runtime_error("NumPy: unsupported buffer format '" + info.format + "'!"); pybind11_fail("NumPy: unsupported buffer format '" + info.format + "'!");
object tmp(api.PyArray_NewFromDescr_( object tmp(api.PyArray_NewFromDescr_(
api.PyArray_Type_, descr, info.ndim, (Py_intptr_t *) &info.shape[0], api.PyArray_Type_, descr, info.ndim, (Py_intptr_t *) &info.shape[0],
(Py_intptr_t *) &info.strides[0], info.ptr, 0, nullptr), false); (Py_intptr_t *) &info.strides[0], info.ptr, 0, nullptr), false);
if (info.ptr && tmp) if (info.ptr && tmp)
tmp = object(api.PyArray_NewCopy_(tmp.ptr(), -1 /* any order */), false); tmp = object(api.PyArray_NewCopy_(tmp.ptr(), -1 /* any order */), false);
if (!tmp) if (!tmp)
throw std::runtime_error("NumPy: unable to create array!"); pybind11_fail("NumPy: unable to create array!");
m_ptr = tmp.release(); m_ptr = tmp.release().ptr();
} }
protected: protected:
...@@ -186,7 +186,7 @@ struct vectorize_helper { ...@@ -186,7 +186,7 @@ struct vectorize_helper {
/* Check if the parameters are actually compatible */ /* Check if the parameters are actually compatible */
for (size_t i=0; i<N; ++i) for (size_t i=0; i<N; ++i)
if (buffers[i].size != 1 && (buffers[i].ndim != ndim || buffers[i].shape != shape)) if (buffers[i].size != 1 && (buffers[i].ndim != ndim || buffers[i].shape != shape))
throw std::runtime_error("pybind11::vectorize: incompatible size/dimension of inputs!"); pybind11_fail("pybind11::vectorize: incompatible size/dimension of inputs!");
if (size == 1) if (size == 1)
return cast(f(*((Args *) buffers[Index].ptr)...)); return cast(f(*((Args *) buffers[Index].ptr)...));
......
...@@ -45,17 +45,17 @@ template <op_id, op_type, typename B, typename L, typename R> struct op_impl { } ...@@ -45,17 +45,17 @@ template <op_id, op_type, typename B, typename L, typename R> struct op_impl { }
/// Operator implementation generator /// Operator implementation generator
template <op_id id, op_type ot, typename L, typename R> struct op_ { template <op_id id, op_type ot, typename L, typename R> struct op_ {
template <typename Base, typename Holder, typename... Extra> void execute(pybind11::class_<Base, Holder> &class_, Extra&&... extra) const { template <typename Base, typename Holder, typename... Extra> void execute(pybind11::class_<Base, Holder> &class_, const Extra&... extra) const {
typedef typename std::conditional<std::is_same<L, self_t>::value, Base, L>::type L_type; typedef typename std::conditional<std::is_same<L, self_t>::value, Base, L>::type L_type;
typedef typename std::conditional<std::is_same<R, self_t>::value, Base, R>::type R_type; typedef typename std::conditional<std::is_same<R, self_t>::value, Base, R>::type R_type;
typedef op_impl<id, ot, Base, L_type, R_type> op; typedef op_impl<id, ot, Base, L_type, R_type> op;
class_.def(op::name(), &op::execute, std::forward<Extra>(extra)...); class_.def(op::name(), &op::execute, extra...);
} }
template <typename Base, typename Holder, typename... Extra> void execute_cast(pybind11::class_<Base, Holder> &class_, Extra&&... extra) const { template <typename Base, typename Holder, typename... Extra> void execute_cast(pybind11::class_<Base, Holder> &class_, const Extra&... extra) const {
typedef typename std::conditional<std::is_same<L, self_t>::value, Base, L>::type L_type; typedef typename std::conditional<std::is_same<L, self_t>::value, Base, L>::type L_type;
typedef typename std::conditional<std::is_same<R, self_t>::value, Base, R>::type R_type; typedef typename std::conditional<std::is_same<R, self_t>::value, Base, R>::type R_type;
typedef op_impl<id, ot, Base, L_type, R_type> op; typedef op_impl<id, ot, Base, L_type, R_type> op;
class_.def(op::name(), &op::execute_cast, std::forward<Extra>(extra)...); class_.def(op::name(), &op::execute_cast, extra...);
} }
}; };
......
...@@ -26,7 +26,7 @@ template <typename Value, typename Alloc> struct type_caster<std::vector<Value, ...@@ -26,7 +26,7 @@ template <typename Value, typename Alloc> struct type_caster<std::vector<Value,
typedef std::vector<Value, Alloc> type; typedef std::vector<Value, Alloc> type;
typedef type_caster<Value> value_conv; typedef type_caster<Value> value_conv;
public: public:
bool load(PyObject *src, bool convert) { bool load(handle src, bool convert) {
list l(src, true); list l(src, true);
if (!l.check()) if (!l.check())
return false; return false;
...@@ -34,21 +34,21 @@ public: ...@@ -34,21 +34,21 @@ public:
value.clear(); value.clear();
value_conv conv; value_conv conv;
for (auto it : l) { for (auto it : l) {
if (!conv.load(it.ptr(), convert)) if (!conv.load(it, convert))
return false; return false;
value.push_back((Value) conv); value.push_back((Value) conv);
} }
return true; return true;
} }
static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) { static handle cast(const type &src, return_value_policy policy, handle parent) {
list l(src.size()); list l(src.size());
size_t index = 0; size_t index = 0;
for (auto const &value: src) { for (auto const &value: src) {
object value_(value_conv::cast(value, policy, parent), false); object value_ = object(value_conv::cast(value, policy, parent), false);
if (!value_) if (!value_)
return nullptr; return handle();
PyList_SET_ITEM(l.ptr(), index++, value_.release()); // steals a reference PyList_SET_ITEM(l.ptr(), index++, value_.release().ptr()); // steals a reference
} }
return l.release(); return l.release();
} }
...@@ -59,26 +59,26 @@ template <typename Key, typename Compare, typename Alloc> struct type_caster<std ...@@ -59,26 +59,26 @@ template <typename Key, typename Compare, typename Alloc> struct type_caster<std
typedef std::set<Key, Compare, Alloc> type; typedef std::set<Key, Compare, Alloc> type;
typedef type_caster<Key> key_conv; typedef type_caster<Key> key_conv;
public: public:
bool load(PyObject *src, bool convert) { bool load(handle src, bool convert) {
pybind11::set s(src, true); pybind11::set s(src, true);
if (!s.check()) if (!s.check())
return false; return false;
value.clear(); value.clear();
key_conv conv; key_conv conv;
for (auto entry : s) { for (auto entry : s) {
if (!conv.load(entry.ptr(), convert)) if (!conv.load(entry, convert))
return false; return false;
value.insert((Key) conv); value.insert((Key) conv);
} }
return true; return true;
} }
static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) { static handle cast(const type &src, return_value_policy policy, handle parent) {
pybind11::set s; pybind11::set s;
for (auto const &value: src) { for (auto const &value: src) {
object value_(key_conv::cast(value, policy, parent), false); object value_ = object(key_conv::cast(value, policy, parent), false);
if (!value_ || !s.add(value)) if (!value_ || !s.add(value))
return nullptr; return handle();
} }
return s.release(); return s.release();
} }
...@@ -91,7 +91,7 @@ public: ...@@ -91,7 +91,7 @@ public:
typedef type_caster<Key> key_conv; typedef type_caster<Key> key_conv;
typedef type_caster<Value> value_conv; typedef type_caster<Value> value_conv;
bool load(PyObject *src, bool convert) { bool load(handle src, bool convert) {
dict d(src, true); dict d(src, true);
if (!d.check()) if (!d.check())
return false; return false;
...@@ -107,13 +107,13 @@ public: ...@@ -107,13 +107,13 @@ public:
return true; return true;
} }
static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) { static handle cast(const type &src, return_value_policy policy, handle parent) {
dict d; dict d;
for (auto const &kv: src) { for (auto const &kv: src) {
object key(key_conv::cast(kv.first, policy, parent), false); object key = object(key_conv::cast(kv.first, policy, parent), false);
object value(value_conv::cast(kv.second, policy, parent), false); object value = object(value_conv::cast(kv.second, policy, parent), false);
if (!key || !value) if (!key || !value)
return nullptr; return handle();
d[key] = value; d[key] = value;
} }
return d.release(); return d.release();
......
...@@ -15,6 +15,7 @@ setup( ...@@ -15,6 +15,7 @@ setup(
packages=[], packages=[],
license='BSD', license='BSD',
headers=[ headers=[
'include/pybind11/attr.h',
'include/pybind11/cast.h', 'include/pybind11/cast.h',
'include/pybind11/complex.h', 'include/pybind11/complex.h',
'include/pybind11/descr.h', 'include/pybind11/descr.h',
...@@ -58,10 +59,10 @@ C++11-compatible compilers are widely available, this heavy machinery has ...@@ -58,10 +59,10 @@ C++11-compatible compilers are widely available, this heavy machinery has
become an excessively large and unnecessary dependency. become an excessively large and unnecessary dependency.
Think of this library as a tiny self-contained version of Boost.Python with Think of this library as a tiny self-contained version of Boost.Python with
everything stripped away that isn't relevant for binding generation. The core everything stripped away that isn't relevant for binding generation. Without
header files only require ~2.5K lines of code and depend on Python (2.7 or 3.x) comments, the core header files only require ~2.5K lines of code and depend on
and the C++ standard library. This compact implementation was possible thanks Python (2.7 or 3.x) and the C++ standard library. This compact implementation
to some of the new C++11 language features (specifically: tuples, lambda was possible thanks to some of the new C++11 language features (specifically:
functions and variadic templates). Since its creation, this library has grown tuples, lambda functions and variadic templates). Since its creation, this
beyond Boost.Python in many ways, leading to dramatically simpler binding code library has grown beyond Boost.Python in many ways, leading to dramatically
in many common situations.""") simpler binding code in many common situations.""")
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment