Using C from Python - 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.

Related

pybind11 STL autoconverter breaks std::list pointers

I have a C++ library that manipulates (among other things) a list of wrappers that I have been working on converting to Python using pybind11. The rest of the library operates on a pointer to a list of pointers: std::list<Symbol*>*. The problem is that when attempting to autocast a Python list to this C++ list and then initializing a ParamMap, an object that holds the list on the C++ side, the pointers of the list get all messed up. Inspection in GDB reveals that the "next-object pointers" of all the objects are invalid, and this leads to segfaults when traversing the list.
There is no sign of the objects being deallocated on the C++ side, as neither the destructors for the list container ParamMap nor the list objects Symbol are called. I've deduced that the issue might be Python hyperactively deleting objects C++ is still using, but I've tried object terms like py::return_value_policy::reference and py::keep_alive, and they haven't fixed the problem. What is going wrong here? Unfortunately, changing the list type on the C++ side is not an option, but I would really appreciate some help in making this work on the Python side. Thank you!
Here is some minimal reproduction code:
Symbol.hpp
#include <string>
class Symbol {
private:
std::string val1;
int val2;
public:
Symbol(std::string con1, int con2) : val1(con1), val2(con2) {}
};
ParamMap.hpp
#include <list>
#include "Symbol.hpp"
class ParamMap {
private:
std::list<Symbol*>* lst;
int otherData;
public:
ParamMap(std::list<Symbol*>* symbolList, int dat) : lst(symbolList), otherData(dat) {}
std::list<Symbol*>* getSymbols() { return lst; }
int getOtherData() { return otherData; }
};
Query.cpp
#include <iostream>
#include "ParamMap.hpp"
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
namespace py = pybind11;
void getSymbolListSize(ParamMap* map) {
std::cout << "Entering query method" << std::endl;
auto sz = map->getSymbols()->size(); // SEGFAULT OCCURS WHEN GETTING SIZE
std::cout << "Got size successfully. Size = " << sz << std::endl;
}
PYBIND11_MODULE(list_test, handle) {
handle.def("getSymbolListSize", &getSymbolListSize);
py::class_<ParamMap>(handle, "ParamMap")
.def(py::init<std::list<Symbol*>*, int>(), py::keep_alive<1, 2>())
.def("getOtherData", &ParamMap::getOtherData)
.def("getSymbols", &ParamMap::getSymbols);
py::class_<Symbol>(handle, "Symbol")
.def(py::init<std::string, int>());
}
test.py
import list_test as p
# Creating a list of some random symbols
symbol_list = []
symbol1 = p.Symbol("Hello", 1)
symbol_list.append(symbol1)
symbol2 = p.Symbol("World", 2)
symbol_list.append(symbol2)
# Creating a parammap and passing it the symbol list
pm = p.ParamMap(symbol_list, 71)
print("Symbol list and ParamMap init'd successfully")
# Here, calling Query.cpp's only method
sz = p.getSymbolListSize(pm)
print(sz)
I don't know a lot about how pybind11 works its magic and therefore I can't help you understanding what is going on. However, I have the feeling that pybind attempts to build the list even though your code only uses a pointer to the list. If I were you I'd consider this a pybind bug and post it as an issue on their github page.
As per your code, doing something like this seems to work (although it's not very clean):
#include <list>
#include "Symbol.hpp"
class ParamMap {
private:
std::list<Symbol*>* lst;
int otherData;
public:
ParamMap(std::list<Symbol*> *symbolList, int dat) : lst(symbolList), otherData(dat) {
lst = new std::list<Symbol *>;
for(auto s : *symbolList) {
lst->push_back(s);
}
}
~ParamMap() {
delete lst;
}
std::list<Symbol*>* getSymbols() { return lst; }
int getOtherData() { return otherData; }
};
I don't know who's supposed to manage the lifetime of the pointed list, so you may want to remove the destructor in case someone else is supposed to deallocate the list.

swig macro $descriptor within helper function

Intro
My typical swig interface file is similar to the following:
%{ //COPY THIS BLOCK AS IS
#include <headers.h>
static CppClass* get_CppClass_from_swig_object(PyObject* obj)
{
void* self_obj = nullptr;
int ok = SWIG_Python_ConvertPtr(obj, &self_obj, SWIGTYPE_p_CppClass, 0);
if(!SWIG_IsOK(ok))
{
PyErr_SetString(PyExc_TypeError, "Object must be a CppClass");
return nullptr;
}
return reinterpret_cast<CppClass*>(self_obj);
}
static CppClass convert_to_CppClass(PyObject* py_obj)
{
CppClass* converted_ptr = get_CppClass_from_swig_object(py_obj);
if(converted_ptr==nullptr)
throw std::runtime_error("Python object is not a CppClass");
return CppClass(*converted_ptr);
}
%}
%typemap(in) std::vector<CppClass>& (std::vector<CppClass> temp) {
try{
temp = SequenceConverter::to_vector<CppClass>($input, convert_to_CppClass);
$1 = &temp;
}catch(std::exception& e){
PyErr_SetString(PyExc_RuntimeError, e.what());
SWIG_fail;
}
}
%typemap(typecheck, precedence=SWIG_TYPECHECK_CPPCLASS_VECTOR) std::vector<CppClass>& {
$1 = 0;
if(PyTuple_Check($input))
$1 = 1;
else if(PyList_Check($input))
$1 = 1;
}
class CppClass
{
public:
CppClass();
CppClass(const CppClass& other);
//other methods
};
but I would like to avoid explicitly using SWIGTYPE_p_CppClass within get_CppClass_from_swig_object.
As is, it is not possible to use the $descriptor(CppClass) swig macro as I would like to, because the %{ ... %} block is copied as -is rather than interpreted by swig, and so the $descriptor swig macro would not be interpreted. On the other hand, if i would remove the % and use a { ... } block, swig would try and wrap the whole get_CppClass_from_swig_object and convert_to_CppClass classes rather than simply defining them so they can be used in the typemap.
Question
How can I change my file structure and allow using $descriptor macro within the conversion helpers?
TL;DR
%{...%} blocks are neither preprocessed nor wrapped by swig
{...} blocks are both preprocessed and wrapped ( but small pieces can be prevented from swig preprocessing with a preceding % )
How can I make swig preprocess but not wrap a piece of code?
I don't think there's a way to make the contents of %{...%} be preprocessed, but not wrapped - for most of what the preprocessor does it relies on a typemap to actually be instantiated to populate the substitution information (although $descriptor could still work and I've wished for it in the past).
My usual solution is to pass the SWIG type info as an argument into functions like that, for example:
%{ //COPY THIS BLOCK AS IS
#include <headers.h>
static CppClass* get_CppClass_from_swig_object(PyObject* obj, swig_type_info *ty)
{
//... use ty instead of $descriptor here
Which means that when you use get_CppClass_from_swig_object in a typemap all you need to do is use $1_descriptor or $descriptor to get the correct value for the second argument.

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

Python ctypes and wrapping a c++ std:wstring

I am using msvc++ and Python 2.7. I have a dll that returns a std:wstring. I am trying to wrap it in such a way that it is exposed as a c style string for calls from Python via ctypes. I obviously do not understand something about how strings are handled between the two. I have simplified this into a simple example to understand the passing mechanism. Here is what I have:
C++
#include <iostream>
class WideStringClass{
public:
const wchar_t * testString;
};
extern "C" __declspec(dllexport) WideStringClass* WideStringTest()
{
std::wstring testString = L"testString";
WideStringClass* f = new WideStringClass();
f->testString = testString.c_str();
return f;
}
Python:
from ctypes import *
lib = cdll.LoadLibrary('./myTest.dll')
class WideStringTestResult(Structure):
_fields_ = [ ("testString", c_wchar_p)]
lib.WideStringTest.restype = POINTER(WideStringTestResult)
wst = lib.WideStringTest()
print wst.contents.testString
And, the output:
????????????????????᐀㻔
What am I missing?
Edit:
Changing the C++ to the following solves the problem. Of course, I think I now have a memory leak. But, that can be solved.
#include <iostream>
class WideStringClass{
public:
std::wstring testString;
void setTestString()
{
this->testString = L"testString";
}
};
class Wide_t_StringClass{
public:
const wchar_t * testString;
};
extern "C" __declspec(dllexport) Wide_t_StringClass* WideStringTest()
{
Wide_t_StringClass* wtsc = new Wide_t_StringClass();
WideStringClass* wsc = new WideStringClass();
wsc->setTestString();
wtsc->testString = wsc->testString.c_str();
return wtsc;
}
Thanks.
There is a big issue that is not related to Python:
f->testString = testString.c_str();
This is not correct, since testString (the std::wstring you declared) is a local variable, and as soon as that function returns, testString is gone, thus invalidates any attempt to use what c_str() returned.
So how do you fix this? I'm not a Python programmer, but the way character data is usually marshalled between two differing languages is to copy characters to a buffer that was either created on the receiver's side or the sender's side (better the former than the latter).

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