diff --git a/include/wrappy/wrappy.h b/include/wrappy/wrappy.h index 5436994..48a6ea8 100644 --- a/include/wrappy/wrappy.h +++ b/include/wrappy/wrappy.h @@ -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); @@ -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. diff --git a/wrappy.cpp b/wrappy.cpp index ab1e81a..d1e1840 100644 --- a/wrappy.cpp +++ b/wrappy.cpp @@ -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 @@ -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("wrappy"), nullptr}; + wchar_t name[16] = L"wrappy"; + wchar_t* dummy_args[] = {const_cast(name), nullptr}; PySys_SetArgvEx(1, dummy_args, 0); wrappy::None = PythonObject(PythonObject::borrowed{}, Py_None); @@ -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 @@ -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) @@ -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& v) @@ -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."); @@ -354,7 +368,7 @@ PythonObject callWithArgs( PythonObject function = loadObject(from, name); if (!function) { - throw WrappyError("Wrappy: " + throw WrappyError("Wrappy: " "Lookup of function " + functionName + " failed."); } @@ -444,7 +458,7 @@ std::map 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); } @@ -453,12 +467,12 @@ std::map 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(PyCObject_AsVoidPtr(data)); - void* userdata = PyCObject_GetDesc(data); + LambdaWithData fun = reinterpret_cast(PyCapsule_GetPointer(data, "lambda")); + void* userdata = PyCapsule_GetContext(data); auto args = to_vector(pyargs); auto kwargs = to_map(pykwargs); @@ -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(PyCObject_AsVoidPtr(data)); + Lambda fun = reinterpret_cast(PyCapsule_GetPointer(data, "lambda")); auto args = to_vector(pyargs); auto kwargs = to_map(pykwargs); @@ -487,18 +501,14 @@ PyMethodDef trampolineWithDataMethod {"trampoline2", reinterpret_cast(lambda), nullptr); + PyObject * pydata = PyCapsule_New(reinterpret_cast(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(lambda), nullptr); - } else { // python returns an error if FromVoidPtrAndDesc is called with desc being null - pydata = PyCObject_FromVoidPtrAndDesc(reinterpret_cast(lambda), userdata, nullptr); - } + PyObject * pydata = PyCapsule_New(reinterpret_cast(lambda), "lambda", nullptr); + if (userdata) PyCapsule_SetContext(pydata, userdata); return PythonObject(PythonObject::owning{}, PyCFunction_New(&trampolineWithDataMethod, pydata)); }