support for ancient Python versions (2.7.x)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7179616..2e80bd0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -17,8 +17,8 @@
endif()
set(Python_ADDITIONAL_VERSIONS 3.4 3.5 3.6)
-find_package(PythonLibs 3 REQUIRED)
-find_package(PythonInterp 3 REQUIRED)
+find_package(PythonLibs REQUIRED)
+find_package(PythonInterp REQUIRED)
string(TOUPPER "${CMAKE_BUILD_TYPE}" U_CMAKE_BUILD_TYPE)
if (UNIX)
diff --git a/README.md b/README.md
index 36e8158..ead5b37 100644
--- a/README.md
+++ b/README.md
@@ -19,10 +19,10 @@
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 just over 2000 lines of code and only depends on Python 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), and by only targeting Python 3.x and higher.
+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).
## Core features
The following core C++ features can be mapped to Python
diff --git a/example/example1.py b/example/example1.py
index 30cda8d..f89b662 100755
--- a/example/example1.py
+++ b/example/example1.py
@@ -1,4 +1,5 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python
+from __future__ import print_function
import sys
sys.path.append('.')
diff --git a/example/example10.py b/example/example10.py
index 401c5cc..96cf9b0 100755
--- a/example/example10.py
+++ b/example/example10.py
@@ -1,4 +1,5 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python
+from __future__ import print_function
import sys
sys.path.append('.')
diff --git a/example/example11.py b/example/example11.py
index 733f6de..7fc1b48 100755
--- a/example/example11.py
+++ b/example/example11.py
@@ -1,4 +1,5 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python
+from __future__ import print_function
import sys, pydoc
sys.path.append('.')
diff --git a/example/example2.py b/example/example2.py
index b0f4707..2782da5 100755
--- a/example/example2.py
+++ b/example/example2.py
@@ -1,4 +1,5 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python
+from __future__ import print_function
import sys, pydoc
sys.path.append('.')
diff --git a/example/example3.py b/example/example3.py
index a889320..41cf314 100755
--- a/example/example3.py
+++ b/example/example3.py
@@ -1,4 +1,5 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python
+from __future__ import print_function
import sys
sys.path.append('.')
diff --git a/example/example4.py b/example/example4.py
index aa2a448..a926c14 100755
--- a/example/example4.py
+++ b/example/example4.py
@@ -1,4 +1,5 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python
+from __future__ import print_function
import sys
sys.path.append('.')
diff --git a/example/example5.py b/example/example5.py
index 7e0dfd0..4e75e17 100755
--- a/example/example5.py
+++ b/example/example5.py
@@ -1,4 +1,5 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python
+from __future__ import print_function
import sys
sys.path.append('.')
diff --git a/example/example6.py b/example/example6.py
index 7dbadc4..5a014dd 100755
--- a/example/example6.py
+++ b/example/example6.py
@@ -1,4 +1,5 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python
+from __future__ import print_function
import sys
sys.path.append('.')
diff --git a/example/example7.py b/example/example7.py
index 565ceac..3bfddb0 100755
--- a/example/example7.py
+++ b/example/example7.py
@@ -1,4 +1,5 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python
+from __future__ import print_function
import sys
sys.path.append('.')
diff --git a/example/example8.py b/example/example8.py
index 9c295d2..e918a77 100755
--- a/example/example8.py
+++ b/example/example8.py
@@ -1,4 +1,5 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python
+from __future__ import print_function
import sys
sys.path.append('.')
diff --git a/example/example9.py b/example/example9.py
index d8c654e..9a29353 100755
--- a/example/example9.py
+++ b/example/example9.py
@@ -1,4 +1,5 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python
+from __future__ import print_function
import sys
sys.path.append('.')
diff --git a/include/pybind/cast.h b/include/pybind/cast.h
index a46f9fb..2feaf84 100644
--- a/include/pybind/cast.h
+++ b/include/pybind/cast.h
@@ -25,7 +25,7 @@
#endif
/** 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 {
public:
struct entry {
@@ -241,18 +241,42 @@
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(uint8_t, unsigned long, PyLong_AsUnsignedLong, PyLong_FromUnsignedLong)
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(int32_t, long, PyLong_AsLong, PyLong_FromLong)
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(uint64_t, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong, PyLong_FromUnsignedLongLong)
+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_Fixed, PyLong_FromUnsignedLongLong)
#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(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
PYBIND_TYPE_CASTER_NUMBER(float, double, PyFloat_AsDouble, PyFloat_FromDouble)
@@ -286,7 +310,19 @@
template <> class type_caster<std::string> {
public:
bool load(PyObject *src, bool) {
+#if PY_MAJOR_VERSION >= 3
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; }
value = std::string(ptr);
return true;
@@ -301,13 +337,25 @@
template <> class type_caster<std::wstring> {
public:
bool load(PyObject *src, bool) {
+#if PY_MAJOR_VERSION >= 3
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; }
value = std::wstring(ptr);
return true;
}
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());
+#else
+ return PyUnicode_DecodeUTF16((const char *) src.c_str(), src.length() * 2, "strict", nullptr);
+#endif
}
PYBIND_TYPE_CASTER(std::wstring, "wstr");
};
@@ -316,7 +364,14 @@
template <> class type_caster<char> {
public:
bool load(PyObject *src, bool) {
+#if PY_MAJOR_VERSION >= 3
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; }
value = ptr;
return true;
@@ -337,6 +392,9 @@
operator char() { return *value; }
protected:
char *value;
+#if PY_MAJOR_VERSION < 3
+ object temp;
+#endif
};
template <typename T1, typename T2> class type_caster<std::pair<T1, T2>> {
diff --git a/include/pybind/common.h b/include/pybind/common.h
index 8a9850d..d327ab6 100644
--- a/include/pybind/common.h
+++ b/include/pybind/common.h
@@ -24,9 +24,6 @@
#endif
#endif
-#define PYTHON_PLUGIN(name) \
- extern "C" PYTHON_EXPORT PyObject *PyInit_##name()
-
#include <vector>
#include <string>
#include <stdexcept>
@@ -37,7 +34,7 @@
#if defined(_MSC_VER)
#define HAVE_ROUND
#pragma warning(push)
-#pragma warning(disable: 4510 4610 4512)
+#pragma warning(disable: 4510 4610 4512 4005)
#if _DEBUG
#define _DEBUG_MARKER
#undef _DEBUG
@@ -61,6 +58,14 @@
#pragma warning(pop)
#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)
typedef Py_ssize_t ssize_t;
diff --git a/include/pybind/numpy.h b/include/pybind/numpy.h
index d101013..3042800 100644
--- a/include/pybind/numpy.h
+++ b/include/pybind/numpy.h
@@ -47,7 +47,11 @@
static API lookup() {
PyObject *numpy = PyImport_ImportModule("numpy.core.multiarray");
PyObject *capsule = numpy ? PyObject_GetAttrString(numpy, "_ARRAY_API") : nullptr;
+#if PY_MAJOR_VERSION >= 3
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(numpy);
if (api_ptr == nullptr)
diff --git a/include/pybind/operators.h b/include/pybind/operators.h
index e0f858f..84fc4c2 100644
--- a/include/pybind/operators.h
+++ b/include/pybind/operators.h
@@ -103,7 +103,11 @@
PYBIND_BINARY_OPERATOR(sub, rsub, operator-, l - r)
PYBIND_BINARY_OPERATOR(add, radd, operator+, l + r)
PYBIND_BINARY_OPERATOR(mul, rmul, operator*, l * r)
+#if PY_MAJOR_VERSION >= 3
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(lshift, rlshift, operator<<, l << r)
PYBIND_BINARY_OPERATOR(rshift, rrshift, operator>>, l >> r)
diff --git a/include/pybind/pybind.h b/include/pybind/pybind.h
index fa2cffd..45ce9e4 100644
--- a/include/pybind/pybind.h
+++ b/include/pybind/pybind.h
@@ -45,7 +45,14 @@
template <typename T> inline arg_t<T> arg::operator=(const T &value) { return arg_t<T>(name, value); }
/// 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
struct doc { const char *value; doc(const char *value) : value(value) { } };
@@ -69,11 +76,16 @@
short keywords = 0;
return_value_policy policy = return_value_policy::automatic;
std::string signature;
+#if PY_MAJOR_VERSION < 3
+ PyObject *class_ = nullptr;
+#endif
PyObject *sibling = nullptr;
const char *doc = nullptr;
function_entry *next = nullptr;
};
+ function_entry *m_entry;
+
/// Picks a suitable return value converter from cast.h
template <typename T> using return_value_caster =
detail::type_caster<typename std::conditional<
@@ -122,7 +134,14 @@
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(pybind::sibling s, function_entry *entry, const char **, const char **) { entry->sibling = s.value; }
@@ -170,13 +189,13 @@
std::tuple<Extra...> extras;
};
- function_entry *entry = new function_entry();
- entry->data = new capture { f, std::tuple<Extra...>(std::forward<Extra>(extra)...) };
+ m_entry = new function_entry();
+ m_entry->data = new capture { f, std::tuple<Extra...>(std::forward<Extra>(extra)...) };
typedef arg_value_caster<Arg...> cast_in;
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;
process_extras(data->extras, pyArgs, kwargs, entry->is_method);
cast_in args;
@@ -187,14 +206,14 @@
const int N = sizeof...(Extra) > sizeof...(Arg) ? sizeof...(Extra) : sizeof...(Arg);
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());
d += " -> ";
d += std::move(cast_out::name());
- initialize(entry, d, sizeof...(Arg));
+ initialize(d, sizeof...(Arg));
}
/// Delegating helper constructor to deal with lambda functions
@@ -219,6 +238,9 @@
(Return (*)(const Class *, Arg ...)) nullptr, std::forward<Extra>(extra)...);
}
+ /// Return the function name
+ const char *name() const { return m_entry->name; }
+
private:
/// Functors, lambda functions, etc.
template <typename Func, typename Return, typename... Arg, typename... Extra>
@@ -228,13 +250,13 @@
std::tuple<Extra...> extras;
};
- function_entry *entry = new function_entry();
- entry->data = new capture { std::forward<Func>(f), std::tuple<Extra...>(std::forward<Extra>(extra)...) };
+ m_entry = new function_entry();
+ m_entry->data = new capture { std::forward<Func>(f), std::tuple<Extra...>(std::forward<Extra>(extra)...) };
typedef arg_value_caster<Arg...> cast_in;
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;
process_extras(data->extras, pyArgs, kwargs, entry->is_method);
cast_in args;
@@ -245,13 +267,13 @@
const int N = sizeof...(Extra) > sizeof...(Arg) ? sizeof...(Extra) : sizeof...(Arg);
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());
d += " -> ";
d += std::move(cast_out::name());
- initialize(entry, d, sizeof...(Arg));
+ initialize(d, sizeof...(Arg));
}
static PyObject *dispatcher(PyObject *self, PyObject *args, PyObject *kwargs ) {
@@ -322,19 +344,31 @@
}
}
- void initialize(function_entry *entry, const detail::descr &descr, int args) {
- if (entry->name == nullptr)
- entry->name = "";
+ void initialize(const detail::descr &descr, int args) {
+ if (m_entry->name == nullptr)
+ 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(
- "cpp_function(): function \"" + std::string(entry->name) + "\" takes " +
- std::to_string(args) + " arguments, but " + std::to_string(entry->keywords) +
+ "cpp_function(): function \"" + std::string(m_entry->name) + "\" takes " +
+ std::to_string(args) + " arguments, but " + std::to_string(m_entry->keywords) +
" pybind::arg entries were specified!");
- entry->is_constructor = !strcmp(entry->name, "__init__");
- entry->signature = descr.str();
+ m_entry->is_constructor = !strcmp(m_entry->name, "__init__");
+ 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)) {
entry->def = new PyMethodDef();
memset(entry->def, 0, sizeof(PyMethodDef));
@@ -354,13 +388,14 @@
parent = parent->next;
parent->next = entry;
entry = backup;
+ overloaded = true;
}
std::string signatures;
int index = 0;
function_entry *it = entry;
while (it) { /* Create pydoc it */
- if (it->sibling)
+ if (overloaded)
signatures += std::to_string(++index) + ". ";
signatures += "Signature : " + std::string(it->signature) + "\n";
if (it->doc && strlen(it->doc) > 0)
@@ -374,7 +409,11 @@
std::free((char *) func->m_ml->ml_doc);
func->m_ml->ml_doc = strdup(signatures.c_str());
if (entry->is_method) {
+#if PY_MAJOR_VERSION >= 3
m_ptr = PyInstanceMethod_New(m_ptr);
+#else
+ 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");
Py_DECREF(func);
@@ -387,6 +426,7 @@
PYBIND_OBJECT_DEFAULT(module, object, PyModule_Check)
module(const char *name, const char *doc = nullptr) {
+#if PY_MAJOR_VERSION >= 3
PyModuleDef *def = new PyModuleDef();
memset(def, 0, sizeof(PyModuleDef));
def->m_name = name;
@@ -394,6 +434,9 @@
def->m_size = -1;
Py_INCREF(def);
m_ptr = PyModule_Create(def);
+#else
+ m_ptr = Py_InitModule3(name, nullptr, doc);
+#endif
if (m_ptr == nullptr)
throw std::runtime_error("Internal error in module::module()");
inc_ref();
@@ -430,7 +473,11 @@
void (*init_holder)(PyObject *), const destructor &dealloc,
PyObject *parent, const char *doc) {
PyHeapTypeObject *type = (PyHeapTypeObject*) PyType_Type.tp_alloc(&PyType_Type, 0);
+#if PY_MAJOR_VERSION >= 3
PyObject *name = PyUnicode_FromString(name_);
+#else
+ PyObject *name = PyString_FromString(name_);
+#endif
if (type == nullptr || name == nullptr)
throw std::runtime_error("Internal error in custom_type::custom_type()");
Py_INCREF(name);
@@ -444,7 +491,10 @@
if (module_name.check())
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_basicsize = instance_size;
type->ht_type.tp_init = (initproc) init;
@@ -453,6 +503,9 @@
type->ht_type.tp_flags |=
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE;
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_sequence = &type->as_sequence;
type->ht_type.tp_as_mapping = &type->as_mapping;
@@ -482,7 +535,12 @@
/* Allocate a metaclass on demand (for static properties) */
handle metaclass() {
auto &ht_type = ((PyHeapTypeObject *) m_ptr)->ht_type;
+#if PY_MAJOR_VERSION >= 3
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) {
std::string name_ = std::string(ht_type.tp_name) + "_meta";
PyHeapTypeObject *type = (PyHeapTypeObject*) PyType_Type.tp_alloc(&PyType_Type, 0);
@@ -490,7 +548,10 @@
if (type == nullptr || name == nullptr)
throw std::runtime_error("Internal error in custom_type::metaclass()");
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_base = &PyType_Type;
type->ht_type.tp_flags |= Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE;
@@ -541,6 +602,9 @@
void *get_buffer_data) {
PyHeapTypeObject *type = (PyHeapTypeObject*) m_ptr;
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_releasebuffer = releasebuffer;
auto info = ((detail::type_info *) capsule(attr("__pybind__")));
@@ -606,17 +670,19 @@
template <typename Func, typename... Extra>
class_ &def(const char *name_, Func&& f, Extra&&... extra) {
- attr(name_) = cpp_function(std::forward<Func>(f), name(name_),
- sibling(attr(name_)), is_method(),
- std::forward<Extra>(extra)...);
+ cpp_function cf(std::forward<Func>(f), name(name_),
+ sibling(attr(name_)), is_method(this),
+ std::forward<Extra>(extra)...);
+ attr(cf.name()) = cf;
return *this;
}
template <typename Func, typename... Extra> class_ &
def_static(const char *name_, Func f, Extra&&... extra) {
- attr(name_) = cpp_function(std::forward<Func>(f), name(name_),
- sibling(attr(name_)),
- std::forward<Extra>(extra)...);
+ cpp_function cf(std::forward<Func>(f), name(name_),
+ sibling(attr(name_)),
+ std::forward<Extra>(extra)...);
+ attr(cf.name()) = cf;
return *this;
}
@@ -654,9 +720,9 @@
class_ &def_readwrite(const char *name, D C::*pm, Extra&&... extra) {
cpp_function fget([pm](const C &c) -> const D &{ return c.*pm; },
return_value_policy::reference_internal,
- is_method(), extra...),
+ is_method(this), extra...),
fset([pm](C &c, const D &value) { c.*pm = value; },
- is_method(), extra...);
+ is_method(this), extra...);
def_property(name, fget, fset);
return *this;
}
@@ -665,7 +731,7 @@
class_ &def_readonly(const char *name, const D C::*pm, Extra&& ...extra) {
cpp_function fget([pm](const C &c) -> const D &{ return c.*pm; },
return_value_policy::reference_internal,
- is_method(), std::forward<Extra>(extra)...);
+ is_method(this), std::forward<Extra>(extra)...);
def_property_readonly(name, fget);
return *this;
}
diff --git a/include/pybind/pytypes.h b/include/pybind/pytypes.h
index 5aff796..e9a60e9 100644
--- a/include/pybind/pytypes.h
+++ b/include/pybind/pytypes.h
@@ -213,10 +213,30 @@
public:
PYBIND_OBJECT_DEFAULT(str, object, PyUnicode_Check)
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 {
public:
@@ -252,7 +272,13 @@
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 {
- 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;
}
};
diff --git a/include/pybind/stl.h b/include/pybind/stl.h
index 4b935cf..bf1d898 100644
--- a/include/pybind/stl.h
+++ b/include/pybind/stl.h
@@ -100,9 +100,10 @@
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; }
-NAMESPACE_END(detail)
NAMESPACE_END(pybind)
#if defined(_MSC_VER)