Panda3D classes as PyObject


I’ve been trying some things with python callback functions in C++ classes. Here’s what I’m trying to do:
(1) I have two C++ classes, MyClass and MySecondClass, both useable from python (using interrogate)
(2) the users sets the callback using MyClass.set_callback(PyObject myPythonFunc)
(3) whenever my class feels like it, it calls the callback function using PyEval_CallObject
(4) when calling the callback function, it passes a MySecondClass instance as parameter to the function.
With 1-3 I have no trouble, just with 4. I know I need to pass a PyObject
, but I can’t seem to find a way to get a Panda class and grab it as PyObject (I know its related to Dtool_PyInstDef but that doesn’t bring me much further).
I’ve been looking around in py_panda.h but am still clueless how to do this. Or isn’t there a clean solution for this at all?

Thanks in advance,

It depends on the inheritance hierarchy of MySecondClass. If it inherits from TypedReferenceCount, you can do it with:

  PyObject *self =
      DTool_CreatePyInstanceTyped(this, Dtool_TypedReferenceCount,
                                  true, false, get_type_index());

There are similar functions for different inheritance hierarchies. Check some of the generated code output by interrogate for more examples.


Thanks for your reply! This seems to work good, I had to change Dtool_TypedReferenceCount to Dtool_MySecondClass, (otherwise I’d get a TypedReferenceCount object in python and not what I want), and had to add these lines to the top of my file:

extern EXPCL_PANDA_GRUTIL Dtool_PyTypedObject Dtool_MySecondClass;

[size=92](viciously stolen from memoryUsagePointers.cxx)[/size]

After that, it worked great. Thanks again!

If you just got a plain TypedReferenceCount pointer in Python, it might mean that you haven’t interfaced with Panda’s runtime typing system properly. Coincidentally, I’ve been noticing this error message at startup lately:

:interrogatedb(warning): Class GeoMipTerrain has a zero TypeHandle value; check that init_type() is called.

Could this be the type in question? :slight_smile:


Yeah, I just noticed I forgot the init_type just a few seconds before I read your post. :slight_smile: Just fixed it in the config_grutil file.
I didn’t actually notice it because I had notify-level-interrogatedb to “error”, because of a different warning that annoyed me.
So, I guess it’s illegal to do it my way, even though it seems to work?

It’s perfectly legal to do it with an explicit cast to the known type. No reason to change that.

It’s just that, if you had the TypeHandle initialized properly, it should have also worked with a cast to TypedReferenceCount, because from there the dynamic runtime type system would have automatically downcast it to the appropriate type.


Ah, that’s good to know. Thanks again!

Hmm, I just noticed grutil itself compiles fine, but I wanted to recompile pandatool and got this (at bam-info step):

/usr/local/panda/lib/ undefined reference to `PyEval_CallFunction'
collect2: ld returned 1 exit status

Did I miss something in the .pp files or so?

We have to shadow all of the Python calls we make in dtool/src/pystub/pystub.cxx. Take a look at this file and add the new Python call to it (it goes in two different places). Should be pretty clear where it belongs; the list is in alphabetical order.


Ah. That seems to work good, thanks!

I just realized that DTool_CreatePyInstanceTyped() will “steal” a reference to the ReferenceCount object you pass in, at least if you pass true for the third parameter (which you should), so it’s necessary to explicitly up the reference count of your object first:

  PyObject *self =
      DTool_CreatePyInstanceTyped(this, Dtool_TypedReferenceCount,
                                  true, false, get_type_index()); 


Ah, okay. Just added that, thanks!