do more work with classes from pytypes.h (especially for STL container casting)

This commit is contained in:
Wenzel Jakob 2016-01-17 22:36:41 +01:00
parent d561cb010c
commit 678d787ca4
10 changed files with 128 additions and 105 deletions

View File

@ -22,13 +22,13 @@ 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.
Tutorial and reference documentation is provided at Tutorial and reference documentation is provided at
[http://pybind11.readthedocs.org/en/latest](http://pybind11.readthedocs.org/en/latest). [http://pybind11.readthedocs.org/en/latest](http://pybind11.readthedocs.org/en/latest).

View File

@ -19,13 +19,13 @@ 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.
Core features Core features
************* *************

View File

@ -10,7 +10,7 @@ test_function(enum=1)
None None
test_function(enum=2) test_function(enum=2)
None None
<class 'Example4.EMode'> <class 'example.EMode'>
EMode.EFirstMode EMode.EFirstMode
EMode.EFirstMode EMode.EFirstMode
Example4::test_function(enum=1) Example4::test_function(enum=1)

View File

@ -22,6 +22,8 @@ def sanitize(lines):
line = line.replace('__builtin__', 'builtins') line = line.replace('__builtin__', 'builtins')
line = line.replace('example.', '') line = line.replace('example.', '')
line = line.replace('unicode', 'str') line = line.replace('unicode', 'str')
line = line.replace('Example4.EMode', 'EMode')
line = line.replace('example.EMode', 'EMode')
line = line.replace('method of builtins.PyCapsule instance', '') line = line.replace('method of builtins.PyCapsule instance', '')
line = line.strip() line = line.strip()
if sys.platform == 'win32': if sys.platform == 'win32':

View File

@ -271,4 +271,7 @@ struct error_already_set : public std::runtime_error { public: error_already_set
/// Thrown when pybind11::cast or handle::call fail due to a type casting error /// Thrown when pybind11::cast or handle::call fail due to a type casting error
struct cast_error : public std::runtime_error { public: cast_error(const std::string &w = "") : std::runtime_error(w) {} }; struct cast_error : public std::runtime_error { public: cast_error(const std::string &w = "") : std::runtime_error(w) {} };
PYBIND11_NOINLINE inline void pybind11_fail(const char *reason) { throw std::runtime_error(reason); }
PYBIND11_NOINLINE inline void pybind11_fail(const std::string &reason) { throw std::runtime_error(reason); }
NAMESPACE_END(pybind11) NAMESPACE_END(pybind11)

View File

@ -24,7 +24,6 @@
#endif #endif
#include "cast.h" #include "cast.h"
#include <iostream>
NAMESPACE_BEGIN(pybind11) NAMESPACE_BEGIN(pybind11)
@ -196,7 +195,7 @@ protected:
a.value, return_value_policy::automatic, nullptr); a.value, return_value_policy::automatic, nullptr);
if (obj == nullptr) if (obj == nullptr)
throw std::runtime_error("arg(): could not convert default keyword " pybind11_fail("arg(): could not convert default keyword "
"argument into a Python object (type not " "argument into a Python object (type not "
"registered yet?)"); "registered yet?)");
@ -490,7 +489,7 @@ protected:
} else if (c == '%') { } else if (c == '%') {
const std::type_info *t = types[type_index++]; const std::type_info *t = types[type_index++];
if (!t) if (!t)
throw std::runtime_error("Internal error while parsing type signature (1)"); pybind11_fail("Internal error while parsing type signature (1)");
auto it = registered_types.find(t); auto it = registered_types.find(t);
if (it != registered_types.end()) { if (it != registered_types.end()) {
signature += ((const detail::type_info *) it->second)->type->tp_name; signature += ((const detail::type_info *) it->second)->type->tp_name;
@ -504,7 +503,7 @@ protected:
} }
} }
if (type_depth != 0 || types[type_index] != nullptr) if (type_depth != 0 || types[type_index] != nullptr)
throw std::runtime_error("Internal error while parsing type signature (2)"); pybind11_fail("Internal error while parsing type signature (2)");
#if !defined(PYBIND11_CPP14) #if !defined(PYBIND11_CPP14)
delete[] types; delete[] types;
@ -519,7 +518,7 @@ protected:
#endif #endif
if (!m_entry->args.empty() && (int) m_entry->args.size() != args) if (!m_entry->args.empty() && (int) m_entry->args.size() != args)
throw std::runtime_error( pybind11_fail(
"cpp_function(): function \"" + std::string(m_entry->name) + "\" takes " + "cpp_function(): function \"" + std::string(m_entry->name) + "\" takes " +
std::to_string(args) + " arguments, but " + std::to_string(m_entry->args.size()) + std::to_string(args) + " arguments, but " + std::to_string(m_entry->args.size()) +
" pybind11::arg entries were specified!"); " pybind11::arg entries were specified!");
@ -555,7 +554,7 @@ protected:
}); });
m_ptr = PyCFunction_New(m_entry->def, entry_capsule.ptr()); m_ptr = PyCFunction_New(m_entry->def, entry_capsule.ptr());
if (!m_ptr) if (!m_ptr)
throw std::runtime_error("cpp_function::cpp_function(): Could not allocate function object"); pybind11_fail("cpp_function::cpp_function(): Could not allocate function object");
} else { } else {
/* Append at the end of the overload chain */ /* Append at the end of the overload chain */
m_ptr = m_entry->sibling; m_ptr = m_entry->sibling;
@ -597,7 +596,7 @@ protected:
m_ptr = PyMethod_New(m_ptr, nullptr, entry->class_); m_ptr = PyMethod_New(m_ptr, nullptr, entry->class_);
#endif #endif
if (!m_ptr) if (!m_ptr)
throw std::runtime_error("cpp_function::cpp_function(): Could not allocate instance method object"); pybind11_fail("cpp_function::cpp_function(): Could not allocate instance method object");
Py_DECREF(func); Py_DECREF(func);
} }
} }
@ -621,7 +620,7 @@ public:
m_ptr = Py_InitModule3(name, nullptr, doc); m_ptr = Py_InitModule3(name, nullptr, doc);
#endif #endif
if (m_ptr == nullptr) if (m_ptr == nullptr)
throw std::runtime_error("Internal error in module::module()"); pybind11_fail("Internal error in module::module()");
inc_ref(); inc_ref();
} }
@ -647,7 +646,7 @@ public:
static module import(const char *name) { static module import(const char *name) {
PyObject *obj = PyImport_ImportModule(name); PyObject *obj = PyImport_ImportModule(name);
if (!obj) if (!obj)
throw std::runtime_error("Module \"" + std::string(name) + "\" not found!"); pybind11_fail("Module \"" + std::string(name) + "\" not found!");
return module(obj, false); return module(obj, false);
} }
}; };
@ -668,7 +667,7 @@ public:
auto type = (PyHeapTypeObject*) type_holder.ptr(); auto type = (PyHeapTypeObject*) type_holder.ptr();
if (!type_holder || !name) if (!type_holder || !name)
throw std::runtime_error("generic_type: unable to create type object!"); pybind11_fail("generic_type: unable to create type object!");
/* Register supplemental type information in C++ dict */ /* Register supplemental type information in C++ dict */
auto &internals = get_internals(); auto &internals = get_internals();
@ -732,7 +731,7 @@ public:
} }
if (PyType_Ready(&type->ht_type) < 0) if (PyType_Ready(&type->ht_type) < 0)
throw std::runtime_error("generic_type: PyType_Ready failed!"); pybind11_fail("generic_type: PyType_Ready failed!");
m_ptr = type_holder.ptr(); m_ptr = type_holder.ptr();
@ -756,7 +755,7 @@ protected:
object type_holder(PyType_Type.tp_alloc(&PyType_Type, 0), false); object type_holder(PyType_Type.tp_alloc(&PyType_Type, 0), false);
object name(PYBIND11_FROM_STRING(name_.c_str()), false); object name(PYBIND11_FROM_STRING(name_.c_str()), false);
if (!type_holder || !name) if (!type_holder || !name)
throw std::runtime_error("generic_type::metaclass(): unable to create type object!"); pybind11_fail("generic_type::metaclass(): unable to create type object!");
auto type = (PyHeapTypeObject*) type_holder.ptr(); auto type = (PyHeapTypeObject*) type_holder.ptr();
type->ht_name = name.release(); type->ht_name = name.release();
@ -767,7 +766,7 @@ protected:
~Py_TPFLAGS_HAVE_GC; ~Py_TPFLAGS_HAVE_GC;
if (PyType_Ready(&type->ht_type) < 0) if (PyType_Ready(&type->ht_type) < 0)
throw std::runtime_error("generic_type::metaclass(): PyType_Ready failed!"); pybind11_fail("generic_type::metaclass(): PyType_Ready failed!");
ob_type = (PyTypeObject *) type_holder.release(); ob_type = (PyTypeObject *) type_holder.release();
} }
@ -798,7 +797,7 @@ protected:
auto &registered_instances = detail::get_internals().registered_instances; auto &registered_instances = detail::get_internals().registered_instances;
auto it = registered_instances.find(self->value); auto it = registered_instances.find(self->value);
if (it == registered_instances.end()) if (it == registered_instances.end())
throw std::runtime_error("generic_type::dealloc(): Tried to deallocate unregistered instance!"); pybind11_fail("generic_type::dealloc(): Tried to deallocate unregistered instance!");
registered_instances.erase(it); registered_instances.erase(it);
} }
Py_XDECREF(self->parent); Py_XDECREF(self->parent);
@ -1096,14 +1095,12 @@ PYBIND11_NOINLINE inline void keep_alive_impl(int Nurse, int Patient, PyObject *
handle patient(Patient > 0 ? PyTuple_GetItem(arg, Patient - 1) : ret); handle patient(Patient > 0 ? PyTuple_GetItem(arg, Patient - 1) : ret);
if (!nurse || !patient) if (!nurse || !patient)
throw std::runtime_error("Could not activate keep_alive!"); pybind11_fail("Could not activate keep_alive!");
cpp_function disable_lifesupport( cpp_function disable_lifesupport(
[patient](handle weakref) { patient.dec_ref(); weakref.dec_ref(); }); [patient](handle weakref) { patient.dec_ref(); weakref.dec_ref(); });
weakref wr(nurse, disable_lifesupport); weakref wr(nurse, disable_lifesupport);
if (!wr)
throw std::runtime_error("Could not allocate weak reference!");
patient.inc_ref(); /* reference patient and leak the weak reference */ patient.inc_ref(); /* reference patient and leak the weak reference */
(void) wr.release(); (void) wr.release();
@ -1138,7 +1135,7 @@ template <typename InputType, typename OutputType> void implicitly_convertible()
auto & registered_types = detail::get_internals().registered_types_cpp; auto & registered_types = detail::get_internals().registered_types_cpp;
auto it = registered_types.find(&typeid(OutputType)); auto it = registered_types.find(&typeid(OutputType));
if (it == registered_types.end()) if (it == registered_types.end())
throw std::runtime_error("implicitly_convertible: Unable to find type " + type_id<OutputType>()); pybind11_fail("implicitly_convertible: Unable to find type " + type_id<OutputType>());
((detail::type_info *) it->second)->implicit_conversions.push_back(implicit_caster); ((detail::type_info *) it->second)->implicit_conversions.push_back(implicit_caster);
} }
@ -1196,7 +1193,7 @@ inline function get_overload(const void *this_ptr, const char *name) {
#define PYBIND11_OVERLOAD_PURE(ret_type, class_name, name, ...) \ #define PYBIND11_OVERLOAD_PURE(ret_type, class_name, name, ...) \
PYBIND11_OVERLOAD_INT(ret_type, class_name, name, __VA_ARGS__) \ PYBIND11_OVERLOAD_INT(ret_type, class_name, name, __VA_ARGS__) \
throw std::runtime_error("Tried to call pure virtual function \"" #name "\""); pybind11::pybind11_fail("Tried to call pure virtual function \"" #name "\"");
NAMESPACE_END(pybind11) NAMESPACE_END(pybind11)

View File

@ -88,12 +88,12 @@ public:
iterator(PyObject *obj, bool borrowed = false) : object(obj, borrowed) { ++*this; } iterator(PyObject *obj, bool borrowed = false) : object(obj, borrowed) { ++*this; }
iterator& operator++() { iterator& operator++() {
if (ptr()) if (ptr())
value = object(PyIter_Next(ptr()), false); value = object(PyIter_Next(m_ptr), false);
return *this; return *this;
} }
bool operator==(const iterator &it) const { return *it == **this; } bool operator==(const iterator &it) const { return *it == **this; }
bool operator!=(const iterator &it) const { return *it != **this; } bool operator!=(const iterator &it) const { return *it != **this; }
const object &operator*() const { return value; } const handle &operator*() const { return value; }
bool check() const { return PyIter_Check(ptr()); } bool check() const { return PyIter_Check(ptr()); }
private: private:
object value; object value;
@ -127,10 +127,10 @@ public:
void operator=(const handle &h) { void operator=(const handle &h) {
if (attr) { if (attr) {
if (PyObject_SetAttr(obj, key, (PyObject *) h.ptr()) < 0) if (PyObject_SetAttr(obj, key, (PyObject *) h.ptr()) < 0)
throw std::runtime_error("Unable to set object attribute"); pybind11_fail("Unable to set object attribute");
} else { } else {
if (PyObject_SetItem(obj, key, (PyObject *) h.ptr()) < 0) if (PyObject_SetItem(obj, key, (PyObject *) h.ptr()) < 0)
throw std::runtime_error("Unable to set object item"); pybind11_fail("Unable to set object item");
} }
} }
@ -164,12 +164,12 @@ public:
void operator=(const handle &o) { void operator=(const handle &o) {
o.inc_ref(); // PyList_SetItem steals a reference o.inc_ref(); // PyList_SetItem steals a reference
if (PyList_SetItem(list, (ssize_t) index, (PyObject *) o.ptr()) < 0) if (PyList_SetItem(list, (ssize_t) index, (PyObject *) o.ptr()) < 0)
throw std::runtime_error("Unable to assign value in Python list!"); pybind11_fail("Unable to assign value in Python list!");
} }
operator object() const { operator object() const {
PyObject *result = PyList_GetItem(list, (ssize_t) index); PyObject *result = PyList_GetItem(list, (ssize_t) index);
if (!result) if (!result)
throw std::runtime_error("Unable to retrieve value from Python list!"); pybind11_fail("Unable to retrieve value from Python list!");
return object(result, true); return object(result, true);
} }
private: private:
@ -184,12 +184,12 @@ public:
void operator=(const handle &o) { void operator=(const handle &o) {
o.inc_ref(); // PyTuple_SetItem steals a reference o.inc_ref(); // PyTuple_SetItem steals a reference
if (PyTuple_SetItem(tuple, (ssize_t) index, (PyObject *) o.ptr()) < 0) if (PyTuple_SetItem(tuple, (ssize_t) index, (PyObject *) o.ptr()) < 0)
throw std::runtime_error("Unable to assign value in Python tuple!"); pybind11_fail("Unable to assign value in Python tuple!");
} }
operator object() const { operator object() const {
PyObject *result = PyTuple_GetItem(tuple, (ssize_t) index); PyObject *result = PyTuple_GetItem(tuple, (ssize_t) index);
if (!result) if (!result)
throw std::runtime_error("Unable to retrieve value from Python tuple!"); pybind11_fail("Unable to retrieve value from Python tuple!");
return object(result, true); return object(result, true);
} }
private: private:
@ -205,8 +205,8 @@ public:
pos = -1; pos = -1;
return *this; return *this;
} }
std::pair<object, object> operator*() const { std::pair<handle, handle> operator*() const {
return std::make_pair(object(key, true), object(value, true)); return std::make_pair(key, value);
} }
bool operator==(const dict_iterator &it) const { return it.pos == pos; } bool operator==(const dict_iterator &it) const { return it.pos == pos; }
bool operator!=(const dict_iterator &it) const { return it.pos != pos; } bool operator!=(const dict_iterator &it) const { return it.pos != pos; }
@ -242,7 +242,10 @@ inline iterator handle::end() const { return iterator(nullptr); }
class str : public object { class str : public object {
public: public:
PYBIND11_OBJECT_DEFAULT(str, object, PyUnicode_Check) PYBIND11_OBJECT_DEFAULT(str, object, PyUnicode_Check)
str(const std::string &s) : object(PyUnicode_FromStringAndSize(s.c_str(), s.length()), false) { } str(const std::string &s)
: object(PyUnicode_FromStringAndSize(s.c_str(), s.length()), false) {
if (!m_ptr) pybind11_fail("Could not allocate string object!");
}
operator std::string() const { operator std::string() const {
#if PY_MAJOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3
@ -250,7 +253,7 @@ public:
#else #else
object temp(PyUnicode_AsUTF8String(m_ptr), false); object temp(PyUnicode_AsUTF8String(m_ptr), false);
if (temp.ptr() == nullptr) if (temp.ptr() == nullptr)
throw std::runtime_error("Unable to extract string contents!"); pybind11_fail("Unable to extract string contents!");
return PyString_AsString(temp.ptr()); return PyString_AsString(temp.ptr());
#endif #endif
} }
@ -270,14 +273,16 @@ public:
PYBIND11_OBJECT_DEFAULT(bytes, object, PYBIND11_BYTES_CHECK) PYBIND11_OBJECT_DEFAULT(bytes, object, PYBIND11_BYTES_CHECK)
bytes(const std::string &s) bytes(const std::string &s)
: object(PYBIND11_BYTES_FROM_STRING_AND_SIZE(s.data(), s.size()), false) { } : object(PYBIND11_BYTES_FROM_STRING_AND_SIZE(s.data(), s.size()), false) {
if (!m_ptr) pybind11_fail("Could not allocate bytes object!");
}
operator std::string() const { operator std::string() const {
char *buffer; char *buffer;
ssize_t length; ssize_t length;
int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(m_ptr, &buffer, &length); int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(m_ptr, &buffer, &length);
if (err == -1) if (err == -1)
throw std::runtime_error("Unable to extract bytes contents!"); pybind11_fail("Unable to extract bytes contents!");
return std::string(buffer, length); return std::string(buffer, length);
} }
}; };
@ -306,6 +311,7 @@ public:
else else
m_ptr = PyLong_FromUnsignedLongLong((unsigned long long) value); m_ptr = PyLong_FromUnsignedLongLong((unsigned long long) value);
} }
if (!m_ptr) pybind11_fail("Could not allocate int object!");
} }
template <typename T, template <typename T,
@ -328,8 +334,12 @@ public:
class float_ : public object { class float_ : public object {
public: public:
PYBIND11_OBJECT_DEFAULT(float_, object, PyFloat_Check) PYBIND11_OBJECT_DEFAULT(float_, object, PyFloat_Check)
float_(float value) : object(PyFloat_FromDouble((double) value), false) { } float_(float value) : object(PyFloat_FromDouble((double) value), false) {
float_(double value) : object(PyFloat_FromDouble((double) value), false) { } if (!m_ptr) pybind11_fail("Could not allocate float object!");
}
float_(double value) : object(PyFloat_FromDouble((double) value), false) {
if (!m_ptr) pybind11_fail("Could not allocate float object!");
}
operator float() const { return (float) PyFloat_AsDouble(m_ptr); } operator float() const { return (float) PyFloat_AsDouble(m_ptr); }
operator double() const { return (double) PyFloat_AsDouble(m_ptr); } operator double() const { return (double) PyFloat_AsDouble(m_ptr); }
}; };
@ -337,7 +347,9 @@ public:
class weakref : public object { class weakref : public object {
public: public:
PYBIND11_OBJECT_DEFAULT(weakref, object, PyWeakref_Check) PYBIND11_OBJECT_DEFAULT(weakref, object, PyWeakref_Check)
weakref(handle obj, handle callback = handle()) : object(PyWeakref_NewRef(obj.ptr(), callback.ptr()), false) { } weakref(handle obj, handle callback = handle()) : object(PyWeakref_NewRef(obj.ptr(), callback.ptr()), false) {
if (!m_ptr) pybind11_fail("Could not allocate weak reference!");
}
}; };
class slice : public object { class slice : public object {
@ -346,6 +358,7 @@ public:
slice(ssize_t start_, ssize_t stop_, ssize_t step_) { slice(ssize_t start_, ssize_t stop_, ssize_t step_) {
int_ start(start_), stop(stop_), step(step_); int_ start(start_), stop(stop_), step(step_);
m_ptr = PySlice_New(start.ptr(), stop.ptr(), step.ptr()); m_ptr = PySlice_New(start.ptr(), stop.ptr(), step.ptr());
if (!m_ptr) pybind11_fail("Could not allocate slice object!");
} }
bool compute(ssize_t length, ssize_t *start, ssize_t *stop, ssize_t *step, ssize_t *slicelength) const { bool compute(ssize_t length, ssize_t *start, ssize_t *stop, ssize_t *step, ssize_t *slicelength) const {
return PySlice_GetIndicesEx((PYBIND11_SLICE_OBJECT *) m_ptr, length, return PySlice_GetIndicesEx((PYBIND11_SLICE_OBJECT *) m_ptr, length,
@ -357,10 +370,13 @@ class capsule : public object {
public: public:
PYBIND11_OBJECT_DEFAULT(capsule, object, PyCapsule_CheckExact) PYBIND11_OBJECT_DEFAULT(capsule, object, PyCapsule_CheckExact)
capsule(PyObject *obj, bool borrowed) : object(obj, borrowed) { } capsule(PyObject *obj, bool borrowed) : object(obj, borrowed) { }
capsule(void *value, void (*destruct)(PyObject *) = nullptr) : object(PyCapsule_New(value, nullptr, destruct), false) { } capsule(void *value, void (*destruct)(PyObject *) = nullptr)
: object(PyCapsule_New(value, nullptr, destruct), false) {
if (!m_ptr) pybind11_fail("Could not allocate capsule object!");
}
template <typename T> operator T *() const { template <typename T> operator T *() const {
T * result = static_cast<T *>(PyCapsule_GetPointer(m_ptr, nullptr)); T * result = static_cast<T *>(PyCapsule_GetPointer(m_ptr, nullptr));
if (!result) throw std::runtime_error("Unable to extract capsule contents!"); if (!result) pybind11_fail("Unable to extract capsule contents!");
return result; return result;
} }
}; };
@ -368,7 +384,9 @@ public:
class tuple : public object { class tuple : public object {
public: public:
PYBIND11_OBJECT(tuple, object, PyTuple_Check) PYBIND11_OBJECT(tuple, object, PyTuple_Check)
tuple(size_t size = 0) : object(PyTuple_New((ssize_t) size), false) { } tuple(size_t size = 0) : object(PyTuple_New((ssize_t) size), false) {
if (!m_ptr) pybind11_fail("Could not allocate tuple object!");
}
size_t size() const { return (size_t) PyTuple_Size(m_ptr); } size_t size() const { return (size_t) PyTuple_Size(m_ptr); }
detail::tuple_accessor operator[](size_t index) const { return detail::tuple_accessor(ptr(), index); } detail::tuple_accessor operator[](size_t index) const { return detail::tuple_accessor(ptr(), index); }
}; };
@ -376,7 +394,9 @@ public:
class dict : public object { class dict : public object {
public: public:
PYBIND11_OBJECT(dict, object, PyDict_Check) PYBIND11_OBJECT(dict, object, PyDict_Check)
dict() : object(PyDict_New(), false) { } dict() : object(PyDict_New(), false) {
if (!m_ptr) pybind11_fail("Could not allocate dict object!");
}
size_t size() const { return (size_t) PyDict_Size(m_ptr); } size_t size() const { return (size_t) PyDict_Size(m_ptr); }
detail::dict_iterator begin() const { return (++detail::dict_iterator(ptr(), 0)); } detail::dict_iterator begin() const { return (++detail::dict_iterator(ptr(), 0)); }
detail::dict_iterator end() const { return detail::dict_iterator(); } detail::dict_iterator end() const { return detail::dict_iterator(); }
@ -386,7 +406,9 @@ public:
class list : public object { class list : public object {
public: public:
PYBIND11_OBJECT(list, object, PyList_Check) PYBIND11_OBJECT(list, object, PyList_Check)
list(size_t size = 0) : object(PyList_New((ssize_t) size), false) { } list(size_t size = 0) : object(PyList_New((ssize_t) size), false) {
if (!m_ptr) pybind11_fail("Could not allocate list object!");
}
size_t size() const { return (size_t) PyList_Size(m_ptr); } size_t size() const { return (size_t) PyList_Size(m_ptr); }
detail::list_accessor operator[](size_t index) const { return detail::list_accessor(ptr(), index); } detail::list_accessor operator[](size_t index) const { return detail::list_accessor(ptr(), index); }
void append(const object &object) const { PyList_Append(m_ptr, (PyObject *) object.ptr()); } void append(const object &object) const { PyList_Append(m_ptr, (PyObject *) object.ptr()); }
@ -395,10 +417,12 @@ public:
class set : public object { class set : public object {
public: public:
PYBIND11_OBJECT(set, object, PySet_Check) PYBIND11_OBJECT(set, object, PySet_Check)
set() : object(PySet_New(nullptr), false) { } set() : object(PySet_New(nullptr), false) {
if (!m_ptr) pybind11_fail("Could not allocate set object!");
}
size_t size() const { return (size_t) PySet_Size(m_ptr); } size_t size() const { return (size_t) PySet_Size(m_ptr); }
void add(const object &object) const { PySet_Add(m_ptr, (PyObject *) object.ptr()); } bool add(const object &object) const { return PySet_Add(m_ptr, (PyObject *) object.ptr()) == 0; }
void clear() const { PySet_Clear(ptr()); } void clear() const { PySet_Clear(m_ptr); }
}; };
class function : public object { class function : public object {
@ -448,7 +472,7 @@ PYBIND11_NOINLINE inline detail::type_info* get_type_info(PyTypeObject *type) {
return (detail::type_info *) it->second; return (detail::type_info *) it->second;
type = type->tp_base; type = type->tp_base;
if (type == nullptr) if (type == nullptr)
throw std::runtime_error("pybind11::detail::get_type_info: unable to find type object!"); pybind11_fail("pybind11::detail::get_type_info: unable to find type object!");
} while (true); } while (true);
} }

View File

@ -14,7 +14,6 @@
#include <set> #include <set>
#include <iostream> #include <iostream>
#if defined(_MSC_VER) #if defined(_MSC_VER)
#pragma warning(push) #pragma warning(push)
#pragma warning(disable: 4127) // warning C4127: Conditional expression is constant #pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
@ -28,14 +27,14 @@ template <typename Value, typename Alloc> struct type_caster<std::vector<Value,
typedef type_caster<Value> value_conv; typedef type_caster<Value> value_conv;
public: public:
bool load(PyObject *src, bool convert) { bool load(PyObject *src, bool convert) {
if (!PyList_Check(src)) list l(src, true);
if (!l.check())
return false; return false;
size_t size = (size_t) PyList_GET_SIZE(src); value.reserve(l.size());
value.reserve(size);
value.clear(); value.clear();
value_conv conv; value_conv conv;
for (size_t i=0; i<size; ++i) { for (auto it : l) {
if (!conv.load(PyList_GetItem(src, (ssize_t) i), convert)) if (!conv.load(it.ptr(), convert))
return false; return false;
value.push_back((Value) conv); value.push_back((Value) conv);
} }
@ -43,17 +42,15 @@ public:
} }
static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) { static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
object list(PyList_New(src.size()), false); list l(src.size());
if (!list)
return nullptr;
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_(value_conv::cast(value, policy, parent), false);
if (!value_) if (!value_)
return nullptr; return nullptr;
PyList_SET_ITEM(list.ptr(), index++, value_.release()); // steals a reference PyList_SET_ITEM(l.ptr(), index++, value_.release()); // steals a reference
} }
return list.release(); return l.release();
} }
PYBIND11_TYPE_CASTER(type, _("list<") + value_conv::name() + _(">")); PYBIND11_TYPE_CASTER(type, _("list<") + value_conv::name() + _(">"));
}; };
@ -68,8 +65,8 @@ public:
return false; return false;
value.clear(); value.clear();
key_conv conv; key_conv conv;
for (const object &o: s) { for (auto entry : s) {
if (!conv.load((PyObject *) o.ptr(), convert)) if (!conv.load(entry.ptr(), convert))
return false; return false;
value.insert((Key) conv); value.insert((Key) conv);
} }
@ -77,15 +74,13 @@ public:
} }
static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) { static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
object set(PySet_New(nullptr), false); pybind11::set s;
if (!set)
return nullptr;
for (auto const &value: src) { for (auto const &value: src) {
object value_(key_conv::cast(value, policy, parent), false); object value_(key_conv::cast(value, policy, parent), false);
if (!value_ || PySet_Add(set.ptr(), value_.ptr()) != 0) if (!value_ || !s.add(value))
return nullptr; return nullptr;
} }
return set.release(); return s.release();
} }
PYBIND11_TYPE_CASTER(type, _("set<") + key_conv::name() + _(">")); PYBIND11_TYPE_CASTER(type, _("set<") + key_conv::name() + _(">"));
}; };
@ -97,16 +92,15 @@ public:
typedef type_caster<Value> value_conv; typedef type_caster<Value> value_conv;
bool load(PyObject *src, bool convert) { bool load(PyObject *src, bool convert) {
if (!PyDict_Check(src)) dict d(src, true);
if (!d.check())
return false; return false;
value.clear();
PyObject *key_, *value_;
ssize_t pos = 0;
key_conv kconv; key_conv kconv;
value_conv vconv; value_conv vconv;
while (PyDict_Next(src, &pos, &key_, &value_)) { value.clear();
if (!kconv.load(key_, convert) || !vconv.load(value_, convert)) for (auto it : d) {
if (!kconv.load(it.first.ptr(), convert) ||
!vconv.load(it.second.ptr(), convert))
return false; return false;
value[(Key) kconv] = (Value) vconv; value[(Key) kconv] = (Value) vconv;
} }
@ -114,16 +108,15 @@ public:
} }
static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) { static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
object dict(PyDict_New(), false); dict d;
if (!dict)
return nullptr;
for (auto const &kv: src) { for (auto const &kv: src) {
object key(key_conv::cast(kv.first, policy, parent), false); object key(key_conv::cast(kv.first, policy, parent), false);
object value(value_conv::cast(kv.second, policy, parent), false); object value(value_conv::cast(kv.second, policy, parent), false);
if (!key || !value || PyDict_SetItem(dict.ptr(), key.ptr(), value.ptr()) != 0) if (!key || !value)
return nullptr; return nullptr;
d[key] = value;
} }
return dict.release(); return d.release();
} }
PYBIND11_TYPE_CASTER(type, _("dict<") + key_conv::name() + _(", ") + value_conv::name() + _(">")); PYBIND11_TYPE_CASTER(type, _("dict<") + key_conv::name() + _(", ") + value_conv::name() + _(">"));
@ -131,7 +124,10 @@ public:
NAMESPACE_END(detail) NAMESPACE_END(detail)
inline std::ostream &operator<<(std::ostream &os, const object &obj) { os << (std::string) obj.str(); return os; } inline std::ostream &operator<<(std::ostream &os, const handle &obj) {
os << (std::string) obj.str();
return os;
}
NAMESPACE_END(pybind11) NAMESPACE_END(pybind11)

View File

@ -11,6 +11,7 @@
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#if defined(__GNUG__) #if defined(__GNUG__)
#include <cxxabi.h> #include <cxxabi.h>
#endif #endif
@ -26,7 +27,7 @@ inline void erase_all(std::string &string, const std::string &search) {
} }
} }
inline void clean_type_id(std::string &name) { PYBIND11_NOINLINE inline void clean_type_id(std::string &name) {
#if defined(__GNUG__) #if defined(__GNUG__)
int status = 0; int status = 0;
std::unique_ptr<char, void (*)(void *)> res { std::unique_ptr<char, void (*)(void *)> res {

View File

@ -17,6 +17,7 @@ setup(
headers=[ headers=[
'include/pybind11/cast.h', 'include/pybind11/cast.h',
'include/pybind11/complex.h', 'include/pybind11/complex.h',
'include/pybind11/descr.h',
'include/pybind11/numpy.h', 'include/pybind11/numpy.h',
'include/pybind11/pybind11.h', 'include/pybind11/pybind11.h',
'include/pybind11/stl.h', 'include/pybind11/stl.h',
@ -57,11 +58,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 whole everything stripped away that isn't relevant for binding generation. The core
codebase requires less than 3000 lines of code and only depends on Python (2.7 header files only require ~2.5K lines of code and depend on Python (2.7 or 3.x)
or 3.x) and the C++ standard library. This compact implementation was and the C++ standard library. This compact implementation was possible thanks
possible thanks to some of the new C++11 language features (tuples, lambda to some of the new C++11 language features (specifically: tuples, lambda
functions and variadic templates). Since its creation, this library has functions and variadic templates). Since its creation, this library has grown
grown beyond Boost.Python in many ways, leading to dramatically simpler binding beyond Boost.Python in many ways, leading to dramatically simpler binding code
code in many common situations.""", in many common situations.""")
)