Extract constant value from python by boost python - 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");

Related

Boost Python issue with converters - static linking

I have a question regarding the below code.
It's an example how to pass a custom class via shared_ptr to embedded python code and it works when boost is dynamically linked.
Unfortunately the same code with statically linked boost doesn't work with the following error message:
"No to_python (by-value) converter found for C++ type: class boost::shared_ptr".
I don't understand why a different linking can affect type recognition of a registered converter. What am I missing?
Can anybody help me out?
Thanks,
Dominik
Example from here.
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/python.hpp>
#include <string>
#include <iostream>
namespace bp = boost::python;
struct Foo{
Foo(){}
Foo(std::string const& s) : m_string(s){}
void doSomething() {
std::cout << "Foo:" << m_string << std::endl;
}
std::string m_string;
};
typedef boost::shared_ptr<Foo> foo_ptr;
BOOST_PYTHON_MODULE(hello)
{
bp::class_<Foo, foo_ptr>("Foo")
.def("doSomething", &Foo::doSomething)
;
};
int main(int argc, char **argv)
{
Py_Initialize();
try {
PyRun_SimpleString(
"a_foo = None\n"
"\n"
"def setup(a_foo_from_cxx):\n"
" print 'setup called with', a_foo_from_cxx\n"
" global a_foo\n"
" a_foo = a_foo_from_cxx\n"
"\n"
"def run():\n"
" a_foo.doSomething()\n"
"\n"
"print 'main module loaded'\n"
);
foo_ptr a_cxx_foo = boost::make_shared<Foo>("c++");
inithello();
bp::object main = bp::object(bp::handle<>(bp::borrowed(
PyImport_AddModule("__main__")
)));
// pass the reference to a_cxx_foo into python:
bp::object setup_func = main.attr("setup");
setup_func(a_cxx_foo);
// now run the python 'main' function
bp::object run_func = main.attr("run");
run_func();
}
catch (bp::error_already_set) {
PyErr_Print();
}
Py_Finalize();
return 0;
}
I far as I understand the documentation about Boost Python linkage, it seems that the conversion registry used for automatic conversion of Python object into C++ object is not available when statically linked. I'm facing the same issue and that's a pity it is actually the case. I would have imagined at least the required converter to be bundle but I'm afraid it is not the case for some reason.

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.

Calling a Python function from C++

I am trying to make a call to a python module function from my cpp file.
The call i have made is as follows:
#include <iostream>
#include "Python.h"
int
main(int argc, char** argv)
{
Py_Initialize();
PyObject *pName = PyString_FromString("tmpPyth");
PyObject *pModule = PyImport_Import(pName);
std::cout<< "Works fine till here";
PyObject *pDict = PyModule_GetDict(pModule);
if (pModule != NULL) {
PyObject *pFunc = PyObject_GetAttrString(pDict, "pyFunc");
if(pFunc != NULL){
PyObject_CallObject(pFunc, NULL);
}
}
else
std::cout << "Python Module not found";
return 0;
}
My python module is defined as follows:
import numpy
import scipy
import matplotlib
from scipy import stats
def blah():
baseline = [9.74219, 10.2226, 8.7469, 8.69791, 9.96442, 9.96472, 9.37913, 9.75004]
follow_up = [9.94227,9.46763,8.53081,9.43679,9.97695,10.4285,10.159,8.86134]
paired_sample = stats.ttest_rel(baseline , follow_up )
print "The t-statistic is %.3f and the p-value is %.3f." % paired_sample
The code in the cpp file runs fine till the 1st "std::cout" but then ends up giving me a "seg fault". Running the python code separately works fine and gives the desired output.
I cant figure out what is going wrong. Any help will be appreciated.
(Note the program is compiling correctly and running correctly till the 1st "cout")
So there are a couple of things that you were not doing right. See the comments inline. Assuming that both your CPP file and Python file lives at the following path: /home/shanil/project.
test.cpp:
#include <iostream>
#include "Python.h"
int
main(int argc, char** argv)
{
Py_Initialize();
// First set in path where to find your custom python module.
// You have to tell the path otherwise the next line will try to load
// your module from the path where Python's system modules/packages are
// found.
PyObject* sysPath = PySys_GetObject("path");
PyList_Append(sysPath, PyString_FromString("/home/shanil/project"));
// Load the module
PyObject *pName = PyString_FromString("my_mod");
PyObject *pModule = PyImport_Import(pName);
// Random use-less check
std::cout<< "Works fine till here\n";
if (pModule != NULL) {
std::cout << "Python module found\n";
// Load all module level attributes as a dictionary
PyObject *pDict = PyModule_GetDict(pModule);
// Remember that you are loading the module as a dictionary, the lookup you were
// doing on pDict would fail as you were trying to find something as an attribute
// which existed as a key in the dictionary
PyObject *pFunc = PyDict_GetItem(pDict, PyString_FromString("my_func"));
if(pFunc != NULL){
PyObject_CallObject(pFunc, NULL);
} else {
std::cout << "Couldn't find func\n";
}
}
else
std::cout << "Python Module not found\n";
return 0;
}
my_mod.py:
def my_func():
print 'got called'

Call C function inside a C extension in Python

I've tried to make a C extension to Python. My problem is that I have C function calls inside the C function I have made a C extension for. For example I am using C functions in pmd.h and usb1024LS.h inside these C functions. When I try running my script, I get errors like "undefined symbol: hid_init". Where hid_init is a function.
I have tried running the program in a c main program, and it works.
How do I call C functions from inside other C functions which have an extension?
Thanks!
My code:
test.py - test script:
import ctypes
import myTest_1024LS
ctypes_findInterface = ctypes.CDLL('/home/oysmith/NetBeansProjects/MCCDAQ/usb1024LS_with_py/myTest_1024LS.so').findInterface
ctypes_findInterface.restype = ctypes.c_void_p
ctypes_findInterface.argtypes = [ctypes.c_void_p]
ctypes_findInterface()
setup.py:
from distutils.core import setup, Extension
setup(name="myTest_1024LS", version="0.0", ext_modules = [Extension("myTest_1024LS", ["myTest_1024LS.c"])])
myTest_1024LS.c:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/types.h>
#include <asm/types.h>
#include <python2.7/Python.h>
#include "pmd.h"
#include "usb-1024LS.h"
#include "myTest_1024LS.h"
void findInterface(void){
int interface;
hid_return ret;
ret = hid_init();
if (ret != HID_RET_SUCCESS) {
fprintf(stderr, "hid_init failed with return code %d\n", ret);
exit(1);
}
if ((interface = PMD_Find_Interface(&hid, 0, USB1024LS_PID)) >= 0) {
printf("USB 1024LS Device is found! interface = %d\n", interface);
} else if ((interface = PMD_Find_Interface(&hid, 0, USB1024HLS_PID)) >= 0) {
printf("USB 1024HLS Device is found! interface = %d\n", interface);
} else {
fprintf(stderr, "USB 1024LS and USB 1024HLS not found.\n");
exit(1);
}
}
PyDoc_STRVAR(myTest_1024LS__doc__, "myTes_1024LS point evaluation kernel");
PyDoc_STRVAR(findInterface__doc__, "find device");
static PyObject *py_findInterface(PyObject *self, PyObject *args);
static PyMethodDef wrapper_methods[] = {
{"findInterface", py_findInterface, METH_VARARGS, findInterface__doc__},
{NULL, NULL}
};
PyMODINIT_FUNC initwrapper(void){
Py_InitModule3("wrapper", wrapper_methods, myTest_1024LS__doc__);
}
static PyObject *py_findInterface(PyObject *self, PyObject *args){
if(!PyArg_ParseTuple(args, "")){
return NULL;
}
findInterface();
return 0;
}
When building C extensions which themselves have to be linked against other shared libraries you'll have to tell which ones to link against in the setup.py. In this case at least the library which exports the hid_init() function. See the Python documentation for more details and examples: Building C and C++ Extensions with distutils. The second example contains arguments to link an extra library to the extension module.
The ctypes ”declarations” are wrong: void is not the same as a void pointer (void*). The findInterface() C function has neither arguments nor a return value, which is ”declared” as:
ctypes_findInterface.argtypes = []
ctypes_findInterface.restype = None

Resource handle of boost python

Using boost::python to call the python codes from c++.
int main()
{
namespace bp = boost::python;
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);
//get the ldap object from the main_namespace
boost::python::object ldap = boost::python::extract<boost::python::object>(main_namespace["l"]);
//...do something...
}
Now I want to get a brain new ldap object, could I do it like this?
bp::object main_module_2 = bp::import("__main__");
bp::import("ldap");
bp::import("ldif");
bp::object main_namespace_2 = main_module_2.attr("__dict__");
bp::exec("import ldap,ldif\n"
"l = ldap.initialize('ldaps://RIO-PC')\n",
main_namespace);
//get the ldap object from the main_namespace
boost::python::object ldap_2 = boost::python::extract<boost::python::object>(main_namespace_2["l"]);
If this is unsafe, what should I do?If this is safe, do I have another options?
environment :
boost version : 1_55_0
compiler : vc2008
os : win7 64bits
Now I want to get a brain new ldap object, could I do it like this?
Yes you can. The ldap module is a wrapper over the OpenLDAP C API, and as such if the documentation of the python module isn't clear enough in itself, you can always consult the original documentation [1,2]. There you will find that the LDAP structure returned from the open/init/initialize method calls is a per-connection descriptor.
To further increase your confidence, you can verify that on your particular platform the object is not reused. You can do so by checking that the returned python object identifiers (id(obj)) are different:
#include <boost/python.hpp>
#include <iostream>
int main() {
namespace bp = boost::python;
Py_Initialize();
bp::object main_module = bp::import("__main__");
bp::import("ldap");
bp::object main_namespace = main_module.attr("__dict__");
bp::exec(
"import ldap\n"
"a = ldap.initialize('ldaps://tls.example.com')\n"
"b = ldap.initialize('ldaps://tls.example.com')\n",
main_namespace);
boost::python::object a = boost::python::extract<
boost::python::object>(main_namespace["a"]);
boost::python::object b = boost::python::extract<
boost::python::object>(main_namespace["b"]);
std::cout << "id(a) = " << reinterpret_cast<long>(a.ptr()) << std::endl;
std::cout << "id(b) = " << reinterpret_cast<long>(b.ptr()) << std::endl;
}

Categories