CPP Middleware in a python enviroment
I Want to realize this structure.
App (python) <-> Middleware (cpp) <-> Driver (python)
A App (python) will access some middleware classes in CPP. And then use a driver (python).
App.py
import pybind_11_example as middleware_cpp
n = 40
print('C++:')
print('Answer:', middleware_cpp.testFunctionA_cpp(n))
Middleware.h
#include <pybind11/pybind11.h>
class middleware
{
public:
unsigned int testFunctionA(const unsigned int n);
namespace py = pybind11;
PYBIND11_MODULE(pybind_11_example, mod) {
mod.def("testFunctionA_cpp", &testFunctionA, "Middleware class.");
}
Middleware.cpp
#include "Middleware.h"
#include "stdio.h"
#include <pybind11/pybind11.h>
#include <pybind11/embed.h> // python interpreter
#include <pybind11/stl.h> // type conversion
unsigned int middleware::testFunctionA(const unsigned int n)
{
printf("Now Sent back to python driver interface\n");
//py::scoped_interpreter guard{}; // start interpreter, dies when out of scope
py::module driver= py::module::import("Driver");
py::object result = driver.attr("setValue")("setting value from cpp to python driver");
return 42;
}
Driver.py
class Driver:
def __init__(self):
print ("Init Driver Class")
self.name = "This is the Driver Class"
def printMyClass(self):
print(self.name)
def setValue(self, value):
print(value)
I have read the docs but did this example not working. So i want to place it here as a example template if other want also try this approach.
Question 1:
How do I call the python Driver class function "setValue" from cpp?
The current implementation from Middleware.cpp calling the function setValue leads to this error:
AttributeError: module 'Driver' has no attribute 'setValue'
Question 2:
Calling the interpreter twice should not be needed, because it is assumed, the the middleware is accessed from the running app process, which is already in python.
py::scoped_interpreter guard{}; // start interpreter, dies when out of scope
Best regards Holger
I've written part of a class in C++ and I want to be able to use it in conjunction with a Python GUI, so I'm using Boost.Python to try and make it easy. The issue I'm running into is that in following their guide (http://www.boost.org/doc/libs/1_55_0/libs/python/doc/tutorial/doc/html/python/exposing.html), I keep getting the following exception whenever I run bjam:
PacketWarrior/pcap_ext.cc:21:5: error: too few template arguments for class template 'class_'
Obviously it's complaining at me for omitting what they claim are optional arguments to the 'class_' template function, but I can't figure out why. I'm assuming it's a compiler issue but I don't know how to fix it. I'm running OS X 10.9 and using darwin for the default toolset, but GCC throws the same error. My Boost version is 1_55_0 if that helps at all.
Class header file (header guards omitted):
#include <queue>
#include "pcap.h"
#include "Packet.h"
class PacketEngine {
public:
PacketEngine();
~PacketEngine();
const char** getAvailableDevices(char *error_buf);
bool selectDevice(const char* dev);
Packet getNextPacket();
private:
char *selected_device;
char **devices;
int num_devices;
std::queue<Packet> packet_queue;
};
The cc file containing the references to Boost.Python and my class:
#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
#include "PacketEngine.h"
BOOST_PYTHON_MODULE(pcap_ext) {
using namespace boost::python;
class_<PacketEngine>("PacketEngine")
.def("getAvailableDevices", &PacketEngine::getAvailableDevices);
}
And my bjam file (irrelevant parts and comments omitted):
use-project boost : ../../../Downloads/boost_1_55_0 ;
project
: requirements <library>/boost/python//boost_python
<implicit-dependency>/boost//headers
: usage-requirements <implicit-dependency>/boost//headers
;
python-extension pcap_ext : PacketWarrior/pcap_ext.cc ;
install convenient_copy
: pcap_ext
: <install-dependencies>on <install-type>SHARED_LIB <install-type>PYTHON_EXTENSION
<location>.
;
local rule run-test ( test-name : sources + )
{
import testing ;
testing.make-test run-pyd : $(sources) : : $(test-name) ;
}
run-test pcap : pcap_ext pcap.py ;
Any ideas as to how to circumvent this exception are greatly appreciated! I looked into the obvious route of just adding the optional parameters but I don't think they're relevant to my project. The class_ definition can be found here:
http://www.boost.org/doc/libs/1_37_0/libs/python/doc/v2/class.html
In short, include either:
boost/python.hpp: The Boost.Python convenient header file.
boost/python/class.hpp: The header that defines boost::python::class_.
The current included header files are declaring class_ with no default template arguments from def_visitor.hpp.
Also, trying to directly expose PacketEngine::getAvailableDevices() will likely present a problem:
It accepts a char* argument, but strings are immutable in Python.
There are no types that automatically convert to/from a const char** in Boost.Python.
It may be reasonable for a Python user to expect PacketEngine.getAvailableDevices() to return an iterable type containing Python strs, or throw an exception on error. This can be accomplished in a non-intrusive manner by writing a helper or auxiliary function that delegates to original function, but is exposed to Python as PacketEngine.getAvailableDevices().
Here is a complete example based on the original code:
#include <exception> // std::runtime_error
#include <boost/python.hpp>
namespace {
const char* devices_str[] = {
"device A",
"device B",
"device C",
NULL
};
} // namespace
class PacketEngine
{
public:
PacketEngine() : devices(devices_str) {}
const char** getAvailableDevices(char *error_buf)
{
// Mockup example to force an error on second call.
static bool do_error = false;
if (do_error)
{
strcpy(error_buf, "engine not responding");
}
do_error = true;
return devices;
}
private:
const char **devices;
};
/// #brief Auxiliary function for PacketEngine::getAvailableDevices that
/// provides a more Pythonic API. The original function accepts a
/// char* and returns a const char**. Both of these types are
/// difficult to use within Boost.Python, as strings are immutable
/// in Python, and Boost.Python is focused to providing
/// interoperability to C++, so the const char** type has no direct
/// support.
boost::python::list PacketEngine_getAvailableDevices(PacketEngine& self)
{
// Get device list and error from PacketEngine.
char error_buffer[256] = { 0 };
const char** devices = self.getAvailableDevices(error_buffer);
// On error, throw an exception. Boost.Python will catch it and
// convert it to a Python's exceptions.RuntimeError.
if (error_buffer[0])
{
throw std::runtime_error(error_buffer);
}
// Convert the c-string array to a list of Python strings.
namespace python = boost::python;
python::list device_list;
for (unsigned int i = 0; devices[i]; ++i)
{
const char* device = devices[i];
device_list.append(python::str(device, strlen(device)));
}
return device_list;
}
BOOST_PYTHON_MODULE(example)
{
namespace python = boost::python;
python::class_<PacketEngine>("PacketEngine")
.def("getAvailableDevices", &PacketEngine_getAvailableDevices);
}
Interactive usage:
>>> import example
>>> engine = example.PacketEngine()
>>> for device in engine.getAvailableDevices():
... print device
...
device A
device B
device C
>>> devices = engine.getAvailableDevices()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
RuntimeError: engine not responding
for example I have a function in python that I want to convert to c++ (or call from c++ but I don't want to depend on python interpretor)
simple python function
//test.py
def my_sum(x,y):
print "Hello World!"
return x*x+y
I run shedskin and have
//test.cpp
#include "builtin.hpp"
#include "test.hpp"
namespace __test__ {
str *__name__;
void __init() {
__name__ = new str("__main__");
}
} // module namespace
int main(int, char **) {
__shedskin__::__init();
__shedskin__::__start(__test__::__init);
}
//test.hpp
#ifndef __TEST_HPP
#define __TEST_HPP
using namespace __shedskin__;
namespace __test__ {
extern str *__name__;
} // module namespace
#endif
ugly code and there is no my function my_sum and code depends on "builtin.hpp". is it possible to convert only function?
or
I want to call function from my c++ code something like
int sum= py.my_sum(3,5);
how can I do this?
or
maybe I can do DLL or Lib from python code that I can use in c++ code?
notice the warning that shedskin gives for this program:
*WARNING* test.py:1: function my_sum not called!
it is also mentioned in the documentation that for compilation to work, a function should be called (directly or indirectly), as it's not possible to do type inference otherwise.. how to determine the types of the arguments of my_sum, if there's not even a single call to it..? :-)
adding this, for example:
if __name__ == '__main__':
my_sum(1,1)
makes my_sum appear in the generated C++ code, which can potentially be called from another C++ program.
I'm embedding Python into a C/C++ application that will have a defined API.
The application needs to instantiate classes defined in a script, which are structured roughly like this:
class userscript1:
def __init__(self):
##do something here...
def method1(self):
## method that can be called by the C/C++ app...etc
I've managed in the past (for the proof-of-concept) to get this done using the following type of code:
PyObject* pName = PyString_FromString("userscript.py");
PyObject* pModule = PyImport_Import(pName);
PyObject* pDict = PyModule_GetDict(pModule);
PyObject* pClass = PyDict_GetItemString(pDict, "userscript");
PyObject* scriptHandle = PyObject_CallObject(pClass, NULL);
Now that I'm in more of a production environment, this is failing at the PyImport_Import line - I think this might be because I'm trying to prepend a directory to the script name, e.g.
PyObject* pName = PyString_FromString("E:\\scriptlocation\\userscript.py");
Now, to give you an idea of what I've tried, I tried modifying the system path before all of these calls to make it search for this module. Basically tried modifying sys.path programmatically:
PyObject* sysPath = PySys_GetObject("path");
PyObject* path = PyString_FromString(scriptDirectoryName);
int result = PyList_Insert(sysPath, 0, path);
These lines run ok, but have no effect on making my code work. Obviously, my real code has a boatload of error checking that I have excluded so don't worry about that!
So my question: how do I direct the embedded interpreter to my scripts appropriately so that I can instantiate the classes?
you need to specify userscript and not userscript.py also use PyImport_ImportModule it directly takes a char *
userscript.py means module py in package userscript
this code works for me:
#include <stdio.h>
#include <stdlib.h>
#include <Python.h>
int main(void)
{
const char *scriptDirectoryName = "/tmp";
Py_Initialize();
PyObject *sysPath = PySys_GetObject("path");
PyObject *path = PyString_FromString(scriptDirectoryName);
int result = PyList_Insert(sysPath, 0, path);
PyObject *pModule = PyImport_ImportModule("userscript");
if (PyErr_Occurred())
PyErr_Print();
printf("%p\n", pModule);
Py_Finalize();
return 0;
}
I have a class interface written in C++. I have a few classes that implement this interface also written in C++. These are called in the context of a larger C++ program, which essentially implements "main". I want to be able to write implementations of this interface in Python, and allow them to be used in the context of the larger C++ program, as if they had been just written in C++.
There's been a lot written about interfacing python and C++ but I cannot quite figure out how to do what I want. The closest I can find is here: http://www.cs.brown.edu/~jwicks/boost/libs/python/doc/tutorial/doc/html/python/exposing.html#python.class_virtual_functions, but this isn't quite right.
To be more concrete, suppose I have an existing C++ interface defined something like:
// myif.h
class myif {
public:
virtual float myfunc(float a);
};
What I want to be able to do is something like:
// mycl.py
... some magic python stuff ...
class MyCl(myif):
def myfunc(a):
return a*2
Then, back in my C++ code, I want to be able to say something like:
// mymain.cc
void main(...) {
... some magic c++ stuff ...
myif c = MyCl(); // get the python class
cout << c.myfunc(5) << endl; // should print 10
}
I hope this is sufficiently clear ;)
There's two parts to this answer. First you need to expose your interface in Python in a way which allows Python implementations to override parts of it at will. Then you need to show your C++ program (in main how to call Python.
Exposing the existing interface to Python:
The first part is pretty easy to do with SWIG. I modified your example scenario slightly to fix a few issues and added an extra function for testing:
// myif.h
class myif {
public:
virtual float myfunc(float a) = 0;
};
inline void runCode(myif *inst) {
std::cout << inst->myfunc(5) << std::endl;
}
For now I'll look at the problem without embedding Python in your application, i.e. you start excetion in Python, not in int main() in C++. It's fairly straightforward to add that later though.
First up is getting cross-language polymorphism working:
%module(directors="1") module
// We need to include myif.h in the SWIG generated C++ file
%{
#include <iostream>
#include "myif.h"
%}
// Enable cross-language polymorphism in the SWIG wrapper.
// It's pretty slow so not enable by default
%feature("director") myif;
// Tell swig to wrap everything in myif.h
%include "myif.h"
To do that we've enabled SWIG's director feature globally and specifically for our interface. The rest of it is pretty standard SWIG though.
I wrote a test Python implementation:
import module
class MyCl(module.myif):
def __init__(self):
module.myif.__init__(self)
def myfunc(self,a):
return a*2.0
cl = MyCl()
print cl.myfunc(100.0)
module.runCode(cl)
With that I was then able to compile and run this:
swig -python -c++ -Wall myif.i
g++ -Wall -Wextra -shared -o _module.so myif_wrap.cxx -I/usr/include/python2.7 -lpython2.7
python mycl.py
200.0
10
Exactly what you'd hope to see from that test.
Embedding the Python in the application:
Next up we need to implement a real version of your mymain.cc. I've put together a sketch of what it might look like:
#include <iostream>
#include "myif.h"
#include <Python.h>
int main()
{
Py_Initialize();
const double input = 5.0;
PyObject *main = PyImport_AddModule("__main__");
PyObject *dict = PyModule_GetDict(main);
PySys_SetPath(".");
PyObject *module = PyImport_Import(PyString_FromString("mycl"));
PyModule_AddObject(main, "mycl", module);
PyObject *instance = PyRun_String("mycl.MyCl()", Py_eval_input, dict, dict);
PyObject *result = PyObject_CallMethod(instance, "myfunc", (char *)"(O)" ,PyFloat_FromDouble(input));
PyObject *error = PyErr_Occurred();
if (error) {
std::cerr << "Error occured in PyRun_String" << std::endl;
PyErr_Print();
}
double ret = PyFloat_AsDouble(result);
std::cout << ret << std::endl;
Py_Finalize();
return 0;
}
It's basically just standard embedding Python in another application. It works and gives exactly what you'd hope to see also:
g++ -Wall -Wextra -I/usr/include/python2.7 main.cc -o main -lpython2.7
./main
200.0
10
10
The final piece of the puzzle is being able to convert the PyObject* that you get from creating the instance in Python into a myif *. SWIG again makes this reasonably straightforward.
First we need to ask SWIG to expose its runtime in a headerfile for us. We do this with an extra call to SWIG:
swig -Wall -c++ -python -external-runtime runtime.h
Next we need to re-compile our SWIG module, explicitly giving the table of types SWIG knows about a name so we can look it up from within our main.cc. We recompile the .so using:
g++ -DSWIG_TYPE_TABLE=myif -Wall -Wextra -shared -o _module.so myif_wrap.cxx -I/usr/include/python2.7 -lpython2.7
Then we add a helper function for converting the PyObject* to myif* in our main.cc:
#include "runtime.h"
// runtime.h was generated by SWIG for us with the second call we made
myif *python2interface(PyObject *obj) {
void *argp1 = 0;
swig_type_info * pTypeInfo = SWIG_TypeQuery("myif *");
const int res = SWIG_ConvertPtr(obj, &argp1,pTypeInfo, 0);
if (!SWIG_IsOK(res)) {
abort();
}
return reinterpret_cast<myif*>(argp1);
}
Now this is in place we can use it from within main():
int main()
{
Py_Initialize();
const double input = 5.5;
PySys_SetPath(".");
PyObject *module = PyImport_ImportModule("mycl");
PyObject *cls = PyObject_GetAttrString(module, "MyCl");
PyObject *instance = PyObject_CallFunctionObjArgs(cls, NULL);
myif *inst = python2interface(instance);
std::cout << inst->myfunc(input) << std::endl;
Py_XDECREF(instance);
Py_XDECREF(cls);
Py_Finalize();
return 0;
}
Finally we have to compile main.cc with -DSWIG_TYPE_TABLE=myif and this gives:
./main
11
Minimal example; note that it is complicated by the fact that Base is not pure virtual. There we go:
baz.cpp:
#include<string>
#include<boost/python.hpp>
using std::string;
namespace py=boost::python;
struct Base{
virtual string foo() const { return "Base.foo"; }
// fooBase is non-virtual, calling it from anywhere (c++ or python)
// will go through c++ dispatch
string fooBase() const { return foo(); }
};
struct BaseWrapper: Base, py::wrapper<Base>{
string foo() const{
// if Base were abstract (non-instantiable in python), then
// there would be only this->get_override("foo")() here
//
// if called on a class which overrides foo in python
if(this->get_override("foo")) return this->get_override("foo")();
// no override in python; happens if Base(Wrapper) is instantiated directly
else return Base::foo();
}
};
BOOST_PYTHON_MODULE(baz){
py::class_<BaseWrapper,boost::noncopyable>("Base")
.def("foo",&Base::foo)
.def("fooBase",&Base::fooBase)
;
}
bar.py
import sys
sys.path.append('.')
import baz
class PyDerived(baz.Base):
def foo(self): return 'PyDerived.foo'
base=baz.Base()
der=PyDerived()
print base.foo(), base.fooBase()
print der.foo(), der.fooBase()
Makefile
default:
g++ -shared -fPIC -o baz.so baz.cpp -lboost_python `pkg-config python --cflags`
And the result is:
Base.foo Base.foo
PyDerived.foo PyDerived.foo
where you can see how fooBase() (the non-virtual c++ function) calls virtual foo(), which resolves to the override regardless whether in c++ or python. You could derive a class from Base in c++ and it would work just the same.
EDIT (extracting c++ object):
PyObject* obj; // given
py::object pyObj(obj); // wrap as boost::python object (cheap)
py::extract<Base> ex(pyObj);
if(ex.check()){ // types are compatible
Base& b=ex(); // get the wrapped object
// ...
} else {
// error
}
// shorter, thrwos when conversion not possible
Base &b=py::extract<Base>(py::object(obj))();
Construct py::object from PyObject* and use py::extract to query whether the python object matches what you are trying to extract: PyObject* obj; py::extract<Base> extractor(py::object(obj)); if(!extractor.check()) /* error */; Base& b=extractor();
Quoting http://wiki.python.org/moin/boost.python/Inheritance
"Boost.Python also allows us to represent C++ inheritance relationships so that wrapped derived classes may be passed where values, pointers, or references to a base class are expected as arguments."
There are examples of virtual functions so that solves the first part (the one with class MyCl(myif))
For specific examples doing this, http://wiki.python.org/moin/boost.python/OverridableVirtualFunctions
For the line myif c = MyCl(); you need to expose your python (module) to C++. There are examples here http://wiki.python.org/moin/boost.python/EmbeddingPython
Based upon the (very helpful) answer by Eudoxos I've taken his code and extended it such that there is now an embedded interpreter, with a built-in module.
This answer is the Boost.Python equivalent of my SWIG based answer.
The headerfile myif.h:
class myif {
public:
virtual float myfunc(float a) const { return 0; }
virtual ~myif() {}
};
Is basically as in the question, but with a default implementation of myfunc and a virtual destructor.
For the Python implementation, MyCl.py I have basically the same as the question:
import myif
class MyCl(myif.myif):
def myfunc(self,a):
return a*2.0
This then leaves mymain.cc, most of which is based upon the answer from Eudoxos:
#include <boost/python.hpp>
#include <iostream>
#include "myif.h"
using namespace boost::python;
// This is basically Eudoxos's answer:
struct MyIfWrapper: myif, wrapper<myif>{
float myfunc(float a) const {
if(this->get_override("myfunc"))
return this->get_override("myfunc")(a);
else
return myif::myfunc(a);
}
};
BOOST_PYTHON_MODULE(myif){
class_<MyIfWrapper,boost::noncopyable>("myif")
.def("myfunc",&myif::myfunc)
;
}
// End answer by Eudoxos
int main( int argc, char ** argv ) {
try {
// Tell python that "myif" is a built-in module
PyImport_AppendInittab("myif", initmyif);
// Set up embedded Python interpreter:
Py_Initialize();
object main_module = import("__main__");
object main_namespace = main_module.attr("__dict__");
PySys_SetPath(".");
main_namespace["mycl"] = import("mycl");
// Create the Python object with an eval()
object obj = eval("mycl.MyCl()", main_namespace);
// Find the base C++ type for the Python object (from Eudoxos)
const myif &b=extract<myif>(obj)();
std::cout << b.myfunc(5) << std::endl;
} catch( error_already_set ) {
PyErr_Print();
}
}
The key part that I've added here, above and beyond the "how do I embed Python using Boost.Python?" and "how do I extend Python using Boost.python?" (which was answered by Eudoxos) is the answer to the question "How do I do both at once in the same program?". The solution to this lies with the PyImport_AppendInittab call, which takes the initialisation function that would normally be called when the module is loaded and registers it as a built-in module. Thus when mycl.py says import myif it ends up importing the built-in Boost.Python module.
Take a look at Boost Python, that is the most versatile and powerful tool to bridge between C++ and Python.
http://www.boost.org/doc/libs/1_48_0/libs/python/doc/
There's no real way to interface C++ code directly with Python.
SWIG does handle this, but it builds its own wrapper.
One alternative I prefer over SWIG is ctypes, but to use this you need to create a C wrapper.
For the example:
// myif.h
class myif {
public:
virtual float myfunc(float a);
};
Build a C wrapper like so:
extern "C" __declspec(dllexport) float myif_myfunc(myif* m, float a) {
return m->myfunc(a);
}
Since you are building using C++, the extern "C" allows for C linkage so you can call it easily from your dll, and __declspec(dllexport) allows the function to be called from the dll.
In Python:
from ctypes import *
from os.path import dirname
dlldir = dirname(__file__) # this strips it to the directory only
dlldir.replace( '\\', '\\\\' ) # Replaces \ with \\ in dlldir
lib = cdll.LoadLibrary(dlldir+'\\myif.dll') # Loads from the full path to your module.
# Just an alias for the void pointer for your class
c_myif = c_void_p
# This tells Python how to interpret the return type and arguments
lib.myif_myfunc.argtypes = [ c_myif, c_float ]
lib.myif_myfunc.restype = c_float
class MyCl(myif):
def __init__:
# Assume you wrapped a constructor for myif in C
self.obj = lib.myif_newmyif(None)
def myfunc(a):
return lib.myif_myfunc(self.obj, a)
While SWIG does all this for you, there's little room for you to modify things as you please without getting frustrated at all the changes you have to redo when you regenerate the SWIG wrapper.
One issue with ctypes is that it doesn't handle STL structures, since it's made for C. SWIG does handle this for you, but you may be able to wrap it yourself in the C. It's up to you.
Here's the Python doc for ctypes:
http://docs.python.org/library/ctypes.html
Also, the built dll should be in the same folder as your Python interface (why wouldn't it be?).
I am curious though, why would you want to call Python from inside C++ instead of calling the C++ implementation directly?