I use SWIG and Numpy. I define a C function called inplace() to process data array fast, and I want to make some error checking (if two arrays have the same dimentions).
I use %rename and %inline in the .i file. As I understand, rename should map the function names', so every time someone uses inplace, safe_inplace is run and the errors are checked.
But it does not work :( . As far I notice, safe_inplace is not executed, python runs directly inplace without touching the safe version of the function.
# .i
%include "inplace.h"
%rename (inplace) safe_inplace;
%inline %{
void safe_inplace(int* datain, int in_dx, int in_dy, int in_dz,
int* dataout, int out_dx, int out_dy)
{
if ((in_dx != out_dx) || (in_dy != out_dy)) {
PyErr_Format(PyExc_ValueError, /*... messgage*/)
return;
}
inplace( /* .. pass the arguments to original function*/ );
}
header file:
# .h
void inplace(int* datain, int in_dx, int in_dy, int in_dz, int* dataout, int out_dx, int out_dy);
Python:
#.py
inplace.inplace(a,b)
The original example that I modify can be found here
Your original approach was close, but you probably want to get SWIG not to wrap the original version of the function at all.
I've put together a slightly simpler example illustrating how this could work. Given the header file:
void foo();
We want to wrap it such that a slightly modified version is called before invoking the real one.
The simplest way to do this would be to never actually show SWIG the header file at all for wrapping, only for compiling the wrapper, e.g.:
%module test
%{
#include "test.h"
#include <iostream>
%}
%rename (foo) foo_safe;
%inline %{
void foo_safe() {
std::cout << "Hello world" << std::endl;
foo(); // Calls the foo() from test.h, as you'd hope
}
%}
If you don't want to drop the %include (e.g. there's other things you care about in that header file too) you can do something like:
%module test
%{
#include "test.h"
#include <iostream>
%}
%rename (unsafe_foo) foo;
%include "test.h"
%rename (foo) foo_safe;
%inline %{
void foo_safe() {
std::cout << "Hello world" << std::endl;
foo();
}
%}
To expose the real implementation of foo as unsafe_foo.
Or you could use %ignore if there's no reason for Python users to be able to call unsafe_ignore ever:
%module test
%{
#include "test.h"
#include <iostream>
%}
%rename (foo) foo_safe;
%inline %{
void foo_safe() {
std::cout << "Hello world" << std::endl;
foo();
}
%}
%ignore foo;
%include "test.h"
Finally it looks like your goal is actually just to run some code prior to the call of the real C function. If that's the case there's a few ways you can do that too, for example you can add python code before the real function call is made with pythonprepend:
%feature("pythonprepend") foo() %{
print "hello world"
# check args and raise possibly
%}
Or lastly you could use the %exception functionality too, something like (untested):
%exception inplace {
// Check args and possibly throw
$action
}
$action will be substituted with the real call automatically.
Related
I am trying to create a Python Bluetooth wrapper to wrap C++ classes. This is my SWIG interface file:
%module blsdk
%include "pyabc.i"
%include "std_vector.i"
%include "cstring.i"
%include "cpointer.i"
%include "typemaps.i"
%include serialport.i
%include exploresearch.i
Here is my serialport.i
%module serialport
%{
#include <string>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <termios.h>
#include <sys/poll.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <assert.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
#include <bluetooth/sdp.h>
#include <bluetooth/sdp_lib.h>
#include <bluetooth/rfcomm.h>
#include "BTSerialPortBinding.h"
%}
%include "BTSerialPortBinding.h"
My BTSerialPortBinding.h has these functions:
static BTSerialPortBinding *Create(std::string address, int channelID);
int Connect();
void Close();
int Read(char *buffer, int length);
void Write(const char *write_buffer, int length);
bool IsDataAvailable();
How can I wrap the int Read(char* buffer, int length) function? I want to have the char* buffer as output and the length as input. I have tried to define the read function as int Read(char* OUTPUT, int length) but this gives an error: TypeError: a bytes-like object is required, not 'str' in my program as I need a byte object in Python. Any help would be very much appreciated.
This is not a complete answer but it might serve to get you started hacking around. As always with SWIG the key is looking at the generated code and monkeying around with it. Writing off the top of my head so again, just a starting point.
One thing you can do is a bit hacky but could work if you have some theoretical limit to how much data you read. A handy way is to 'swallow' the input and return value with a pair like this:
%typemap(in,numinputs=0) char *buffer
{
$1 = malloc(some_arbitrary_large_amount);
// or 'cheat' by looking at swig output and using the value you just happen
// to know is the length (like arg1 or something)
}
%typemap(argout) char *buffer
{
PyObject *tmp = $result;
int len = 0;
int res = SWIG_AsVal_long(tmp, &len);
if(!SWIG_IsOK(res)) {
free($1);
SWIG_fail;
}
$result = SWIG_From_CharPtrAndSize( $1, len );
PyDecRef(tmp); //probably?
free($1);
}
This would change the interface on the python side to just take the length argument and return a python string which may not be what you want. Note that you can return whatever you like so instead of SWIG_From_CharPtr you could create some other python object like a bytearray.
Another approach is to play with multi-arg typemaps. More hazy on the details here but you'd be doing something like:
%typemap(in) (char *buffer, int length)
{
/*
$input is a python object of your choice - bytearray?
Use the various Python/Swig APIs to decode the input object.
Set $1 and $2 to the data pointer and length decoded from
your input object and they will be passed to the C function.
*/
}
Now you have a Read() function on the python side that takes one argument which is up to you to create and set the size of. Could be anything as long as you can figure out how to get access to the internal array and size. Numpy is a pretty good candidate but if you're using Numpy, they already have a really nice set of typemaps for SWIG. Then you'd just do:
%include "numpy.i"
%apply( char *IN_ARRAY1, int DIM1 )
and give it a numpy array.
I am new to learning swig. I am interested in calling C++ from Python on an Ubuntu machine.
I just started looking at the intro tutorial here http://www.swig.org/tutorial.html
Consider the interface file on that page example.i copied as is below.
/* example.i */
%module example
%{
/* Put header files here or function declarations like below */
extern double My_variable;
extern int fact(int n);
extern int my_mod(int x, int y);
extern char *get_time();
%}
extern double My_variable;
extern int fact(int n);
extern int my_mod(int x, int y);
extern char *get_time();
Why is are the contents between the %{ %} repeated in the second half of the file? As given in the manual, http://www.swig.org/Doc3.0/SWIGDocumentation.html#Introduction_nn5
The %{ %} block provides a location for inserting additional code,
such as C header files or additional C declarations, into the
generated C wrapper code.
But it doesn't address the point of the repetition in the example. What am I missing?
The code between %{ and %} is inserted verbatim in the generated SWIG wrapper, and is used to give the wrapper code access to the headers or declarations listed.
The code outside those markers instructs SWIG to make a wrapper for each of the declarations (or entire header files) listed.
If you left out extern int fact(int n); in the first portion, the wrapper, when compiled and linked to the source or library containing the function, wouldn't be able to access the function since the extern declaration would be missing. If left out of the second portion, a wrapper wouldn't be generated to access it from the scripting language.
There is a shortcut:
%inline %{
...
%}
That instructs SWIG to both insert and wrap the declarations.
I have a simple test.h file with my own array class (which uses the standard vector class):
#include <vector>
#include <string>
using namespace std;
class Array1D{
private:
vector<double> data_;
int xsize_;
public:
Array1D(): xsize_(0) {};
// creates vector of size nx and sets each element to t
Array1D(const int& nx, const double& t): xsize_(nx) {
data_.resize(xsize_, t);
}
double& operator()(int i) {return data_[i];}
const double& operator[](int i) const {return data_[i];}
};
I want to be able to use the [] operator in python using swig. My current SWIG interface file looks like
%module test
%{
#define SWIG_FILE_WITH_INIT
#include "test.h"
%}
%include "std_vector.i"
namespace std{
%template(DoubleVector) vector<double>;
}
%include "test.h"
When I make the module, everything runs fine, but when I instantiate an object of Array1D, a = test.Array1D(10,2), which creates a length 10 vector with 2 in each element, and type a[1] I get
TypeError: 'Array1D' object does not support indexing.
How should my SWIG interface file look in order to extend the operator method so I can output a[1] properly within python? I would also like to be able to do something like a[1] = 3.0;
I figured it out. This is what I needed to add to my interface file:
%extend Array1D{
const double& __getitem__(int i) {
return (*self)[i];
}
}
I have a C header file containing structure definitions with typedef, and an array of char definition with typedef too:
/* File: test.h */
typedef struct
{
char *key;
void *value;
int size;
} cti_pair;
typedef char FOO[CONST];
The SWIG interface file contains the following lines:
/* File: test.i */
%module test
%{
#define SWIG_FILE_WITH_INIT
#include "/home/users/jdoe/workspace/project/src/lib-cti/test.h"
...
%}
#ifndef CTI_TYPES_H_
#define CTI_TYPES_H_
#include "cti_const.h"
typedef char FOO[CONST];
typedef struct
{
char *key;
void *value;
int size;
} cti_pair;
The problem is that I can access the cti_pair struct, but can't use FOO (it's not defined) in my python script.
Ok, just figure out what the problem was.
Actually, I used %extend in another part of the interface file. But this keyword can only be used on structures, not on basic typedef (and SWIG does not display any error message if we use %extend the wrong way).
As a matter of fact, FOO was defined. The problem was not related to this at all. Thanks!
I'm trying to get SWIG to recognize a simple preprocessor macro that "defines" a new function based on another definition and more complicated function. So, in the C header file I have:
#define FOO 1
#define my_macro_fun(args) my_fun(args,FOO)
SWIG sees and successfully wraps my_fun, but I want it to wrap my_macro_fun instead.
SWIG tries to spot macros that are constants and wrap them, but it won't be able to do anything smart with a macro like that. Fortunately there's an easy work around. Imagine you have the following header file:
#define FOO 1
#define my_macro_fun(args) my_fun(args,FOO)
void my_fun(int a, int b);
You can wrap it like:
%module test
%{
#include "test.h"
%}
%include "test.h"
which skips the my_macro_fun function. To get SWIG to wrap that though all you need to do is:
%module test
%{
#include "test.h"
%}
// Lie! Tell SWIG that it should be wrapped like any other function.
void my_macro_fun(int);
// This is entirely optional: it will cause my_fun to be wrapped as well
%include "test.h"
This little lie is perfectly fine in SWIG - it'll generate Wrapper code that assumes my_macro_fun(int) is callable, exactly like you would if you were using the macro. When compiling the wrapper the compiler will end up using the macro there and nobody is any the wiser.
Note that the order is important - the function that's really a macro needs to come before the %include in the interface file otherwise SWIG will try to expand the macro during the parsing of your declaration which makes for a syntax error. You can skip the %include entirely, or use a %ignore as well if you want to include it for other parts but suppress the original my_fun in the generated interface.
With some SWIG languages (e.g. Python) you can also use the typemap default:
%module test
%{
#include "test.h"
%}
%typemap(default) int b {
$1 = FOO;
}
%include "test.h"
To supply a value for an argument if none is given for it.