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)
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)
......
......@@ -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
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
......
#!/usr/bin/env python3
#!/usr/bin/env python
from __future__ import print_function
import sys
sys.path.append('.')
......
#!/usr/bin/env python3
#!/usr/bin/env python
from __future__ import print_function
import sys
sys.path.append('.')
......
#!/usr/bin/env python3
#!/usr/bin/env python
from __future__ import print_function
import sys, pydoc
sys.path.append('.')
......
#!/usr/bin/env python3
#!/usr/bin/env python
from __future__ import print_function
import sys, pydoc
sys.path.append('.')
......
#!/usr/bin/env python3
#!/usr/bin/env python
from __future__ import print_function
import sys
sys.path.append('.')
......
#!/usr/bin/env python3
#!/usr/bin/env python
from __future__ import print_function
import sys
sys.path.append('.')
......
#!/usr/bin/env python3
#!/usr/bin/env python
from __future__ import print_function
import sys
sys.path.append('.')
......
#!/usr/bin/env python3
#!/usr/bin/env python
from __future__ import print_function
import sys
sys.path.append('.')
......
#!/usr/bin/env python3
#!/usr/bin/env python
from __future__ import print_function
import sys
sys.path.append('.')
......
#!/usr/bin/env python3
#!/usr/bin/env python
from __future__ import print_function
import sys
sys.path.append('.')
......
#!/usr/bin/env python3
#!/usr/bin/env python
from __future__ import print_function
import sys
sys.path.append('.')
......
......@@ -25,7 +25,7 @@ NAMESPACE_BEGIN(detail)
#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 @@ protected:
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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>> {
......
......@@ -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;
......
......@@ -47,7 +47,11 @@ public:
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)
......
......@@ -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(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)
......
......@@ -213,10 +213,30 @@ class str : public object {
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 @@ public:
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;
}
};
......
......@@ -100,9 +100,10 @@ public:
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)
......
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