pybind11: inherit/import one module into another - python

I have 2 pybind11 modules, Foo and Bar
I would like to import all symbols from Bar into Foo
eg, in Foo:
from Bar import *
My first attempt was to create 2 modules (using PYBIND11_MODULE), and call pybind11::module::import("bar") inside the module definition of foo:
#include <pybind11/pybind11.h>
namespace py = pybind11;
struct Bar
{
void bar()
{
py::print("in bar");
}
};
struct Foo
{
void foo()
{
py::print("in foo");
}
};
PYBIND11_MODULE(bar, m)
{
py::class_<Bar>(m, "Bar")
.def(py::init<>())
.def("bar", &Bar::bar);
}
PYBIND11_MODULE(foo, m)
{
py::module::import("bar"); // attempt to import Bar into Foo
py::class_<Foo>(m, "Foo")
.def(py::init<>())
.def("foo", &Foo::foo);
}
However, when importing the foo module in python, I get an error:
ModuleNotFoundError: No module named 'bar'
The only reason I want to do this is to be able to separate the definitions of various different types into separate files, and then "collect" them together into a single module.
My 2nd attempt was to create helper functions which take the module instance as a parameter, and then instantiates the relevant pybind11::class_ with the provided module instance
Eg:
in foo.h:
#pragma once
#include <pybind11/pybind11.h>
namespace py = pybind11;
struct Foo
{
void foo()
{
py::print("in foo");
}
};
void PyFoo(pybind11::module_& m)
{
py::class_<Foo>(m, "Foo")
.def(py::init<>())
.def("foo", &Foo::foo);
};
in bar.h:
#pragma once
#include <pybind11/pybind11.h>
namespace py = pybind11;
struct Bar
{
void bar()
{
py::print("in bar");
}
};
void PyBar(pybind11::module_& m)
{
py::class_<Bar>(m, "Bar")
.def(py::init<>())
.def("bar", &Bar::bar);
};
in module.cpp:
#include "foo.h"
#include "bar.h"
#include <pybind11/pybind11.h>
namespace py = pybind11;
PYBIND11_MODULE(foo, m)
{
PyBar(m);
PyFoo(m);
}
This actually works!
However, having to create a helper function for every single type I want to register with pybind11 seems a little boiler-platey.
Is there a better way to "collect" multiple pybind11 type definitions into a single module?

Related

How to make it so that user-made exceptions in C++ inherit from BaseException class of Python using SWIG

I have a library in C++ where I have my own exception class called "Exception" and I use SWIG to create a wrapper for Python. The idea is that the exception is catched and its methods can be used like in this example:
example.py:
try:
functionThatThrowsError()
except myLibrary.Exception as exc:
print (exc.code(), exc.msg())
The wrapper for the exception is created without problem, the thing is that Python requires that user-made exceptions inherit from the Python builtin BaseException class and inspecting myLibrary.py generated it shows that the class is not inheriting from BaseException but from object. If I manually change that line to inherit from BaseException instead of object the example.py works perfectly.
My question is how to tell SWIG that my Exception class should inherit from the BaseException class from Python.
Here are the other files to give more context:
exception.h:
#ifndef EXCEPTION
#define EXCEPTION
#include <string.h>
#include<exception>
using namespace std;
class Exception : public exception {
public:
Exception(int c, const char* m);
const char* msg();
const int code();
virtual const char* what() const throw();
~Exception() {};
int _code; //!< Error code.
char _msg[256]; //! Error message.
};
#endif
exception.cpp:
#include "../include/Exception.h"
Exception::Exception(int c, const char* m)
{
_code = c;
strncpy(_msg, m, 256);
}
const char* Exception::msg()
{
return _msg;
}
const int Exception::code()
{
return _code;
}
const char* Exception::what() const throw()
{
return _msg;
}
myLibrary.i:
%module myLibrary
%{
#define SWIG_FILE_WITH_INIT
#include "../include/Exception.h"
%}
%include "stl.i"
%exception {
try {
$action
} catch (Exception &e) {
SWIG_Python_Raise(SWIG_NewPointerObj(
(new Exception(e.code(), e.msg())),
SWIGTYPE_p_Exception,SWIG_POINTER_OWN),
"Exception", SWIGTYPE_p_Exception);
SWIG_fail;
} catch (...) {
SWIG_exception(SWIG_RuntimeError, "unknown exception");
}
}
%include "../include/Exception.h"
%inline %{
// The -builtin SWIG option results in SWIGPYTHON_BUILTIN being defined
#ifdef SWIGPYTHON_BUILTIN
bool is_python_builtin() { return true; }
#else
bool is_python_builtin() { return false; }
#endif
%}

Passing a C++ class instance into a C++ class on boost.python C++

I'm actually trying to use a C++ class like an attribute of an other C++ class in a Boost python library. I want to bind this two class in python like this :
import ClassParameter
t = ClassParameter.Slave("hi")
a = ClassParameter.Master()
a.setSlave(t)
Then i'd like to use some method from my Master class that use an instance of my Slave class : a.setSlave(t)
Problem is, when I bind the Slave, the Master got only a copy of the instance. And I don't know how I can do the link between both.
This is my boost code :
#include <boost/python.hpp>
#include "Master.h"
#include "Slave.h"
BOOST_PYTHON_MODULE(ClassParameter)
{
using namespace boost::python;
class_<Slave>("Slave")
.def(init<>())
.def(init<std::string>())
.def("getMessage", &Slave::getMessage)
.def("setMessage", &Slave::setMessage);
class_<Master>("Master")
.def(init<>())
.def(init<Slave>())
.def("showMessage",&Master::showMessage)
.def("setSlave",&Master::setSlave)
.def("getSlave",&Master::getSlave);
}
This is my class Slave :
#ifndef _SLAVE_H_
#define _SLAVE_H_
#include <iostream>
class Slave
{
public:
Slave(std::string message);
Slave();
Slave(const Slave& s1 );
std::string getMessage(void) ;
void setMessage(std::string message);
private:
std::string m_message;
};
#endif //_SLAVE_H_
Slave::Slave(){
m_message = "no message";
}
Slave::Slave(std::string message){
m_message = message;
}
Slave::Slave(const Slave& s1 ){
m_message = s1.m_message;
}
std::string Slave::getMessage(void) {
return m_message;
}
void Slave::setMessage(std::string message){
m_message = message;
}
This is my Master Class:
#ifndef _MASTER_H_
#define _MASTER_H_
#include "Slave.h"
#include <iostream>
class Master
{
public:
Master();
Master(Slave s) : m_slave(&s) {}
void showMessage();
void setSlave(Slave s);
Slave getSlave();
private:
Slave *m_slave;
};
#endif //_MASTER_H_
#include "Master.h"
Master::Master(){
m_slave =0;
}
void Master::showMessage(){
if (m_slave!=0) std::cout<< ( m_slave->getMessage() )<<std::endl;
}
void Master::setSlave(Slave s){
m_slave = &s;
}
Slave Master::getSlave(){
return *m_slave;
}
The error message when i'm using showMessage from Master is :
Traceback (most recent call last):
File "test.py", line 13, in <module>
a.showMessage()
RuntimeError: basic_string::_M_construct null not valid
I think it's because the setSlave got a temp copy, but i don't know an other way to solve this problem.

how do i get a structure in c++ from python?

My C++ program:
#include <iostream>
using namespace std;
struct FirstStructure
{
public:
int first_int;
int second_int;
};
struct SecondStructure
{
public:
int third_int;
FirstStructure ft;
};
int test_structure(SecondStructure ss)
{
int sum = ss.ft.first_int + ss.ft.second_int + ss.third_int;
return sum;
}
extern "C"
{
int test(SecondStructure ss)
{
return test_structure(ss);
}
}
And I compile the cpp file use this command "g++ -fPIC -shared -o array.so array.cpp".
Then I call the file array.so use python,my python program as these:
#coding=utf-8
import ctypes
from ctypes import *
class FirstStructure(Structure):
_fields_ = [
("first_int", c_int),
("second_int", c_int)
]
class SecondStructure(Structure):
_fields_ = [
("third_int", c_int),
("ft", FirstStructure)
]
if __name__ == '__main__':
fs = FirstStructure(1, 2)
ss = SecondStructure(3, fs)
print ss.ft.first_int
lib = ctypes.CDLL("./array.so")
print lib.test(ss)
When I run the python program,the console show an error, the error is "segmentation fault".I read the documentation from the url "https://docs.python.org/2/library/ctypes.html",how to fix the bug.
You have to declare a function's argument and return types in python, in order to be able to call it properly.
So, insert the following before calling the test function:
lib.test.argtypes = [SecondStructure]
lib.test.restype = ctypes.c_int
Things should work then, as far as I can see...
As long as the amount of C-to-python interfaces remains "small" (whatever that is), I think ctypes is just fine.
ok,I got it,modified code as these:
#include <iostream>
using namespace std;
extern "C"
{
struct FirstStructure
{
public:
int first_int;
int second_int;
};
struct SecondStructure
{
public:
int third_int;
FirstStructure ft;
};
int test_structure(SecondStructure *ss)
{
int sum = ss->ft.first_int + ss->ft.second_int + ss->third_int;
return sum;
}
int test(SecondStructure *ss)
{
return test_structure(ss);
}
}
and then,I fixed the bug.
Well if you are intending to design communication medium between C++ and python then I would suggest go for combination zmq and google protocol buffers.
where proto buf would serve for serialization/deserialization and zmq for communication medium.
You might want to have a look at Boost.python
https://wiki.python.org/moin/boost.python/SimpleExample
It will allow you to compile python modules from C++ and define how the python is allowed to access the c++ code in an easy to understand fashion

Extract constant value from python by boost python

codes of python(which work)
import ldap,ldif
l = ldap.initialize('ldaps://RIO-PC:636')
l.set_option(ldap.OPT_TIMEOUT);
I want to extract the constant value of ldap.OPT_TIMEOUT, but how to?
#include <iostream>
#include <boost/python.hpp>
int main()
{
namespace bp = boost::python;
try{
Py_Initialize();
bp::object main_module = bp::import("__main__");
bp::import("ldap");
bp::import("ldif");
bp::object main_namespace = main_module.attr("__dict__");
bp::exec("import ldap,ldif\n"
"l = ldap.initialize('ldaps://RIO-PC')\n",
main_namespace);
boost::python::object ldap = boost::python::extract<boost::python::object>(main_namespace["l"]);
ldap.attr("OPT_TIMEOUT"); //this line will throw exception
}catch(boost::python::error_already_set const &){
PyErr_Print();
PyErr_Clear();
}
}
the error message is
AttributeError: SimpleLDAPObject has no attribute 'OPT_TIMEOUT'
environment
compiler : vc2008
boost version : 1.55_0
os : win7 64bits(x64)
Your C++ code is trying to extract l.OPT_TIMEOUT, not ldap.OPT_TIMEOUT. Try
bp::object ldap_module = bp::import("ldap");
ldap_module.attr("OPT_TIMEOUT");

Swig - wrapping C struct

I am trying to write Python wrap for C code which uses struct.
modules.c:
struct foo
{
int a;
};
struct foo bar;
modulues.i
%module nepal
%{
struct foo
{
int a;
}
%}
extern struct foo bar;
But during compiling I am given error:
In function ‘Swig_var_bar_set’:
error: ‘bar’ undeclared (first use in this function)
Could you be so kind to help me how to correctly define export struct variable ?
Try this:
%module nepal
%{
struct foo
{
int a;
};
extern struct foo bar;
%}
struct foo
{
int a;
};
extern struct foo bar;
The code in %{ %} is inserted in the wrapper, and the code below it is parsed to create the wrapper. It's easier to put this all in a header file so it is not so repetitive:
modules.h
struct foo
{
int a;
};
extern struct foo bar;
modules.c
#include "modules.h"
struct foo bar;
modules.i
%module nepal
%{
#include "modules.h"
%}
%include "modules.h"

Categories