How to use ctypes and function returning TF2*

I am trying to use my ROOT code compiles as .so in a python code. I have a function in a class returning pointer to TF2*:

class lePSF
{
	public:
		lePSF();
		void SetXY(double x, double y);
		void SetRPhi(double r, double phi);
		void SetDrawPSF();
		void SetFitPSF();
		TF2 *GetPSFFunc();
	private:
		TF2 * mpsf;
};

TF2* lePSF::GetPSFFunc()
{
	cerr << mpsf << endl;
	mpsf->Print();
	return mpsf;
}

extern "C"
{
    lePSF* lePSF_new(){ return new lePSF(); }
    TF2* lePSF_GetPSFFunc(lePSF* lepsf){ return (TF2*)lepsf->GetPSFFunc();}
}

compiles fine. However, I have problems using this code from python:

class lePSF(object):
    def __init__(self):
        self.obj = lib.lePSF_new()

    def GetPSFFunc(self):
        tfunc = lib.lePSF_GetPSFFunc(self.obj)
	return tfunc

lePSF.GetPSFFunc() returns int ofcourse. So I need to set restype to pointer to TF2. So I try before the class declaration:

lib.lePSF_GetPSFFunc.restype = POINTER(TF2)

Unfortunately, this does not work:

Traceback (most recent call last):
  File "./pyPSF", line 10, in <module>
    lib.lePSF_GetPSFFunc.restype = POINTER(TF2)
  File "/usr/lib/python2.5/ctypes/__init__.py", line 254, in POINTER
    {'_type_': cls})
TypeError: _type_ must have storage info

What can I do?

Hi,

there’s a whole bundle of things that I do not understand …

Let’s start with the basics (your example is missing implementations of most of the member functions, so I can’t be sure I’m testing the same). You say: “lePSF.GetPSFFunc() returns int ofcourse.”, but first that function is not a static function, so it can not be called as such, and second, it returns a TF2*, so that’s what it returns, not int? If you meant the python equivalent (I really would not recommend masking classes with the same name like this), then still the function returns a TF2*, not int?

(As for ctypes, those are C-bindings, so it can’t do anything with a C++ type such as TF2.)

Cheers,
Wim

I was not clear. My attempt was to use ctypes. So I make functions calling class methods inside an extern “C” {}. Python GetPSFFunc() calls such C version:

def GetPSFFunc(self):
        tfunc = lib.lePSF_GetPSFFunc(self.obj)

and because it is linked to ctype .so function (lePSF_GetPSFFunc), it returns int when called in python by default. Now I need it to return TF2* in python, as it does in the definition in C file…

Hi,

okay, got it.

Then yes, that’s not going to work from ctypes per se, since it can not handle C++ classes (the offsets would be wrong if they are non-zero), and ctypes does not understand PyROOT-bound classes either (which are constructed as ordinary python classes).

What you can do, however, is bind the int that you received from ctypes into a PyROOT bound object, since TF2 has a dictionary associated with it. This can be done like so:TPython.ObjectProxy_FromVoidPtr( ctypes.c_voidp( returned_int ), 'TF2' ) although I would not recommend it, since it will then be carried as a TF2*, rather than any final derived type, if applicable. Also, it can not check offsets at that point (it basically is a reinterpret_cast), so you have to make sure the pointer value is correct.

Cheers,
Wim

Thanks. Anyway, I guess I’ll use the ACLIC and LoadLibrary ROOT method. In my case it seems the best choice…