[pygtk] Subclassing gobject classes other than gobject.GObject
Hrvoje Nikšić
hrvoje.niksic at avl.com
Wed Nov 22 21:49:47 WST 2006
I'm looking into using gobject's OO framework for the low-level portion
of an application, with the intention of using Python for extending and
scripting the low-level functionality. Ideally, the C code would just
use gobjects and know nothing (or as little as possible) about Python.
While studying PyGobject I stumbled into a subclassing problem. I'd
like to subclass from Python a gobject class written in C (and itself
derived from GObject), and eventually pass its instances to the C code
that expects regular gobjects. This would allow Python code to create
first-class GObject classes and objects usable within the framework.
For example:
# MyClass is a gobject class implemented in C.
MyClass = gobject.type_from_name('MyClass')
# Subclass it in Python.
class Foo(MyClass):
... additional code here ...
gobject.type_register(Foo)
# From this point, instances of Foo should be GObject type instances
# and therefore first-class citizens in the GObject world.
Let's try it:
[~/work/testgobject]$ python
Python 2.4.4c1 (#2, Oct 11 2006, 21:51:02)
[GCC 4.1.2 20060928 (prerelease) (Ubuntu 4.1.1-13ubuntu5)] on linux2
[...]
>>> import gobject
>>> import ctypes
>>> ctypes.cdll
# load a pure-C SO that implements a test gobject type, DateTimeType
>>> x=ctypes.cdll.LoadLibrary("./x.so")
>>> x.initialize() # set up the type
>>> gobject.type_from_name("DateTimeType")
<GType DateTimeType (135936872)>
>>> o=gobject.new(gobject.type_from_name('DateTimeType'))
>>> o
<__main__.DateTimeType object (DateTimeType) at 0xb7d8ac84>
That part works -- the gtype is accessible from Python and appears
usable. But what if I want to subclass the type? Since Python 2.4
allows subclassing built-in types, I tried it this way:
>>> class Foo(gobject.type_from_name("DateTimeType")):
... def foo(self):
... self
...
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: Error when calling the metaclass bases
GType.__init__() takes exactly 1 argument (3 given)
Obviously, this is wrong. It doesn't make sense to try to subclass the
GType type, we must inherit from a type that can create actual GType
instances. The distinction is subtle, but very important, as shown
here:
>>> gobject.type_from_name('GObject')
<GType GObject (80)> # (1)
>>> gobject.type_from_name('DateTimeType')
<GType DateTimeType (135936872)> # (2)
>>> gobject.GObject
<type 'gobject.GObject'> # (3)
To inherit from DateTimeType, I need to get a Python type object like
(3), not a GType type object, like (1) or (2). But hey, I already have
a Python *instance* of DateTimeType, so the type must be accessible as
well:
>>> type(o)
<class '__main__.__main__.DateTimeType'>
If it's a class object, it must be subclassable:
>>> class Foo(type(o)):
... def foo():
... return self
...
>>> foo=Foo()
>>> foo
<Foo object (DateTimeType) at 0xb7d8fd74>
But Foo is still not a separate GObject class; for GObject code, a Foo
object is indistinguishable from a DateTimeType object:
>>> gobject.type_name(type(foo))
'DateTimeType'
To fix that, we must register it with GType:
>>> gobject.type_register(Foo)
<class '__main__.Foo'>
>>> gobject.type_name(type(foo))
'__main__+Foo'
Instances of Foo are now not only first-class citizens of the GObject
world, but GObject is also aware of the inheritance relationship between
DateTimeType and Foo:
>>> gobject.type_children(gobject.type_from_name('DateTimeType'))
[<GType __main__+Foo (136049464)>]
In conclusion, it would seem that PyGTK's gobject wrapper has all the
pieces needed for this, with the following parts being (to me)
non-obvious:
1. What is the canonical way to convert <GType x> to something like
<class 'x'> as shown above? Creating an instance of x and calling
type(x) seems like an incredible kludge.
2. Has anyone tried to pass GObjects created in a similar way back to C?
How does one convert a PyObject* to a GObject*?
3. Is it intended to be able to subclass gobject classes other than
GObject? All the examples I can find only demonstrate subclassing
gobject.GObject and its Python class children.
I would appreciate any help with this. If this is described in a
publicly accessible document, feel free to point it out.
More information about the pygtk
mailing list