Commit 57082210 by Wenzel Jakob

support for ancient Python versions (2.7.x)

parent d557e1d3
...@@ -17,8 +17,8 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) ...@@ -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)
......
...@@ -19,10 +19,10 @@ become an excessively large and unnecessary dependency. ...@@ -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
......
#!/usr/bin/env python3 #!/usr/bin/env python
from __future__ import print_function
import sys import sys
sys.path.append('.') sys.path.append('.')
......
#!/usr/bin/env python3 #!/usr/bin/env python
from __future__ import print_function
import sys import sys
sys.path.append('.') sys.path.append('.')
......
#!/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('.')
......
#!/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('.')
......
#!/usr/bin/env python3 #!/usr/bin/env python
from __future__ import print_function
import sys import sys
sys.path.append('.') sys.path.append('.')
......
#!/usr/bin/env python3 #!/usr/bin/env python
from __future__ import print_function
import sys import sys
sys.path.append('.') sys.path.append('.')
......
#!/usr/bin/env python3 #!/usr/bin/env python
from __future__ import print_function
import sys import sys
sys.path.append('.') sys.path.append('.')
......
#!/usr/bin/env python3 #!/usr/bin/env python
from __future__ import print_function
import sys import sys
sys.path.append('.') sys.path.append('.')
......
#!/usr/bin/env python3 #!/usr/bin/env python
from __future__ import print_function
import sys import sys
sys.path.append('.') sys.path.append('.')
......
#!/usr/bin/env python3 #!/usr/bin/env python
from __future__ import print_function
import sys import sys
sys.path.append('.') sys.path.append('.')
......
#!/usr/bin/env python3 #!/usr/bin/env python
from __future__ import print_function
import sys import sys
sys.path.append('.') sys.path.append('.')
......
...@@ -25,7 +25,7 @@ NAMESPACE_BEGIN(detail) ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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>> {
......
...@@ -24,9 +24,6 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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;
......
...@@ -47,7 +47,11 @@ public: ...@@ -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)
......
...@@ -103,7 +103,11 @@ inline op_<op_##id, op_u, self_t, undefined_t> op(const self_t &) { ...@@ -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)
......
...@@ -213,10 +213,30 @@ class str : public object { ...@@ -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: ...@@ -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;
} }
}; };
......
...@@ -100,9 +100,10 @@ public: ...@@ -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)
......
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