how to get access to a NodePath subclass

I don’t really understand the python class structure or the interface built by swing between python and c++, so this may be impossible. But what I want is to be able to put NodePath subclasses like the following

class SNP(NodePath):
    def __init__(self,foo):
        NodePath.__init__(self,'name')
        
        self.foo = foo

into the scene graph, like so:

>>> from SNP import SNP
>>>
>>> s = SNP(4)
>>> s.reparentTo(render)
>>> s.foo
4

and then get it back via, say, find()

>>> from SNP import SNP

>>> b = render.find('**/name')
>>> b
render/name
>>> s
render/name

but what I get back (I assume) is just the NodePath chunk of the object, because that’s all that c++ knows about when it does its scene graph gymnastics. As a result, information is lost:

>>> b.foo
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AttributeError: 'libpanda.NodePath' object has no attribute 'foo'

I have some fairly large classes (most of my classes, actually) that rely on NodePath as their base, and in turn have some lengthy collections of these objects. I’d like to be able to get access to their non-Panda members via picking or scene graph searching. Is there any/a recommended way to do this?

Try this trick:

s.setPythonTag('trueClass', s)

Then:

b = render.find('**/name')
s = b.getPythonTag('trueClass')

which will return the Python object you associated with the NodePath under the tag “trueClass”.

Or even:

s = b.getNetPythonTag('trueClass')

which is the same as getPythonTag(), but it will walk up the tree if necessary to find the first parent that contains a definition for the tag “trueClass”, which is particularly useful if you got the NodePath via picking (which is likely to return a child of your root NodePath).

Caution! Note that when you do this:

s.setPythonTag('trueClass', s)

You have created a reference count loop. s now contains a reference to itself, and so it will never be freed by Python’s reference-counting mechanism. Worse, for various fiddly reasons having to do with the way Python’s garbage collector works, it will never be garbage collected either. So this will create a memory leak, unless you remember to do:

s.clearPythonTag('trueClass')

when you are done with it.

David