[PyKDE] question about sip wrapping of PyObject

Tony Willis Tony.Willis at nrc-cnrc.gc.ca
Wed Nov 3 03:14:50 GMT 2004


Hi

I am trying to extend Paul Kunz' HippoDraw package so that it can work
efficiently inside a larger python script that makes extensive use of
PyQt and thus of the sip environment. At present in order to store
data internally inside the sip-wrapped version of HippoDraw I have to
go from numarray object -> python list -> HippoDraw NTuple. This
has a real impact on performance. Basically I want to avoid any data
conversion whatsoever but use the numarray objects themselves.

my environment - RH 9 linux, sip 4.0.1, python 2.3.4, numarray 0.9,
gcc 3.2.2.

On the C++ side of things I have managed to create a class which
will, I hope, do what I want. Basically its just a std::vector of
PyArrayObject pointers.

In Python I want to be able to say e.g.:

self._radius_ntuple = SipArrayTuple();
self._radius_ntuple.addColumn("demo",x_pos)

where x_pos is a 1-dimensional python 'numarray' object.

Here are  extractions from the SipArrayTuple.h and SipArrayTuple.cc
code that I hope will implement this stuff on the C++ side of things.
The full versions of this code compile OK.

/////////// SipArrayTuple.h //////////////

#ifndef SipArrayTuple_H
#define SipArrayTuple_H

#include <Python.h>
#include <numarray/libnumarray.h>
#include "datasrcs/DataSource.h"

class MDL_HIPPOPLOT_API SipArrayTuple : public DataSource
{
 private:
  std::vector < PyArrayObject* > m_data;

 public:
  SipArrayTuple ();

  /** Adds a column to the end of the SipArrayTuple.  If the size of the
      input array is the same as the size of the existing columns adds
      input array to then end of the SipArrayTuple . Gives the column the
      label @a label.  Returns the index of the newly created column.
      If the size of the input array differs from the size of existing
      columns or if the label already exists, then throws a
      DataSourceException object.
  */
  int addColumn ( const std::string & label,
		  PyObject * array );
};

#endif // SipArrayTuple_H
/////////////// end SipArrayTuple.h ////////////////////

/////////// SipArrayTuple.cc ////////////////

#include "SipArrayTuple.h"

#include <algorithm>
#include <numeric>

using std::string;
using std::vector;

SipArrayTuple::SipArrayTuple ()
  : DataSource ()
{
}

int SipArrayTuple:: addColumn ( const std::string & label,
	    PyObject * array )
{
  m_data.push_back ((PyArrayObject *) array );
  addLabel ( label );
  return m_data.size() - 1;
}
/////////////// end SipArrayTuple.cc ////////////////////


However I'm having trouble with the 'sip' wrapper code. The larger
sihippo.sip that includes SipArrayTuple.sip is:

/////////////// sihippo.sip ////////////////////
%Module sihippo

%Import qt/qtmod.sip
%Import qtcanvasmod.sip
// lots of other files
%Include vector.sip
%Include SipArrayTuple.sip
/////////////// end sihippo.sip //////////////

When I run this through sip (4.0.1) this is what I get:

[tonywlp 4:12pm] [sip]> make
creating built sources
sip -e -g -c . -I /usr/local/share/sip -I /usr/local/share/sip/qtcanvas -I ../numarray -I ../sip  \
-t Qt_3_2_0 -t WS_X11 ../sip/sihippo.sip
sip: PyObject is undefined
make: *** [sipsihippocmodule.h] Error 1

Here is the extraction from SipArrayTuple.sip that wraps the addColumn
call:

/////////////// SipArrayTuple.sip ////////////////////

%PostInitialisationCode
    import_libnumarray();
%End

class SipArrayTuple : DataSource
{

%TypeHeaderCode
#include "numarray/SipArrayTuple.h"
#include <string>
%End

public:

  int addColumn ( const std::string &, PyObject *)
    throw ( DataSourceException );

};
/////////////// end SipArrayTuple.sip ////////////////////

Basically I'm confused about how to tell SipArrayTuple.sip to pick up
the definition for PyObject. If I comment out the inclusion
of SipArrayTuple.sip in sihippo.sip above, the vector.sip code
passes through sip OK. Is it because inside vector.sip (see below)
the PyObject pointer is used inside a %ConvertFromTypeCode  block?
I don't think I need to do any Convert stuff.

Also is there some particular place I should put the
%PostInitialisationCode
    import_libnumarray();
%End

in sihippo.sip?, or can I leave it where it is?

I would appreciate any and all advice - I'm pretty much a python / sip
newbie! Could you please copy a reply directly to my e-mail
address Tony.Willis at nrc-cnrc.gc.ca as I don't read this list very often.

Thank you!

Tony
___________
Tony Willis
National Research Council   Tony.Willis at nrc-cnrc.gc.ca
Box 248                     (250)493-2277
Penticton, BC  V2A 6J9      fax: 493-7767
Government of Canada        Gouvernement du Canada


/////////////// extraction from vector.sip ////////////////////
%MappedType std::vector<double>
{
%TypeHeaderCode
#include <vector>
%End

%ConvertFromTypeCode
	// Handle no list.

	if (!sipCpp)
		return PyList_New(0);

	// Convert to a Python list of doubles

        PyObject *l;

	// Create the list.

	if ((l = PyList_New(sipCpp -> size())) == NULL)
		return NULL;

	// Get it.

	for ( unsigned int i = 0; i < sipCpp -> size(); ++i)
          if (PyList_SetItem(l,i,PyFloat_FromDouble((double)(*sipCpp)[i])) < 0)
		{
			Py_DECREF(l);

			return NULL;
		}

	return l;
%End
}
/////////////// end extraction from vector.sip ////////////////////






More information about the PyQt mailing list