|
Hi Oliver,
> I have understood that the SWIG::director would allow me to override
> an existing libsbml method such as
> libsbml.SpeciesReference.getSpecies().
>
> This might indeed be helpful, thank you for the hint.
>
> However, my original problem is that I add an object whose class is
> derived from
> libsbml.SpeciesReference to the ListOfReactants in libsbml.Reactions.
Although it may not be immediately clear, SWIG directors will solve
your problem as well. They allow for Python subclasses to be
completely substitutable for their parent C++ classes.
> I do not want to change the sbml library for compatibility reasons
Right. I was suggesting that if you came-up with a decent solution
that required reasonable and modest modifications to libSBML, I would
be willing to fold those changes back into the library.
> I could only imagine that my object of my subclass must know the
> address of the C++ proxy which is generated from the
> SWIG::director. I could then override 'this' with that C++ address
> to track my subclass-object.
>
> However, this sounds very complicated.
>
> What do you think?
This will work in libSBML 2.3.x but not 3.0. It's not too
complicated. The example program at the end of this message uses a
customized Python dictionary (ObjectRegistry) to map subclassed
libSBML objects to their parent libSBML object based on SWIG 'this'
pointers. In libSBML 3.0, the problem is libSBML copies objects
passed to it rather than simply taking over ownership of the passed-
in object. Copying objects means the 'this' pointers will no longer
match. You could change my example program to use SBase ids (species
for SpeciesReferences) which *should* always be unique. This assumes
however that i) you have an id at the time of object construction,
ii) you don't change an object's id (otherwise, you would have to
update the registry), and iii) you don't store UnitDefinitions or
local Parameters in the registry as they are in separate namespaces
and their ids can legally "conflict" with SBML objects elsewhere.
Again, I think directors are the way to go. In the meantime, the
code below should provide a decent interim solution.
Thanks.
Ben
#!/usr/bin/env python
import libsbml
class ObjectRegistry (dict):
def add (self, obj):
self[obj] = obj
def getKey (self, obj):
if not hasattr(obj, 'this'): raise TypeError('Not a SWIG object')
return hex( obj.this )
def __contains__ (self, key):
return dict.__contains__(self, self.getKey(key))
def __getitem__ (self, key):
return dict.__getitem__(self, self.getKey(key))
def __setitem__ (self, key, value):
dict.__setitem__(self, self.getKey(key), value)
Registry = ObjectRegistry()
class MySpeciesReference (libsbml.SpeciesReference):
def __init__ (self):
libsbml.SpeciesReference.__init__(self)
Registry.add(self)
msr = MySpeciesReference()
r = libsbml.Reaction()
r.addReactant(msr)
sr = r.getReactant(0)
print type(sr)
print type(Registry[sr])
|