Commit 678d787c by Wenzel Jakob

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

parent d561cb01
......@@ -22,13 +22,13 @@ C++11-compatible compilers are widely available, this heavy machinery has
become an excessively large and unnecessary dependency.
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
header files only require ~2.5K lines of code and depend on Python (2.7 or 3.x)
and the C++ standard library. This compact implementation was possible thanks
to some of the new C++11 language features (specifically: tuples, lambda
functions and variadic templates). Since its creation, this library has grown
beyond Boost.Python in many ways, leading to dramatically simpler binding code
in many common situations.
everything stripped away that isn't relevant for binding generation. Without
comments, the core header files only require ~2.5K lines of code and depend on
Python (2.7 or 3.x) and the C++ standard library. This compact implementation
was possible thanks to some of the new C++11 language features (specifically:
tuples, lambda functions and variadic templates). Since its creation, this
library has grown beyond Boost.Python in many ways, leading to dramatically
simpler binding code in many common situations.
Tutorial and reference documentation is provided at
[http://pybind11.readthedocs.org/en/latest](http://pybind11.readthedocs.org/en/latest).
......
......@@ -19,13 +19,13 @@ C++11-compatible compilers are widely available, this heavy machinery has
become an excessively large and unnecessary dependency.
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
header files only require ~2.5K lines of code and depend on Python (2.7 or 3.x)
and the C++ standard library. This compact implementation was possible thanks
to some of the new C++11 language features (specifically: tuples, lambda
functions and variadic templates). Since its creation, this library has grown
beyond Boost.Python in many ways, leading to dramatically simpler binding code
in many common situations.
everything stripped away that isn't relevant for binding generation. Without
comments, the core header files only require ~2.5K lines of code and depend on
Python (2.7 or 3.x) and the C++ standard library. This compact implementation
was possible thanks to some of the new C++11 language features (specifically:
tuples, lambda functions and variadic templates). Since its creation, this
library has grown beyond Boost.Python in many ways, leading to dramatically
simpler binding code in many common situations.
Core features
*************
......
......@@ -10,7 +10,7 @@ test_function(enum=1)
None
test_function(enum=2)
None
<class 'Example4.EMode'>
<class 'example.EMode'>
EMode.EFirstMode
EMode.EFirstMode
Example4::test_function(enum=1)
......
......@@ -22,6 +22,8 @@ def sanitize(lines):
line = line.replace('__builtin__', 'builtins')
line = line.replace('example.', '')
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.strip()
if sys.platform == 'win32':
......
......@@ -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
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)
......@@ -24,7 +24,6 @@
#endif
#include "cast.h"
#include <iostream>
NAMESPACE_BEGIN(pybind11)
......@@ -196,7 +195,7 @@ protected:
a.value, return_value_policy::automatic, 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 "
"registered yet?)");
......@@ -490,7 +489,7 @@ protected:
} else if (c == '%') {
const std::type_info *t = types[type_index++];
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);
if (it != registered_types.end()) {
signature += ((const detail::type_info *) it->second)->type->tp_name;
......@@ -504,7 +503,7 @@ protected:
}
}
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)
delete[] types;
......@@ -519,7 +518,7 @@ protected:
#endif
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 " +
std::to_string(args) + " arguments, but " + std::to_string(m_entry->args.size()) +
" pybind11::arg entries were specified!");
......@@ -555,7 +554,7 @@ protected:
});
m_ptr = PyCFunction_New(m_entry->def, entry_capsule.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 {
/* Append at the end of the overload chain */
m_ptr = m_entry->sibling;
......@@ -597,7 +596,7 @@ protected:
m_ptr = PyMethod_New(m_ptr, nullptr, entry->class_);
#endif
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);
}
}
......@@ -621,7 +620,7 @@ public:
m_ptr = Py_InitModule3(name, nullptr, doc);
#endif
if (m_ptr == nullptr)
throw std::runtime_error("Internal error in module::module()");
pybind11_fail("Internal error in module::module()");
inc_ref();
}
......@@ -647,7 +646,7 @@ public:
static module import(const char *name) {
PyObject *obj = PyImport_ImportModule(name);
if (!obj)
throw std::runtime_error("Module \"" + std::string(name) + "\" not found!");
pybind11_fail("Module \"" + std::string(name) + "\" not found!");
return module(obj, false);
}
};
......@@ -668,7 +667,7 @@ public:
auto type = (PyHeapTypeObject*) type_holder.ptr();
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 */
auto &internals = get_internals();
......@@ -732,7 +731,7 @@ public:
}
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();
......@@ -756,7 +755,7 @@ protected:
object type_holder(PyType_Type.tp_alloc(&PyType_Type, 0), false);
object name(PYBIND11_FROM_STRING(name_.c_str()), false);
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();
type->ht_name = name.release();
......@@ -767,7 +766,7 @@ protected:
~Py_TPFLAGS_HAVE_GC;
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();
}
......@@ -798,7 +797,7 @@ protected:
auto &registered_instances = detail::get_internals().registered_instances;
auto it = registered_instances.find(self->value);
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);
}
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);
if (!nurse || !patient)
throw std::runtime_error("Could not activate keep_alive!");
pybind11_fail("Could not activate keep_alive!");
cpp_function disable_lifesupport(
[patient](handle weakref) { patient.dec_ref(); weakref.dec_ref(); });
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 */
(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 it = registered_types.find(&typeid(OutputType));
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);
}
......@@ -1196,7 +1193,7 @@ inline function get_overload(const void *this_ptr, const char *name) {
#define PYBIND11_OVERLOAD_PURE(ret_type, class_name, name, ...) \
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)
......
......@@ -14,7 +14,6 @@
#include <set>
#include <iostream>
#if defined(_MSC_VER)
#pragma warning(push)
#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;
public:
bool load(PyObject *src, bool convert) {
if (!PyList_Check(src))
list l(src, true);
if (!l.check())
return false;
size_t size = (size_t) PyList_GET_SIZE(src);
value.reserve(size);
value.reserve(l.size());
value.clear();
value_conv conv;
for (size_t i=0; i<size; ++i) {
if (!conv.load(PyList_GetItem(src, (ssize_t) i), convert))
for (auto it : l) {
if (!conv.load(it.ptr(), convert))
return false;
value.push_back((Value) conv);
}
......@@ -43,17 +42,15 @@ public:
}
static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
object list(PyList_New(src.size()), false);
if (!list)
return nullptr;
list l(src.size());
size_t index = 0;
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_)
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() + _(">"));
};
......@@ -68,8 +65,8 @@ public:
return false;
value.clear();
key_conv conv;
for (const object &o: s) {
if (!conv.load((PyObject *) o.ptr(), convert))
for (auto entry : s) {
if (!conv.load(entry.ptr(), convert))
return false;
value.insert((Key) conv);
}
......@@ -77,15 +74,13 @@ public:
}
static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
object set(PySet_New(nullptr), false);
if (!set)
return nullptr;
pybind11::set s;
for (auto const &value: src) {
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 set.release();
return s.release();
}
PYBIND11_TYPE_CASTER(type, _("set<") + key_conv::name() + _(">"));
};
......@@ -97,16 +92,15 @@ public:
typedef type_caster<Value> value_conv;
bool load(PyObject *src, bool convert) {
if (!PyDict_Check(src))
dict d(src, true);
if (!d.check())
return false;
value.clear();
PyObject *key_, *value_;
ssize_t pos = 0;
key_conv kconv;
value_conv vconv;
while (PyDict_Next(src, &pos, &key_, &value_)) {
if (!kconv.load(key_, convert) || !vconv.load(value_, convert))
value.clear();
for (auto it : d) {
if (!kconv.load(it.first.ptr(), convert) ||
!vconv.load(it.second.ptr(), convert))
return false;
value[(Key) kconv] = (Value) vconv;
}
......@@ -114,16 +108,15 @@ public:
}
static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
object dict(PyDict_New(), false);
if (!dict)
return nullptr;
dict d;
for (auto const &kv: src) {
object key(key_conv::cast(kv.first, 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;
d[key] = value;
}
return dict.release();
return d.release();
}
PYBIND11_TYPE_CASTER(type, _("dict<") + key_conv::name() + _(", ") + value_conv::name() + _(">"));
......@@ -131,7 +124,10 @@ public:
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)
......
......@@ -11,6 +11,7 @@
#include <cstdio>
#include <cstdlib>
#if defined(__GNUG__)
#include <cxxabi.h>
#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__)
int status = 0;
std::unique_ptr<char, void (*)(void *)> res {
......
......@@ -17,6 +17,7 @@ setup(
headers=[
'include/pybind11/cast.h',
'include/pybind11/complex.h',
'include/pybind11/descr.h',
'include/pybind11/numpy.h',
'include/pybind11/pybind11.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.
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
codebase requires less than 3000 lines of code and only depends on Python (2.7
or 3.x) and the C++ standard library. This compact implementation was
possible thanks to some of the new C++11 language features (tuples, lambda
functions and variadic templates). Since its creation, this library has
grown beyond Boost.Python in many ways, leading to dramatically simpler binding
code in many common situations.""",
)
everything stripped away that isn't relevant for binding generation. The core
header files only require ~2.5K lines of code and depend on Python (2.7 or 3.x)
and the C++ standard library. This compact implementation was possible thanks
to some of the new C++11 language features (specifically: tuples, lambda
functions and variadic templates). Since its creation, this library has grown
beyond Boost.Python in many ways, leading to dramatically 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