[Zope-dev] Strange Problem with a Product using SWIG Python Proxy Classes

Sean Gillies sgillies@frii.com
Thu, 2 Jan 2003 12:52:01 -0700


Greetings,

My question concerns the use of SWIG Python proxy classes in a
Zope Product.  In the ZDG and elsewhere, I have seen the statement
that if an object is pickleable, it can be used as a persistent
object in a Zope Product.  In my experience, my SWIG Python proxy
classes are pickleable, can be stored in a ZODB, the Product that
uses them can be installed in Zope, instances of the Product
classes can be added and work, but on a restart of Zope, the
instances of my Product classes are broken and will cause Zope
to segfault on any attempt to access the proxy class.  I am
using Python 2.1.3 with threads and the thread stack size patch
built on OS X 10.2 and Zope 2.6.0.  I've had no other problems
with Python or Zope on this machine until I began developing this
new Product.

I am developing a Zope Product that will use a Python interface to
a C language GIS library.  The Python module is created with SWIG
(1.3.17) and consists of proxy classes that dispatch methods and
member variable access to the underlying C objects.  For those who
are unfamiliar with SWIG, here's a link to a doc that describes
the proxy classes:

http://www.swig.org/Doc1.3/Python.html#n28

Basically, I have a C structure with an attribute named 'name',
a C library named '_mapscript' and have a proxy class like

class mapObj(_object):
     __swig_setmethods__ = {}
     __setattr__ = lambda self, name, value: _swig_setattr(self, mapObj, 
name, value)
     __swig_getmethods__ = {}
     __getattr__ = lambda self, name: _swig_getattr(self, mapObj, name)
     __swig_setmethods__["name"] = _mapscript.mapObj_name_set
     __swig_getmethods__["name"] = _mapscript.mapObj_name_get
     if _newclass:
         name = property(_mapscript.mapObj_name_get,
                         _mapscript.mapObj_name_set)
     def __init__(self,*args):
         self.this = apply(_mapscript.new_mapObj,args)
         self.thisown = 1
     def __del__(self, destroy= _mapscript.delete_mapObj):
         try:
             if self.thisown: destroy(self)
         except: pass

As I understand, the 'if _newclass ...' code should be passed by Python 
2.1.  I have verified that instances of this class can be
pickled using dump/load from pickle and cPickle.  I have also been
able to successfully save and load instances of the mapObj proxy
class using ZODB from the Python interpreter (outside of Zope).
Instances loaded from a non-Zope ZODB FileStorage work as designed.

In my Product, I use this SWIG Python proxy class as a member of
a Python class (here's a fragment):

def ZMap(...):
     def __init__(self):
         self._map = mapObj()
     def __del__(self):
         del self._map
     def getName():
         return self._map.name

I created methods to add the Product and they work.  Once the
Product is installed, I can add new instances and they work just
as I've designed.  For example, when an instance named 'map1' is
added to a folder under the root named 'Maps' I can access the url
/Maps/map1?getName and I get exactly what I expect.

However, when I restart Zope, any attempt to access that url causes
a segfault and a restart of Zope.

I have had the same experience with testing my Zope FileStorage
(Data.fs) from the Python interpreter.  Newly created instances
of my ZMap class work fine.  Saved instances loaded from Data.fs
are broken and cause a segfault when I try to access any member
of _map.

I'm very puzzled and would greatly appreciate answers, annecdotes
or ideas from anyone who has experience in this area.

thanks!
Sean


# Sean Gillies
# sgillies@frii.com