Skip to content

Commit

Permalink
port to py3
Browse files Browse the repository at this point in the history
  • Loading branch information
PhilipDeegan committed Jul 24, 2019
1 parent b67bee1 commit 91dfb13
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 25 deletions.
10 changes: 5 additions & 5 deletions include/wrappy/wrappy.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,14 @@ class PythonObject {
PyObject* obj_;
};

// Note that this is an input iterator, iterators cannot
// Note that this is an input iterator, iterators cannot
// be stored, rewound, or compared to anything but "end"
struct PythonIterator {
PythonIterator& operator++(); // pre-increment
PythonObject operator*(); // dereference
// *only* for comparison to "end", python iterators have
// *only* for comparison to "end", python iterators have
// no concept of position or comparability
bool operator!=(const PythonIterator&);
bool operator!=(const PythonIterator&);

private:
PythonIterator(bool, PythonObject);
Expand All @@ -102,12 +102,12 @@ void addModuleSearchPath(const std::string& path);

// There is one quirk of call() for the case of member methods:
//
// call("module.A.foo")
// call("module.A.foo")
//
// calls the unbound method "foo", so it is necessary to provide an instance
// of A as the first argument, while
//
// auto a = call("module.A"); call(a, "foo");
// auto a = call("module.A"); call(a, "foo");
//
// calls the method "foo" that is already bound to a, so providing an explicit
// self argument in that case is an error.
Expand Down
50 changes: 30 additions & 20 deletions wrappy.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Python header must be included first since they insist on
// Python header must be included first since they insist on
// unconditionally defining some system macros
// (http://bugs.python.org/issue1045893, still broken in python3.4)
#include <Python.h>
Expand Down Expand Up @@ -40,7 +40,8 @@ void wrappyInitialize()
Py_Initialize();

// Setting a dummy value since many libraries require sys.argv[0] to exist
char* dummy_args[] = {const_cast<char*>("wrappy"), nullptr};
wchar_t name[16] = L"wrappy";
wchar_t* dummy_args[] = {const_cast<wchar_t*>(name), nullptr};
PySys_SetArgvEx(1, dummy_args, 0);

wrappy::None = PythonObject(PythonObject::borrowed{}, Py_None);
Expand Down Expand Up @@ -179,7 +180,20 @@ double PythonObject::floating() const

const char* PythonObject::str() const
{
return PyString_AsString(obj_);
char * my_result = nullptr;
// return PyString_AsString(obj_);
if (PyUnicode_Check(obj_)) {

PyObject * temp_bytes = PyUnicode_AsEncodedString(obj_, "UTF-8", "strict"); // Owned reference
if (temp_bytes != NULL) {
my_result = PyBytes_AS_STRING(temp_bytes); // Borrowed pointer
my_result = strdup(my_result);
Py_DECREF(temp_bytes);
} else {
// TODO: Handle encoding error.
}
}
return my_result;
}

PythonObject::operator bool() const
Expand All @@ -200,7 +214,7 @@ PythonObject construct(long long ll)

PythonObject construct(int i)
{
return PythonObject(PythonObject::owning {}, PyInt_FromLong(i));
return PythonObject(PythonObject::owning {}, PyLong_FromLong(i));
}

PythonObject construct(double d)
Expand All @@ -210,7 +224,7 @@ PythonObject construct(double d)

PythonObject construct(const std::string& str)
{
return PythonObject(PythonObject::owning {}, PyString_FromString(str.c_str()));
return PythonObject(PythonObject::owning {}, PyUnicode_FromString(str.c_str()));
}

PythonObject construct(const std::vector<PythonObject>& v)
Expand All @@ -235,7 +249,7 @@ void addModuleSearchPath(const std::string& path)
auto syspath = PySys_GetObject(&pathString[0]); // Borrowed reference

PythonObject pypath(PythonObject::owning {},
PyString_FromString(path.c_str()));
PyUnicode_FromString(path.c_str()));

if (!pypath) {
throw WrappyError("Wrappy: Can't allocate memory for string.");
Expand Down Expand Up @@ -354,7 +368,7 @@ PythonObject callWithArgs(
PythonObject function = loadObject(from, name);

if (!function) {
throw WrappyError("Wrappy: "
throw WrappyError("Wrappy: "
"Lookup of function " + functionName + " failed.");
}

Expand Down Expand Up @@ -444,7 +458,7 @@ std::map<const char*, PythonObject> to_map(PyObject* pykwargs)
PyObject *key, *value;
Py_ssize_t pos = 0;
while (PyDict_Next(pykwargs, &pos, &key, &value)) {
const char* str = PyString_AsString(key);
const char* str = PyUnicode_AsUTF8(key);
PythonObject obj(PythonObject::borrowed{}, value);
kwargs.emplace(str, obj);
}
Expand All @@ -453,12 +467,12 @@ std::map<const char*, PythonObject> to_map(PyObject* pykwargs)
}

PyObject* trampolineWithData(PyObject* data, PyObject* pyargs, PyObject* pykwargs) {
if (!PyCObject_Check(data)) {
if (!PyCapsule_CheckExact(data)) {
throw WrappyError("Trampoline data corrupted");
}

LambdaWithData fun = reinterpret_cast<LambdaWithData>(PyCObject_AsVoidPtr(data));
void* userdata = PyCObject_GetDesc(data);
LambdaWithData fun = reinterpret_cast<LambdaWithData>(PyCapsule_GetPointer(data, "lambda"));
void* userdata = PyCapsule_GetContext(data);
auto args = to_vector(pyargs);
auto kwargs = to_map(pykwargs);

Expand All @@ -467,11 +481,11 @@ PyObject* trampolineWithData(PyObject* data, PyObject* pyargs, PyObject* pykwarg

PyObject* trampolineNoData(PyObject* data, PyObject* pyargs, PyObject* pykwargs)
{
if (!PyCObject_Check(data)) {
if (!PyCapsule_CheckExact(data)) {
throw WrappyError("Trampoline data corrupted");
}

Lambda fun = reinterpret_cast<Lambda>(PyCObject_AsVoidPtr(data));
Lambda fun = reinterpret_cast<Lambda>(PyCapsule_GetPointer(data, "lambda"));
auto args = to_vector(pyargs);
auto kwargs = to_map(pykwargs);

Expand All @@ -487,18 +501,14 @@ PyMethodDef trampolineWithDataMethod {"trampoline2", reinterpret_cast<PyCFunctio

PythonObject construct(Lambda lambda)
{
PyObject* pydata = PyCObject_FromVoidPtr(reinterpret_cast<void*>(lambda), nullptr);
PyObject * pydata = PyCapsule_New(reinterpret_cast<void*>(lambda), "lambda", nullptr);
return PythonObject(PythonObject::owning{}, PyCFunction_New(&trampolineNoDataMethod, pydata));
}

PythonObject construct(LambdaWithData lambda, void* userdata)
{
PyObject* pydata;
if (!userdata) {
pydata = PyCObject_FromVoidPtr(reinterpret_cast<void*>(lambda), nullptr);
} else { // python returns an error if FromVoidPtrAndDesc is called with desc being null
pydata = PyCObject_FromVoidPtrAndDesc(reinterpret_cast<void*>(lambda), userdata, nullptr);
}
PyObject * pydata = PyCapsule_New(reinterpret_cast<void*>(lambda), "lambda", nullptr);
if (userdata) PyCapsule_SetContext(pydata, userdata);
return PythonObject(PythonObject::owning{}, PyCFunction_New(&trampolineWithDataMethod, pydata));
}

Expand Down

0 comments on commit 91dfb13

Please sign in to comment.