Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions include/wrappy/detail/sys.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#pragma once
// Initializer/finalizer sample for MSVC and GCC/Clang.
// 2010-2016 Joe Lowe. Released into the public domain.
#include <stdio.h>
#include <stdlib.h>

#ifdef __cplusplus
#define INITIALIZER(f) \
static void f(void); \
struct f##_t_ { f##_t_(void) { f(); } }; static f##_t_ f##_; \
static void f(void)
#elif defined(_MSC_VER)
#pragma section(".CRT$XCU",read)
#define INITIALIZER2_(f,p) \
static void f(void); \
__declspec(allocate(".CRT$XCU")) void (*f##_)(void) = f; \
__pragma(comment(linker,"/include:" p #f "_")) \
static void f(void)
#ifdef _WIN64
#define INITIALIZER(f) INITIALIZER2_(f,"")
#else
#define INITIALIZER(f) INITIALIZER2_(f,"_")
#endif
#else
#define INITIALIZER(f) \
static void f(void) __attribute__((constructor)); \
static void f(void)
#endif
56 changes: 27 additions & 29 deletions wrappy.cpp → include/wrappy/detail/wrappy.ipp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Python header must be included first since they insist on
#pragma once
// 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 All @@ -22,8 +23,14 @@ using namespace wrappy;
PyObject *s_EmptyTuple;
PyObject *s_EmptyDict;

__attribute__((constructor))
void wrappyInitialize()

// __attribute__((destructor))
void wrappyFinalize()
{
Py_Finalize();
}

INITIALIZER(wrappyInitialize)
{
// Initialize python interpreter.
// The module search path is initialized as following:
Expand All @@ -40,7 +47,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 All @@ -49,13 +57,7 @@ void wrappyInitialize()

s_EmptyTuple = Py_BuildValue("()");
s_EmptyDict = Py_BuildValue("{}");
}


__attribute__((destructor))
void wrappyFinalize()
{
Py_Finalize();
atexit(wrappyFinalize);
}

PythonObject loadBuiltin(const std::string& name)
Expand Down Expand Up @@ -179,7 +181,7 @@ double PythonObject::floating() const

const char* PythonObject::str() const
{
return PyString_AsString(obj_);
return PyUnicode_AsUTF8(obj_);
}

PythonObject::operator bool() const
Expand All @@ -200,7 +202,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 +212,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 +237,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 +356,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 +446,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 +455,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 +469,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 +489,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
12 changes: 7 additions & 5 deletions include/wrappy/wrappy.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <vector>
#include <string>
#include <stdexcept>
#include <wrappy/detail/sys.hpp>

struct _object;
typedef _object PyObject;
Expand Down Expand Up @@ -71,14 +72,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 +103,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 Expand Up @@ -165,3 +166,4 @@ class ContextManager {
} // end namespace wrappy

#include <wrappy/detail/call.hpp>
#include <wrappy/detail/wrappy.ipp>