After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 710646 - super() does not work within vfunc overrides
super() does not work within vfunc overrides
Status: RESOLVED OBSOLETE
Product: pygobject
Classification: Bindings
Component: introspection
3.10.x
Other Linux
: Normal normal
: ---
Assigned To: Nobody's working on this now (help wanted and appreciated)
Python bindings maintainers
Depends on:
Blocks:
 
 
Reported: 2013-10-22 12:49 UTC by Benjamin Berg
Modified: 2018-01-10 20:34 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
example code (527 bytes, application/octet-stream)
2013-10-22 12:49 UTC, Benjamin Berg
Details

Description Benjamin Berg 2013-10-22 12:49:25 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):
  • File "./drawing.py", line 17 in do_draw
    super(Test, self).do_draw(cr)
TypeError: draw() takes exactly 2 arguments (1 given)

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.
Comment 1 Benjamin Berg 2013-10-22 13:05:16 UTC
Oh, and
    super(Test, self).do_draw(self, cr)

causes a recursion.
Comment 2 Christoph Reiter (lazka) 2017-04-03 08:06:01 UTC
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)
Comment 3 Benjamin Berg 2017-05-05 09:38:16 UTC
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?
Comment 4 Christoph Reiter (lazka) 2017-05-05 09:46:37 UTC
We need to call Window.do_draw(), but the Window class never comes up during the super() process.
Comment 5 Benjamin Berg 2017-05-05 15:26:25 UTC
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.
Comment 6 GNOME Infrastructure Team 2018-01-10 20:34:54 UTC
-- 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.