GNOME Bugzilla – Bug 710646
super() does not work within vfunc overrides
Last modified: 2018-01-10 20:34:54 UTC
Created attachment 257848 [details] example code As super() works fine for __init__, I would have expected that it would also work for other functions. However, the do_* functions do not work properly, an error is returned: Here is the output from the attached example: Traceback (most recent call last):
+ Trace 232656
super(Test, self).do_draw(cr)
I am not sure what kind of magic would be needed to make super() work in this case; though I expect it could be interesting with the whole bound-method stuff.
Oh, and super(Test, self).do_draw(self, cr) causes a recursion.
The code currently looks something like this (in pygi-info.c): class vfunc(object): def __get__(self, *args): print("__get__", args) return self def __call__(self, *args): print("__call__", args) class Widget(object): do_draw = vfunc() class Window(Widget): pass class Custom(Window): def do_draw(self): super(Custom, self).do_draw() Custom().do_draw() ---- super() gives us the vfunc instance of Widget and passes the type and instance of our Custom instance. For super to work we'd need a function bound to the parent gtype. The only solution I can think of is to copy all vfuncs from the base when creating a new class and binding it to the gtype of that class. This way super gives us the already bound method of the parent. The code would need to handle passing a unnecessary "self" arg for compatibility (Custom().do_draw(self) currently works)
Hmm, what prevents us from simply returning a new function that binds the method? i.e.: class vfunc(object): def __get__(self, instance, cls): print("__get__", instance, cls) if instance is None: return self else: return lambda *args, **kwargs : self(instance, *args, **kwargs) def __call__(self, *args): print("__call__", args) Seems to work here, or am I missing some obvious corner case?
We need to call Window.do_draw(), but the Window class never comes up during the super() process.
Hm, yeah, I agree now that copying would be the sanest option. Doing the magic in __get__ is not feasible looking at the different combinations of parameters it gets. But even if there are copies I am unsure on how one could solve the backward compatibility issues. Having magic that accepts a new "self" argument on the function seems dangerous. Another way might be to implement tp_getattro and unbind the returned vfunc again (and warn in the process). This should be feasible as calling do_* only makes sense when chaining up. Assuming: d = Gtk.Dialog() Then the following is valid: Gtk.Window.do_draw(d) super(Gtk.Window).do_draw(w) super(Gtk.Window, w).do_draw() And this is not: Gtk.Window().do_draw(d) <- warns instead of failing d.do_draw() <- Doesn't make any sense as d.draw() exists. It will error as it isn't bound.
-- GitLab Migration Automatic Message -- This bug has been migrated to GNOME's GitLab instance and has been closed from further activity. You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.gnome.org/GNOME/pygobject/issues/58.