Set C++ variable from Python script using SWIG - python

I'm having issues setting a variable in C++ using SWIG and Python. I have a class with a variable and a get and set function, which are all static.
What I'm trying to do is to set the static variable in the Python script, but as soon as it leaves the PyRun_SimpleFile function, the variable is set back to it's original value.
So how can I set variables in C++ using Python/SWIG?
minimal.h
class Minimal
{
public:
static int Minimal::var;
static int Minimal::GetVar() { return var; }
void Minimal::SetVar(int x){ var = x; }
};
minimal.i
%module minimal
%{
#define SWIG_FILE_WITH_INIT
#include "minimal.h"
%}
%include "minimal.h"
Python Script
import minimal
m1 = minimal.Minimal()
m1.SetVar(10)
Call to Python script
// Initialize Python
Py_Initialize();
// Perform Python actions here.
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('../Python')");
PyRun_SimpleString("sys.path.append('../Python/Scripts')");
fp = _Py_fopen(directory, "r");
PyRun_SimpleFile(fp, directory);
Py_Finalize();

Related

How to cast/convert a python function to std::function<double(double*)> in pybind11?

I am using pybind11 to implement binds for my c++ project.
So, my problem is basically how to define a python function in the interpreter
and call it from the C++ code.
The C++ interface passes data using a pointer (double*) and I don't know how to code the function in the interpreter and how to convert it for a std::function to perform the evaluation:
// C++
//--------
double cpp_call( const std::array<double,N> &value, const std::function<double(double*)> &func)
{
return func(value.data());
}
// python binding with pybind11
// module definition...
...
m.def("py_call", &cpp_call);
//python interpreter
//-------------------
?
Please, could someone give some tip to me ?
You're most likely missing a couple of requires headers to get this working, #include <pybind11/functional.h> (for the std::function support) and #include <pybind11/stl.h> (for the stl container support); neither header is included by default (to keep the core project smaller).
With those, your example almost works (it just needs a const added to the inner argument of the std::function, i.e. const std::function<double(const double *)> &func: the std::array is const and thus its .data() returns a const pointer).
Here's a full example showing this working:
#include <pybind11/pybind11.h>
#include <pybind11/functional.h>
#include <pybind11/stl.h>
double cpp_call(const std::array<double, 3> &values,
const std::function<double(double *)> &func) {
double ret = 0;
for (auto d : values) ret += func(&d);
return ret;
}
PYBIND11_MODULE(stack92, m) {
m.def("sum", &cpp_call);
}
Python:
>>> import stack92
>>> def f(v): return v**.5
...
>>> print("1+2+3 =", stack92.sum([1, 4, 9], f))
1+2+3 = 6.0

How to make interface for std::pair<> with no default constructor in swig & python?

I'm going to make python wrapper using swig.
I have some classes and types in c++ dll.
class Image
{
public:
Image(const Image&);
Image& operator= (const Image&);
~Image();
unsigned int width() const;
unsigned int height() const;
};
struct Property
{
std::string path;
std::string datetime;
};
typedef std::pair<Image, Property> MyImage;
class Manage
{
public:
Manage();
~Manage();
void addMyImage(MyImage img);
MyImage getMyImage(int index);
};
I made swig interface file following this:
%include "std_pair.i"
%template(MyImage) std::pair<Image, Property>;
class Image
{
public:
Image(const Image&);
~Image();
unsigned int width() const;
unsigned int height() const;
};
class Manage
{
public:
Manage();
~Manage();
void addMyImage(std::pair<Image, Property> img);
std::pair<Image, Property> getMyImage(int index);
};
I run command swig -c++ -python Test.swig.
I compile Test_wrapper.cxx in Visual Studio, It occurs error following this:
error C2512: 'Image' : no appropriate default constructor available
So I tried with swig -c++ -python -nodefaultctor Test.swig.
But it was same.
============UPDATE============
The problem is std::pair<Image, Property>. When pair create, it calls the constructor of arguments. Image has no default constructor. So erorr occurs.
How can I fix it?
Thanks.
I finally figured out a way to make this work. Firstly, since you've got pass-by-value semantics for addMyImage and getMyImage you need to use %feature("valuewrapper") to turn on pass-by-value wrapping transformation in the generated code otherwise you'll get default constructed pairs in the generated code.
Secondly you need to prevent SWIG from exposing the std::pair constructor that takes no arguments. (This I think is different to the %nodefaultctor directive because one such constructor is explicitly written and not simply assumed to exist). It took me a long time to realise the correct syntax for the easiest(?) way do do this which I believe is using advanced renaming.
So you need to add two lines before your %include <std_pair.i> directive:
%feature("valuewrapper") std::pair<Image,Property>;
%rename("$ignore",$isconstructor,fullname=1) "std::pair<(Image,Property)>";
%include "std_pair.i"
This does however disable all the constructors in std::pair<Image,Property>.

Using C from Python

I want to know the names of the NetworkInterfaces from python, but it seems it's not possible from python so I'm using this C code:
#include <Python.h>
#include <windows.h>
#include <iphlpapi.h>
#include <stdio.h>
#pragma comment(lib, "iphlpapi.lib")
PyObject* GetInterfaces (PyObject* self){
ULONG buflen = sizeof(IP_ADAPTER_INFO);
IP_ADAPTER_INFO *pAdapterInfo = (IP_ADAPTER_INFO *)malloc(buflen);
if (GetAdaptersInfo(pAdapterInfo, &buflen) == ERROR_BUFFER_OVERFLOW) {
free(pAdapterInfo);
pAdapterInfo = (IP_ADAPTER_INFO *)malloc(buflen);
}
if (GetAdaptersInfo(pAdapterInfo, &buflen) == NO_ERROR) {
for (IP_ADAPTER_INFO *pAdapter = pAdapterInfo; pAdapter; pAdapter = pAdapter->Next) {
printf("%s (%s)\n", pAdapter->IpAddressList.IpAddress.String, pAdapter->Description);
}
}
if (pAdapterInfo) free(pAdapterInfo);
return 0;
}
static char interfaces_docs[] =
"GetInterfaces( ): prints the interfaces name and IP\n";
static PyMethodDef interfaces_funcs[] = {
{"GetInterfaces", (PyCFunction)GetInterfaces,
METH_NOARGS, interfaces_docs},
{NULL}
};
void initinterfaces(void)
{
Py_InitModule3("interfaces", interfaces_funcs,
"Interfaces Module");
}
Is this good? And what are the steps to importing it into Python with ctypes? How can I do it? Also is there a way to return a list of tuples instead of printing it? Do I need to compile it? If I do how can I?
Is this good?
Almost. Never return 0/null as a PyObject* unless you're signaling an exception; instead incref Py_None and return it. And you may want to add actual error checking code as well.
And what are the steps to importing it into Python with ctypes? How can I do it?
What you've written doesn't need ctypes, since it's an actual Python module written in C. Use import interfaces after compiling the code to interfaces.pyd.
Also is there a way to return a list of tuples instead of printing it? Do I need to compile it? If I do how can I?
With the normal list and tuple functions; create the object and set each element in turn as required.

How do I invoke a method on a C++ class pointer with swig wrappers?

I'm using SWIG to wrap C++ code for use within a Python testing framework. My problem is that I'm getting a pointer to an instance of a class that I need to then invoke methods on. Eg, within my swig file example.i:
iExample* getMyClassInstance();
...
class iExample
{
public:
virtual void somePureVirtualMethod() = 0;
// ...
};
Now, in python, if I had the class, I could just call the method
myClassInstance.somePureVirtualMethod()
However, I don't actually have an instance of the class, of course. I have an opaque pointer generated from SWIG. How do I use it? Obviously in Python I can't do
myClassInstancePtr = example.getMyClassInstance()
myClassInstancePtr->somePureVirtualMethod()
I tried using cpointer.i or pointer.i in swig to generate pointer functions, but that's no good, because it's trying to create copies of the class. This can't even compile with an interface with pure virtual methods, and even if I wasn't using pure virtual methods, I don't want to create a copy of the class, I just want to invoke something on it!
SWIG can handle this just fine. Make sure you define the interface in SWIG and then it won't be opaque. Here's a working example:
%module x
%inline %{
// Define the interface.
struct iExample
{
virtual int somePureVirtualMethod() = 0;
};
iExample* getMyClassInstance();
%}
// Implementation, not exposed to Python
%{
struct Internal : public iExample
{
int somePureVirtualMethod() { return 5; }
};
iExample* getMyClassInstance() { return new Internal(); }
%}
Demo:
>>> import x
>>> i = x.getMyClassInstance()
>>> i.somePureVirtualMethod()
5
However, this implementation will leak an Internal Instance. You may want to implement a way to free it automatically. One way is to use %newobject and define a virtual destructor. Python will delete the object when there are no more references to it.
%module x
%newobject getMyClassInstance;
%inline %{
struct iExample
{
virtual ~iExample() {};
virtual int somePureVirtualMethod() = 0;
};
iExample* getMyClassInstance();
%}
// Implementation
%{
#include <iostream>
struct Internal : public iExample
{
int somePureVirtualMethod() { return 5; }
~Internal() { std::cout << "destroyed" << std::endl; }
};
iExample* getMyClassInstance() { return new Internal(); }
%}
Demo:
>>> import x
>>> i = x.getMyClassInstance()
>>> i.somePureVirtualMethod()
5
>>> i=2 # reassign i
destroyed # garbage-collected
The simplest answer I've found is to edit your example.i to add in some helper functions to do dereferencing. In your swig file example.i:
{%
...
// Helper function to dereference pointers within python
template <typename T>
T& dereference(T* ptr)
{
return *ptr;
}
...
%}
...
// Make every version of the templated functions we'll need
template <typename T> T& dereference(T* ptr);
%template(dereferencePtr_iExample) dereference<iExample>;
Now in python
myClassInstance = example.dereferencePtr_iExample(example.getMyClassInstance())
myClassInstance.somePureVirtualMethod()
I imagine this method should work generically for other languages like perl as well, and you don't have to screw around with SWIG typemaps.

boost::python : using callback

I have header (fingisdk.h) file like this:
#ifndef FINGISDK_H_
#define FINGISDK_H_
#include "fingienum.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef void (*fingi_event)(FINGI_EVENT_ID eventId, char* msg);
FINGI_EVENT_ID start_fingi_sdk(char* ini_file_location);
FINGI_EVENT_ID download_room_info(char** roominfo);
void register_fingi_sdk_status_event_listener(fingi_event pointer_to_listener_fnc);
#ifdef __cplusplus
}
#endif
#endif
And then i have written a python Wrapper for this one:
#include <fingisdk.h>
#include <fingienum.h>
#include <boost/python.hpp>
BOOST_PYTHON_MODULE(libpythonWrapper)
{
using namespace boost::python;
def("start_fingi_sdk", start_fingi_sdk);
}
And python file for calling it is like this:
import libpythonWrapper
print libpythonWrapper.start_fingi_sdk('file_location.ini')
So far this works fine. However, i can not find out how to expose double the double pointer
function :
FINGI_EVENT_ID download_room_info(char** roominfo);
And callback function :
void register_fingi_sdk_status_event_listener(fingi_event pointer_to_listener_fnc);
Can anyone point me to some documentation or help me solve it
Thankyou
EDIT 1:
After messing around a bit, i figured out how to do the pointer to pointer function . Python does not support pointer , so have to wrap the download_room_info(char** roominfo) to return simple string:
std::string download_room_info_python_wrapper() {
char * value;
FINGI_EVENT_ID result = download_room_info(&value);
return std::string(value);
}
And then:
def("download_room_info", download_room_info_python_wrapper);
Still looking for solution for callback function
So you want to bind this API to Python:
typedef void (*fingi_event)(FINGI_EVENT_ID eventId, char* msg);
void register_fingi_sdk_status_event_listener(fingi_event);
That's a register function which takes a function which takes an eventId and a string. OK, let's define one of our own (in extern "C" of course, as the API is):
void my_callback(FINGI_EVENT_ID eventId, char* msg)
{
// do something
}
Now we can write a wrapper for the register function:
void my_register()
{
register_fingi_sdk_status_event_listener(my_callback);
}
And bind it:
def("my_register", my_register);
That should all work. But it's useless, because we didn't actually do anything in the callback. So this leads to a sub-question, which is how can you possibly do anything in the callback? One idea I have is that you should make your own function registration mechanism which lets you register a Python callback function into something like a global PyObject which will be set to a Python function and invoked using Boost Python:
boost::python::object g_callback;
void my_callback(FINGI_EVENT_ID eventId, char* msg)
{
if (g_callback)
g_callback(eventId, msg);
}
Now it's just a matter of letting the user assign the global callback:
void set_callback(boost::python::object func)
{
g_callback = func;
register_fingi_sdk_status_event_listener(my_callback);
}
def("set_callback", set_callback);
Then in Python:
def callback(eventId, msg):
print eventId, msg
set_callback(callback)
That should be about it, I think. This whole thing would be a ton easier if your callback API supported a "void* userData" argument like many callback APIs do. We'd then use that to store a PyObject or something useful. But the API lacks that, so we're stuck with a global somewhere to remember which function to call.

Categories