support for ancient Python versions (2.7.x)

This commit is contained in:
Wenzel Jakob 2015-09-04 23:42:12 +02:00
parent d557e1d3ad
commit 570822102c
20 changed files with 235 additions and 60 deletions

View File

@ -17,8 +17,8 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
endif() endif()
set(Python_ADDITIONAL_VERSIONS 3.4 3.5 3.6) set(Python_ADDITIONAL_VERSIONS 3.4 3.5 3.6)
find_package(PythonLibs 3 REQUIRED) find_package(PythonLibs REQUIRED)
find_package(PythonInterp 3 REQUIRED) find_package(PythonInterp REQUIRED)
string(TOUPPER "${CMAKE_BUILD_TYPE}" U_CMAKE_BUILD_TYPE) string(TOUPPER "${CMAKE_BUILD_TYPE}" U_CMAKE_BUILD_TYPE)
if (UNIX) if (UNIX)

View File

@ -19,10 +19,10 @@ 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 whole
codebase requires just over 2000 lines of code and only depends on Python and codebase requires less than 3000 lines of code and only depends on Python (2.7
the C++ standard library. This compact implementation was possible thanks to or 3.x) and the C++ standard library. This compact implementation was possible
some of the new C++11 language features (tuples, lambda functions and variadic thanks to some of the new C++11 language features (tuples, lambda functions and
templates), and by only targeting Python 3.x and higher. variadic templates).
## Core features ## Core features
The following core C++ features can be mapped to Python The following core C++ features can be mapped to Python

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python
from __future__ import print_function
import sys import sys
sys.path.append('.') sys.path.append('.')

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python
from __future__ import print_function
import sys import sys
sys.path.append('.') sys.path.append('.')

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python
from __future__ import print_function
import sys, pydoc import sys, pydoc
sys.path.append('.') sys.path.append('.')

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python
from __future__ import print_function
import sys, pydoc import sys, pydoc
sys.path.append('.') sys.path.append('.')

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python
from __future__ import print_function
import sys import sys
sys.path.append('.') sys.path.append('.')

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python
from __future__ import print_function
import sys import sys
sys.path.append('.') sys.path.append('.')

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python
from __future__ import print_function
import sys import sys
sys.path.append('.') sys.path.append('.')

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python
from __future__ import print_function
import sys import sys
sys.path.append('.') sys.path.append('.')

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python
from __future__ import print_function
import sys import sys
sys.path.append('.') sys.path.append('.')

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python
from __future__ import print_function
import sys import sys
sys.path.append('.') sys.path.append('.')

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python
from __future__ import print_function
import sys import sys
sys.path.append('.') sys.path.append('.')

View File

@ -25,7 +25,7 @@ NAMESPACE_BEGIN(detail)
#endif #endif
/** Linked list descriptor type for function signatures (produces smaller binaries /** Linked list descriptor type for function signatures (produces smaller binaries
* compared to a previous solution using std::string and operator +=) */ compared to a previous solution using std::string and operator +=) */
class descr { class descr {
public: public:
struct entry { struct entry {
@ -241,18 +241,42 @@ protected:
PYBIND_TYPE_CASTER(type, #type); \ PYBIND_TYPE_CASTER(type, #type); \
}; };
#if PY_MAJOR_VERSION >= 3
#define PyLong_AsUnsignedLongLong_Fixed PyLong_AsUnsignedLongLong
#define PyLong_AsLongLong_Fixed PyLong_AsLongLong
#else
inline PY_LONG_LONG PyLong_AsLongLong_Fixed(PyObject *o) {
if (PyInt_Check(o))
return (PY_LONG_LONG) PyLong_AsLong(o);
else
return ::PyLong_AsLongLong(o);
}
inline unsigned PY_LONG_LONG PyLong_AsUnsignedLongLong_Fixed(PyObject *o) {
if (PyInt_Check(o))
return (unsigned PY_LONG_LONG) PyLong_AsUnsignedLong(o);
else
return ::PyLong_AsUnsignedLongLong(o);
}
#endif
PYBIND_TYPE_CASTER_NUMBER(int8_t, long, PyLong_AsLong, PyLong_FromLong) PYBIND_TYPE_CASTER_NUMBER(int8_t, long, PyLong_AsLong, PyLong_FromLong)
PYBIND_TYPE_CASTER_NUMBER(uint8_t, unsigned long, PyLong_AsUnsignedLong, PyLong_FromUnsignedLong) PYBIND_TYPE_CASTER_NUMBER(uint8_t, unsigned long, PyLong_AsUnsignedLong, PyLong_FromUnsignedLong)
PYBIND_TYPE_CASTER_NUMBER(int16_t, long, PyLong_AsLong, PyLong_FromLong) PYBIND_TYPE_CASTER_NUMBER(int16_t, long, PyLong_AsLong, PyLong_FromLong)
PYBIND_TYPE_CASTER_NUMBER(uint16_t, unsigned long, PyLong_AsUnsignedLong, PyLong_FromUnsignedLong) PYBIND_TYPE_CASTER_NUMBER(uint16_t, unsigned long, PyLong_AsUnsignedLong, PyLong_FromUnsignedLong)
PYBIND_TYPE_CASTER_NUMBER(int32_t, long, PyLong_AsLong, PyLong_FromLong) PYBIND_TYPE_CASTER_NUMBER(int32_t, long, PyLong_AsLong, PyLong_FromLong)
PYBIND_TYPE_CASTER_NUMBER(uint32_t, unsigned long, PyLong_AsUnsignedLong, PyLong_FromUnsignedLong) PYBIND_TYPE_CASTER_NUMBER(uint32_t, unsigned long, PyLong_AsUnsignedLong, PyLong_FromUnsignedLong)
PYBIND_TYPE_CASTER_NUMBER(int64_t, PY_LONG_LONG, PyLong_AsLongLong, PyLong_FromLongLong) PYBIND_TYPE_CASTER_NUMBER(int64_t, PY_LONG_LONG, PyLong_AsLongLong_Fixed, PyLong_FromLongLong)
PYBIND_TYPE_CASTER_NUMBER(uint64_t, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong, PyLong_FromUnsignedLongLong) PYBIND_TYPE_CASTER_NUMBER(uint64_t, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong_Fixed, PyLong_FromUnsignedLongLong)
#if defined(__APPLE__) // size_t/ssize_t are separate types on Mac OS X #if defined(__APPLE__) // size_t/ssize_t are separate types on Mac OS X
#if PY_MAJOR_VERSION >= 3
PYBIND_TYPE_CASTER_NUMBER(ssize_t, Py_ssize_t, PyLong_AsSsize_t, PyLong_FromSsize_t) PYBIND_TYPE_CASTER_NUMBER(ssize_t, Py_ssize_t, PyLong_AsSsize_t, PyLong_FromSsize_t)
PYBIND_TYPE_CASTER_NUMBER(size_t, size_t, PyLong_AsSize_t, PyLong_FromSize_t) PYBIND_TYPE_CASTER_NUMBER(size_t, size_t, PyLong_AsSize_t, PyLong_FromSize_t)
#else
PYBIND_TYPE_CASTER_NUMBER(ssize_t, PY_LONG_LONG, PyLong_AsLongLong_Fixed, PyLong_FromLongLong)
PYBIND_TYPE_CASTER_NUMBER(size_t, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong_Fixed, PyLong_FromUnsignedLongLong)
#endif
#endif #endif
PYBIND_TYPE_CASTER_NUMBER(float, double, PyFloat_AsDouble, PyFloat_FromDouble) PYBIND_TYPE_CASTER_NUMBER(float, double, PyFloat_AsDouble, PyFloat_FromDouble)
@ -286,7 +310,19 @@ public:
template <> class type_caster<std::string> { template <> class type_caster<std::string> {
public: public:
bool load(PyObject *src, bool) { bool load(PyObject *src, bool) {
#if PY_MAJOR_VERSION >= 3
const char *ptr = PyUnicode_AsUTF8(src); const char *ptr = PyUnicode_AsUTF8(src);
#else
const char *ptr = nullptr;
object temp;
if (PyString_Check(src)) {
ptr = PyString_AsString(src);
} else {
temp = object(PyUnicode_AsUTF8String(src), false);
if (temp.ptr() != nullptr)
ptr = PyString_AsString(temp.ptr());
}
#endif
if (!ptr) { PyErr_Clear(); return false; } if (!ptr) { PyErr_Clear(); return false; }
value = std::string(ptr); value = std::string(ptr);
return true; return true;
@ -301,13 +337,25 @@ public:
template <> class type_caster<std::wstring> { template <> class type_caster<std::wstring> {
public: public:
bool load(PyObject *src, bool) { bool load(PyObject *src, bool) {
#if PY_MAJOR_VERSION >= 3
const wchar_t *ptr = PyUnicode_AsWideCharString(src, nullptr); const wchar_t *ptr = PyUnicode_AsWideCharString(src, nullptr);
#else
object temp(PyUnicode_AsUTF16String(src), false);
if (temp.ptr() == nullptr)
return false;
const wchar_t *ptr = (wchar_t*) PyString_AsString(temp.ptr());
#endif
if (!ptr) { PyErr_Clear(); return false; } if (!ptr) { PyErr_Clear(); return false; }
value = std::wstring(ptr); value = std::wstring(ptr);
return true; return true;
} }
static PyObject *cast(const std::wstring &src, return_value_policy /* policy */, PyObject * /* parent */) { static PyObject *cast(const std::wstring &src, return_value_policy /* policy */, PyObject * /* parent */) {
#if PY_MAJOR_VERSION >= 3
return PyUnicode_FromWideChar(src.c_str(), src.length()); return PyUnicode_FromWideChar(src.c_str(), src.length());
#else
return PyUnicode_DecodeUTF16((const char *) src.c_str(), src.length() * 2, "strict", nullptr);
#endif
} }
PYBIND_TYPE_CASTER(std::wstring, "wstr"); PYBIND_TYPE_CASTER(std::wstring, "wstr");
}; };
@ -316,7 +364,14 @@ public:
template <> class type_caster<char> { template <> class type_caster<char> {
public: public:
bool load(PyObject *src, bool) { bool load(PyObject *src, bool) {
#if PY_MAJOR_VERSION >= 3
char *ptr = PyUnicode_AsUTF8(src); char *ptr = PyUnicode_AsUTF8(src);
#else
temp = object(PyUnicode_AsLatin1String(src), false);
if (temp.ptr() == nullptr)
return false;
char *ptr = PyString_AsString(temp.ptr());
#endif
if (!ptr) { PyErr_Clear(); return false; } if (!ptr) { PyErr_Clear(); return false; }
value = ptr; value = ptr;
return true; return true;
@ -337,6 +392,9 @@ public:
operator char() { return *value; } operator char() { return *value; }
protected: protected:
char *value; char *value;
#if PY_MAJOR_VERSION < 3
object temp;
#endif
}; };
template <typename T1, typename T2> class type_caster<std::pair<T1, T2>> { template <typename T1, typename T2> class type_caster<std::pair<T1, T2>> {

View File

@ -24,9 +24,6 @@
#endif #endif
#endif #endif
#define PYTHON_PLUGIN(name) \
extern "C" PYTHON_EXPORT PyObject *PyInit_##name()
#include <vector> #include <vector>
#include <string> #include <string>
#include <stdexcept> #include <stdexcept>
@ -37,7 +34,7 @@
#if defined(_MSC_VER) #if defined(_MSC_VER)
#define HAVE_ROUND #define HAVE_ROUND
#pragma warning(push) #pragma warning(push)
#pragma warning(disable: 4510 4610 4512) #pragma warning(disable: 4510 4610 4512 4005)
#if _DEBUG #if _DEBUG
#define _DEBUG_MARKER #define _DEBUG_MARKER
#undef _DEBUG #undef _DEBUG
@ -61,6 +58,14 @@
#pragma warning(pop) #pragma warning(pop)
#endif #endif
#if PY_MAJOR_VERSION >= 3
#define PYTHON_PLUGIN(name) \
extern "C" PYTHON_EXPORT PyObject *PyInit_##name()
#else
#define PYTHON_PLUGIN(name) \
extern "C" PYTHON_EXPORT PyObject *init##name()
#endif
NAMESPACE_BEGIN(pybind) NAMESPACE_BEGIN(pybind)
typedef Py_ssize_t ssize_t; typedef Py_ssize_t ssize_t;

View File

@ -47,7 +47,11 @@ public:
static API lookup() { static API lookup() {
PyObject *numpy = PyImport_ImportModule("numpy.core.multiarray"); PyObject *numpy = PyImport_ImportModule("numpy.core.multiarray");
PyObject *capsule = numpy ? PyObject_GetAttrString(numpy, "_ARRAY_API") : nullptr; PyObject *capsule = numpy ? PyObject_GetAttrString(numpy, "_ARRAY_API") : nullptr;
#if PY_MAJOR_VERSION >= 3
void **api_ptr = (void **) (capsule ? PyCapsule_GetPointer(capsule, NULL) : nullptr); void **api_ptr = (void **) (capsule ? PyCapsule_GetPointer(capsule, NULL) : nullptr);
#else
void **api_ptr = (void **) (capsule ? PyCObject_AsVoidPtr(capsule) : nullptr);
#endif
Py_XDECREF(capsule); Py_XDECREF(capsule);
Py_XDECREF(numpy); Py_XDECREF(numpy);
if (api_ptr == nullptr) if (api_ptr == nullptr)

View File

@ -103,7 +103,11 @@ inline op_<op_##id, op_u, self_t, undefined_t> op(const self_t &) {
PYBIND_BINARY_OPERATOR(sub, rsub, operator-, l - r) PYBIND_BINARY_OPERATOR(sub, rsub, operator-, l - r)
PYBIND_BINARY_OPERATOR(add, radd, operator+, l + r) PYBIND_BINARY_OPERATOR(add, radd, operator+, l + r)
PYBIND_BINARY_OPERATOR(mul, rmul, operator*, l * r) PYBIND_BINARY_OPERATOR(mul, rmul, operator*, l * r)
#if PY_MAJOR_VERSION >= 3
PYBIND_BINARY_OPERATOR(truediv, rtruediv, operator/, l / r) PYBIND_BINARY_OPERATOR(truediv, rtruediv, operator/, l / r)
#else
PYBIND_BINARY_OPERATOR(div, rdiv, operator/, l / r)
#endif
PYBIND_BINARY_OPERATOR(mod, rmod, operator%, l % r) PYBIND_BINARY_OPERATOR(mod, rmod, operator%, l % r)
PYBIND_BINARY_OPERATOR(lshift, rlshift, operator<<, l << r) PYBIND_BINARY_OPERATOR(lshift, rlshift, operator<<, l << r)
PYBIND_BINARY_OPERATOR(rshift, rrshift, operator>>, l >> r) PYBIND_BINARY_OPERATOR(rshift, rrshift, operator>>, l >> r)

View File

@ -45,7 +45,14 @@ template <typename T> struct arg_t : public arg {
template <typename T> inline arg_t<T> arg::operator=(const T &value) { return arg_t<T>(name, value); } template <typename T> inline arg_t<T> arg::operator=(const T &value) { return arg_t<T>(name, value); }
/// Annotation for methods /// Annotation for methods
struct is_method { }; struct is_method {
#if PY_MAJOR_VERSION < 3
PyObject *class_;
is_method(object *o) : class_(o->ptr()) { }
#else
is_method(object *) { }
#endif
};
/// Annotation for documentation /// Annotation for documentation
struct doc { const char *value; doc(const char *value) : value(value) { } }; struct doc { const char *value; doc(const char *value) : value(value) { } };
@ -69,11 +76,16 @@ private:
short keywords = 0; short keywords = 0;
return_value_policy policy = return_value_policy::automatic; return_value_policy policy = return_value_policy::automatic;
std::string signature; std::string signature;
#if PY_MAJOR_VERSION < 3
PyObject *class_ = nullptr;
#endif
PyObject *sibling = nullptr; PyObject *sibling = nullptr;
const char *doc = nullptr; const char *doc = nullptr;
function_entry *next = nullptr; function_entry *next = nullptr;
}; };
function_entry *m_entry;
/// Picks a suitable return value converter from cast.h /// Picks a suitable return value converter from cast.h
template <typename T> using return_value_caster = template <typename T> using return_value_caster =
detail::type_caster<typename std::conditional< detail::type_caster<typename std::conditional<
@ -122,7 +134,14 @@ private:
def[entry->keywords++] = strdup(std::to_string(a.value).c_str()); def[entry->keywords++] = strdup(std::to_string(a.value).c_str());
} }
static void process_extra(const pybind::is_method &, function_entry *entry, const char **, const char **) { entry->is_method = true; } static void process_extra(const pybind::is_method &m, function_entry *entry, const char **, const char **) {
entry->is_method = true;
#if PY_MAJOR_VERSION < 3
entry->class_ = m.class_;
#else
(void) m;
#endif
}
static void process_extra(const pybind::return_value_policy p, function_entry *entry, const char **, const char **) { entry->policy = p; } static void process_extra(const pybind::return_value_policy p, function_entry *entry, const char **, const char **) { entry->policy = p; }
static void process_extra(pybind::sibling s, function_entry *entry, const char **, const char **) { entry->sibling = s.value; } static void process_extra(pybind::sibling s, function_entry *entry, const char **, const char **) { entry->sibling = s.value; }
@ -170,13 +189,13 @@ public:
std::tuple<Extra...> extras; std::tuple<Extra...> extras;
}; };
function_entry *entry = new function_entry(); m_entry = new function_entry();
entry->data = new capture { f, std::tuple<Extra...>(std::forward<Extra>(extra)...) }; m_entry->data = new capture { f, std::tuple<Extra...>(std::forward<Extra>(extra)...) };
typedef arg_value_caster<Arg...> cast_in; typedef arg_value_caster<Arg...> cast_in;
typedef return_value_caster<Return> cast_out; typedef return_value_caster<Return> cast_out;
entry->impl = [](function_entry *entry, PyObject *pyArgs, PyObject *kwargs, PyObject *parent) -> PyObject * { m_entry->impl = [](function_entry *entry, PyObject *pyArgs, PyObject *kwargs, PyObject *parent) -> PyObject * {
capture *data = (capture *) entry->data; capture *data = (capture *) entry->data;
process_extras(data->extras, pyArgs, kwargs, entry->is_method); process_extras(data->extras, pyArgs, kwargs, entry->is_method);
cast_in args; cast_in args;
@ -187,14 +206,14 @@ public:
const int N = sizeof...(Extra) > sizeof...(Arg) ? sizeof...(Extra) : sizeof...(Arg); const int N = sizeof...(Extra) > sizeof...(Arg) ? sizeof...(Extra) : sizeof...(Arg);
std::array<const char *, N> kw{}, def{}; std::array<const char *, N> kw{}, def{};
process_extras(((capture *) entry->data)->extras, entry, kw.data(), def.data()); process_extras(((capture *) m_entry->data)->extras, m_entry, kw.data(), def.data());
detail::descr d = cast_in::name(kw.data(), def.data()); detail::descr d = cast_in::name(kw.data(), def.data());
d += " -> "; d += " -> ";
d += std::move(cast_out::name()); d += std::move(cast_out::name());
initialize(entry, d, sizeof...(Arg)); initialize(d, sizeof...(Arg));
} }
/// Delegating helper constructor to deal with lambda functions /// Delegating helper constructor to deal with lambda functions
@ -219,6 +238,9 @@ public:
(Return (*)(const Class *, Arg ...)) nullptr, std::forward<Extra>(extra)...); (Return (*)(const Class *, Arg ...)) nullptr, std::forward<Extra>(extra)...);
} }
/// Return the function name
const char *name() const { return m_entry->name; }
private: private:
/// Functors, lambda functions, etc. /// Functors, lambda functions, etc.
template <typename Func, typename Return, typename... Arg, typename... Extra> template <typename Func, typename Return, typename... Arg, typename... Extra>
@ -228,13 +250,13 @@ private:
std::tuple<Extra...> extras; std::tuple<Extra...> extras;
}; };
function_entry *entry = new function_entry(); m_entry = new function_entry();
entry->data = new capture { std::forward<Func>(f), std::tuple<Extra...>(std::forward<Extra>(extra)...) }; m_entry->data = new capture { std::forward<Func>(f), std::tuple<Extra...>(std::forward<Extra>(extra)...) };
typedef arg_value_caster<Arg...> cast_in; typedef arg_value_caster<Arg...> cast_in;
typedef return_value_caster<Return> cast_out; typedef return_value_caster<Return> cast_out;
entry->impl = [](function_entry *entry, PyObject *pyArgs, PyObject *kwargs, PyObject *parent) -> PyObject *{ m_entry->impl = [](function_entry *entry, PyObject *pyArgs, PyObject *kwargs, PyObject *parent) -> PyObject *{
capture *data = (capture *)entry->data; capture *data = (capture *)entry->data;
process_extras(data->extras, pyArgs, kwargs, entry->is_method); process_extras(data->extras, pyArgs, kwargs, entry->is_method);
cast_in args; cast_in args;
@ -245,13 +267,13 @@ private:
const int N = sizeof...(Extra) > sizeof...(Arg) ? sizeof...(Extra) : sizeof...(Arg); const int N = sizeof...(Extra) > sizeof...(Arg) ? sizeof...(Extra) : sizeof...(Arg);
std::array<const char *, N> kw{}, def{}; std::array<const char *, N> kw{}, def{};
process_extras(((capture *) entry->data)->extras, entry, kw.data(), def.data()); process_extras(((capture *) m_entry->data)->extras, m_entry, kw.data(), def.data());
detail::descr d = cast_in::name(kw.data(), def.data()); detail::descr d = cast_in::name(kw.data(), def.data());
d += " -> "; d += " -> ";
d += std::move(cast_out::name()); d += std::move(cast_out::name());
initialize(entry, d, sizeof...(Arg)); initialize(d, sizeof...(Arg));
} }
static PyObject *dispatcher(PyObject *self, PyObject *args, PyObject *kwargs ) { static PyObject *dispatcher(PyObject *self, PyObject *args, PyObject *kwargs ) {
@ -322,19 +344,31 @@ private:
} }
} }
void initialize(function_entry *entry, const detail::descr &descr, int args) { void initialize(const detail::descr &descr, int args) {
if (entry->name == nullptr) if (m_entry->name == nullptr)
entry->name = ""; m_entry->name = "";
if (entry->keywords != 0 && entry->keywords != args) #if PY_MAJOR_VERSION < 3
if (strcmp(m_entry->name, "__next__") == 0)
m_entry->name = "next";
#endif
if (m_entry->keywords != 0 && m_entry->keywords != args)
throw std::runtime_error( throw std::runtime_error(
"cpp_function(): function \"" + std::string(entry->name) + "\" takes " + "cpp_function(): function \"" + std::string(m_entry->name) + "\" takes " +
std::to_string(args) + " arguments, but " + std::to_string(entry->keywords) + std::to_string(args) + " arguments, but " + std::to_string(m_entry->keywords) +
" pybind::arg entries were specified!"); " pybind::arg entries were specified!");
entry->is_constructor = !strcmp(entry->name, "__init__"); m_entry->is_constructor = !strcmp(m_entry->name, "__init__");
entry->signature = descr.str(); m_entry->signature = descr.str();
#if PY_MAJOR_VERSION < 3
if (m_entry->sibling && PyMethod_Check(m_entry->sibling))
m_entry->sibling = PyMethod_GET_FUNCTION(m_entry->sibling);
#endif
function_entry *entry = m_entry;
bool overloaded = false;
if (!entry->sibling || !PyCFunction_Check(entry->sibling)) { if (!entry->sibling || !PyCFunction_Check(entry->sibling)) {
entry->def = new PyMethodDef(); entry->def = new PyMethodDef();
memset(entry->def, 0, sizeof(PyMethodDef)); memset(entry->def, 0, sizeof(PyMethodDef));
@ -354,13 +388,14 @@ private:
parent = parent->next; parent = parent->next;
parent->next = entry; parent->next = entry;
entry = backup; entry = backup;
overloaded = true;
} }
std::string signatures; std::string signatures;
int index = 0; int index = 0;
function_entry *it = entry; function_entry *it = entry;
while (it) { /* Create pydoc it */ while (it) { /* Create pydoc it */
if (it->sibling) if (overloaded)
signatures += std::to_string(++index) + ". "; signatures += std::to_string(++index) + ". ";
signatures += "Signature : " + std::string(it->signature) + "\n"; signatures += "Signature : " + std::string(it->signature) + "\n";
if (it->doc && strlen(it->doc) > 0) if (it->doc && strlen(it->doc) > 0)
@ -374,7 +409,11 @@ private:
std::free((char *) func->m_ml->ml_doc); std::free((char *) func->m_ml->ml_doc);
func->m_ml->ml_doc = strdup(signatures.c_str()); func->m_ml->ml_doc = strdup(signatures.c_str());
if (entry->is_method) { if (entry->is_method) {
#if PY_MAJOR_VERSION >= 3
m_ptr = PyInstanceMethod_New(m_ptr); m_ptr = PyInstanceMethod_New(m_ptr);
#else
m_ptr = PyMethod_New(m_ptr, nullptr, entry->class_);
#endif
if (!m_ptr) if (!m_ptr)
throw std::runtime_error("cpp_function::cpp_function(): Could not allocate instance method object"); throw std::runtime_error("cpp_function::cpp_function(): Could not allocate instance method object");
Py_DECREF(func); Py_DECREF(func);
@ -387,6 +426,7 @@ public:
PYBIND_OBJECT_DEFAULT(module, object, PyModule_Check) PYBIND_OBJECT_DEFAULT(module, object, PyModule_Check)
module(const char *name, const char *doc = nullptr) { module(const char *name, const char *doc = nullptr) {
#if PY_MAJOR_VERSION >= 3
PyModuleDef *def = new PyModuleDef(); PyModuleDef *def = new PyModuleDef();
memset(def, 0, sizeof(PyModuleDef)); memset(def, 0, sizeof(PyModuleDef));
def->m_name = name; def->m_name = name;
@ -394,6 +434,9 @@ public:
def->m_size = -1; def->m_size = -1;
Py_INCREF(def); Py_INCREF(def);
m_ptr = PyModule_Create(def); m_ptr = PyModule_Create(def);
#else
m_ptr = Py_InitModule3(name, nullptr, doc);
#endif
if (m_ptr == nullptr) if (m_ptr == nullptr)
throw std::runtime_error("Internal error in module::module()"); throw std::runtime_error("Internal error in module::module()");
inc_ref(); inc_ref();
@ -430,7 +473,11 @@ public:
void (*init_holder)(PyObject *), const destructor &dealloc, void (*init_holder)(PyObject *), const destructor &dealloc,
PyObject *parent, const char *doc) { PyObject *parent, const char *doc) {
PyHeapTypeObject *type = (PyHeapTypeObject*) PyType_Type.tp_alloc(&PyType_Type, 0); PyHeapTypeObject *type = (PyHeapTypeObject*) PyType_Type.tp_alloc(&PyType_Type, 0);
#if PY_MAJOR_VERSION >= 3
PyObject *name = PyUnicode_FromString(name_); PyObject *name = PyUnicode_FromString(name_);
#else
PyObject *name = PyString_FromString(name_);
#endif
if (type == nullptr || name == nullptr) if (type == nullptr || name == nullptr)
throw std::runtime_error("Internal error in custom_type::custom_type()"); throw std::runtime_error("Internal error in custom_type::custom_type()");
Py_INCREF(name); Py_INCREF(name);
@ -444,7 +491,10 @@ public:
if (module_name.check()) if (module_name.check())
full_name = std::string(module_name) + "." + full_name; full_name = std::string(module_name) + "." + full_name;
type->ht_name = type->ht_qualname = name; type->ht_name = name;
#if PY_MAJOR_VERSION >= 3
type->ht_qualname = name;
#endif
type->ht_type.tp_name = strdup(full_name.c_str()); type->ht_type.tp_name = strdup(full_name.c_str());
type->ht_type.tp_basicsize = instance_size; type->ht_type.tp_basicsize = instance_size;
type->ht_type.tp_init = (initproc) init; type->ht_type.tp_init = (initproc) init;
@ -453,6 +503,9 @@ public:
type->ht_type.tp_flags |= type->ht_type.tp_flags |=
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE; Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE;
type->ht_type.tp_flags &= ~Py_TPFLAGS_HAVE_GC; type->ht_type.tp_flags &= ~Py_TPFLAGS_HAVE_GC;
#if PY_MAJOR_VERSION < 3
type->ht_type.tp_flags |= Py_TPFLAGS_CHECKTYPES;
#endif
type->ht_type.tp_as_number = &type->as_number; type->ht_type.tp_as_number = &type->as_number;
type->ht_type.tp_as_sequence = &type->as_sequence; type->ht_type.tp_as_sequence = &type->as_sequence;
type->ht_type.tp_as_mapping = &type->as_mapping; type->ht_type.tp_as_mapping = &type->as_mapping;
@ -482,7 +535,12 @@ protected:
/* Allocate a metaclass on demand (for static properties) */ /* Allocate a metaclass on demand (for static properties) */
handle metaclass() { handle metaclass() {
auto &ht_type = ((PyHeapTypeObject *) m_ptr)->ht_type; auto &ht_type = ((PyHeapTypeObject *) m_ptr)->ht_type;
#if PY_MAJOR_VERSION >= 3
auto &ob_type = ht_type.ob_base.ob_base.ob_type; auto &ob_type = ht_type.ob_base.ob_base.ob_type;
#else
auto &ob_type = ht_type.ob_type;
#endif
if (ob_type == &PyType_Type) { if (ob_type == &PyType_Type) {
std::string name_ = std::string(ht_type.tp_name) + "_meta"; std::string name_ = std::string(ht_type.tp_name) + "_meta";
PyHeapTypeObject *type = (PyHeapTypeObject*) PyType_Type.tp_alloc(&PyType_Type, 0); PyHeapTypeObject *type = (PyHeapTypeObject*) PyType_Type.tp_alloc(&PyType_Type, 0);
@ -490,7 +548,10 @@ protected:
if (type == nullptr || name == nullptr) if (type == nullptr || name == nullptr)
throw std::runtime_error("Internal error in custom_type::metaclass()"); throw std::runtime_error("Internal error in custom_type::metaclass()");
Py_INCREF(name); Py_INCREF(name);
type->ht_name = type->ht_qualname = name; type->ht_name = name;
#if PY_MAJOR_VERSION >= 3
type->ht_qualname = name;
#endif
type->ht_type.tp_name = strdup(name_.c_str()); type->ht_type.tp_name = strdup(name_.c_str());
type->ht_type.tp_base = &PyType_Type; type->ht_type.tp_base = &PyType_Type;
type->ht_type.tp_flags |= Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE; type->ht_type.tp_flags |= Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE;
@ -541,6 +602,9 @@ protected:
void *get_buffer_data) { void *get_buffer_data) {
PyHeapTypeObject *type = (PyHeapTypeObject*) m_ptr; PyHeapTypeObject *type = (PyHeapTypeObject*) m_ptr;
type->ht_type.tp_as_buffer = &type->as_buffer; type->ht_type.tp_as_buffer = &type->as_buffer;
#if PY_MAJOR_VERSION < 3
type->ht_type.tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER;
#endif
type->as_buffer.bf_getbuffer = getbuffer; type->as_buffer.bf_getbuffer = getbuffer;
type->as_buffer.bf_releasebuffer = releasebuffer; type->as_buffer.bf_releasebuffer = releasebuffer;
auto info = ((detail::type_info *) capsule(attr("__pybind__"))); auto info = ((detail::type_info *) capsule(attr("__pybind__")));
@ -606,17 +670,19 @@ public:
template <typename Func, typename... Extra> template <typename Func, typename... Extra>
class_ &def(const char *name_, Func&& f, Extra&&... extra) { class_ &def(const char *name_, Func&& f, Extra&&... extra) {
attr(name_) = cpp_function(std::forward<Func>(f), name(name_), cpp_function cf(std::forward<Func>(f), name(name_),
sibling(attr(name_)), is_method(), sibling(attr(name_)), is_method(this),
std::forward<Extra>(extra)...); std::forward<Extra>(extra)...);
attr(cf.name()) = cf;
return *this; return *this;
} }
template <typename Func, typename... Extra> class_ & template <typename Func, typename... Extra> class_ &
def_static(const char *name_, Func f, Extra&&... extra) { def_static(const char *name_, Func f, Extra&&... extra) {
attr(name_) = cpp_function(std::forward<Func>(f), name(name_), cpp_function cf(std::forward<Func>(f), name(name_),
sibling(attr(name_)), sibling(attr(name_)),
std::forward<Extra>(extra)...); std::forward<Extra>(extra)...);
attr(cf.name()) = cf;
return *this; return *this;
} }
@ -654,9 +720,9 @@ public:
class_ &def_readwrite(const char *name, D C::*pm, Extra&&... extra) { class_ &def_readwrite(const char *name, D C::*pm, Extra&&... extra) {
cpp_function fget([pm](const C &c) -> const D &{ return c.*pm; }, cpp_function fget([pm](const C &c) -> const D &{ return c.*pm; },
return_value_policy::reference_internal, return_value_policy::reference_internal,
is_method(), extra...), is_method(this), extra...),
fset([pm](C &c, const D &value) { c.*pm = value; }, fset([pm](C &c, const D &value) { c.*pm = value; },
is_method(), extra...); is_method(this), extra...);
def_property(name, fget, fset); def_property(name, fget, fset);
return *this; return *this;
} }
@ -665,7 +731,7 @@ public:
class_ &def_readonly(const char *name, const D C::*pm, Extra&& ...extra) { class_ &def_readonly(const char *name, const D C::*pm, Extra&& ...extra) {
cpp_function fget([pm](const C &c) -> const D &{ return c.*pm; }, cpp_function fget([pm](const C &c) -> const D &{ return c.*pm; },
return_value_policy::reference_internal, return_value_policy::reference_internal,
is_method(), std::forward<Extra>(extra)...); is_method(this), std::forward<Extra>(extra)...);
def_property_readonly(name, fget); def_property_readonly(name, fget);
return *this; return *this;
} }

View File

@ -213,10 +213,30 @@ class str : public object {
public: public:
PYBIND_OBJECT_DEFAULT(str, object, PyUnicode_Check) PYBIND_OBJECT_DEFAULT(str, object, PyUnicode_Check)
str(const char *s) : object(PyUnicode_FromString(s), false) { } str(const char *s) : object(PyUnicode_FromString(s), false) { }
operator const char *() const { return PyUnicode_AsUTF8(m_ptr); } operator const char *() const {
#if PY_MAJOR_VERSION >= 3
return PyUnicode_AsUTF8(m_ptr);
#else
m_temp = object(PyUnicode_AsUTF8String(m_ptr), false);
if (m_temp.ptr() == nullptr)
return nullptr;
return PyString_AsString(m_temp.ptr());
#endif
}
private:
#if PY_MAJOR_VERSION < 3
mutable object m_temp;
#endif
}; };
inline pybind::str handle::str() const { return pybind::str(PyObject_Str(m_ptr), false); } inline pybind::str handle::str() const {
PyObject *str = PyObject_Str(m_ptr);
#if PY_MAJOR_VERSION < 3
PyObject *unicode = PyUnicode_FromEncodedObject(str, "utf-8", nullptr);
Py_XDECREF(str); str = unicode;
#endif
return pybind::str(str, false);
}
class bool_ : public object { class bool_ : public object {
public: public:
@ -252,7 +272,13 @@ public:
m_ptr = PySlice_New(start.ptr(), stop.ptr(), step.ptr()); m_ptr = PySlice_New(start.ptr(), stop.ptr(), step.ptr());
} }
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(m_ptr, length, start, stop, step, slicelength) == 0; return PySlice_GetIndicesEx(
#if PY_MAJOR_VERSION >= 3
m_ptr,
#else
(PySliceObject *) m_ptr,
#endif
length, start, stop, step, slicelength) == 0;
} }
}; };

View File

@ -100,9 +100,10 @@ public:
PYBIND_TYPE_CASTER(type, detail::descr("dict<") + key_conv::name() + detail::descr(", ") + value_conv::name() + detail::descr(">")); PYBIND_TYPE_CASTER(type, detail::descr("dict<") + key_conv::name() + detail::descr(", ") + value_conv::name() + detail::descr(">"));
}; };
NAMESPACE_END(detail)
inline std::ostream &operator<<(std::ostream &os, const object &obj) { os << (const char *) obj.str(); return os; } inline std::ostream &operator<<(std::ostream &os, const object &obj) { os << (const char *) obj.str(); return os; }
NAMESPACE_END(detail)
NAMESPACE_END(pybind) NAMESPACE_END(pybind)
#if defined(_MSC_VER) #if defined(_MSC_VER)