GNOME Bugzilla – Bug 703338
Regression: changed override on Gtk.Entry stopped working
Last modified: 2014-08-23 05:22:43 UTC
We start to obtain user bug submission for our application (Gramps) with changed override no longer working: attributes not accessible from the overrided method. It's unclear at the moment to us what change in gtk is causing this. The code is an inheritance of Gtk.Entry, with code: __gtype_name__ = 'ValidatableMaskedEntry' __gsignals__ = { 'content-changed': (GObject.SignalFlags.RUN_FIRST, None, ()), 'validation-changed': (GObject.SignalFlags.RUN_FIRST, None, (GObject.TYPE_BOOLEAN, )), 'validate': (GObject.SignalFlags.RUN_LAST, GObject.TYPE_PYOBJECT, (GObject.TYPE_PYOBJECT, )), 'changed': 'override', } __gproperties__ = { 'data-type': (GObject.TYPE_PYOBJECT, 'Data Type of the widget', 'Type object', GObject.PARAM_READWRITE), 'mandatory': (GObject.TYPE_BOOLEAN, 'Mandatory', 'Mandatory', False, GObject.PARAM_READWRITE), } Note the 'changed' which is 'override'. This connects to following method: def do_changed(self): if self._block_changed: self.emit_stop_by_name('changed') return self.emit('content-changed') self.validate() Since latest Debian Jessie and in Mageia with both gtk+-3.8 & 3.9 this code stopped working and gives error: Unhandled exception Traceback (most recent call last):
+ Trace 232172
if self._block_changed:
It seems that all attributes set in the __init__ method of the ValidatableMaskedEntry defined are no longer accessible from the the do_changed method. I'll update this ticket if I obtain more info of users encountering this.
Working workaround for above do_changed method: def do_changed(self): - if self._block_changed: + block_changed = getattr(self, '_block_changed', True) + if block_changed: self.emit_stop_by_name('changed') return self.emit('content-changed') So it seems do_changed is now called before correct __init__ of the object, but by using getattr to see if the attribute is already present, one can work around the error.
Hi Benny, A simplified example exhibiting the problem would be helpful. There could be any number of things which changed in the stack that cause this to happen. I know there were some class initialization changes (bug 686149) which may affect this. But there is also the potential that GtkEntry now emits the signal upon instance initialisation. You could check this by putting print statements before and after the super class call in the sub-class __init__ (and also a print within do_changed). class CustomEntry(Gtk.Entry): def __init__(self): print('before super') super().__init__() print('after super') If this shows to be true (do_changed is called in between the super prints) then a potentially cleaner workaround would be to put the instance variable assignments before the super call and this bug can move to GTK+ (if it is still be considered a bug at that point).
Created attachment 248096 [details] test case showing the issue Test with python testgtkentry.py change in top of file workaround = True for the workaround.
I made a test case which is uploaded. Asked user to test, I don't have 3.8 installed myself yet.
About "a potentially cleaner workaround would be to put the instance variable assignments before the super call" They already are before the super (well here actually MaskedEntry.__init__(self) ), so it must be something more exotic. See in test case: self._block_changed = False print ('before super') MaskedEntry.__init__(self) print ('after super')
Ok, the tester reports that with the uploaded testcase, the bug does not happen, so what happens in our app is more complicated (in the app there is an extra undoable buffer on the entry, and glade is used to construct the entries, those are the most immediate differences that pop up). I'll try to test it myself further when I upgrade my stack myself, and then update the testcase if I find a way to trigger it.
I was also unable to get the example to reproduce the problem on versions 3.8.2 and 3.9.3.
reopening as I can't see any open non developer question.
(In reply to comment #8) > reopening as I can't see any open non developer question. I guess it wasn't explicitly asked. (In reply to comment #6) > I'll try to test it myself further when I upgrade my stack myself, and then > update the testcase if I find a way to trigger it. Benny can you still reproduce this with newer versions of the stack? The attached test case has a dependency on "gramps". If I remove that import and delete the contents of the "on_validate" handler, I don't see any problems with the script. But I'm not entirely sure that justifies that this has been fixed...
I've been unable to reproduce this, is it still an issue?
If I undo the patch in https://bugzilla.gnome.org/show_bug.cgi?id=703338#c1 in the shipped version 4.0.x of Gramps, we still have the crash. In case you have Gramps 4.0.0+ installed, changing --- a/gramps/gui/widgets/validatedmaskedentry.py +++ b/gramps/gui/widgets/validatedmaskedentry.py @@ -1176,8 +1176,9 @@ class ValidatableMaskedEntry(MaskedEntry): # Virtual methods def do_changed(self): - block_changed = getattr(self, '_block_changed', True) - if block_changed: + #block_changed = getattr(self, '_block_changed', True) + #if block_changed: + if self._block_changed: self.stop_emission_by_name('changed') return self.emit('content-changed') and running the app: create empty family tree-> load, go to event view->add event hits the bug. However, the testcase does not hit this bug, as the user indicated. For us, the fact the workaround works is great, however, it seems the workaround is still needed. It must be something inherent in the stacking of classes as used in Gramps though, so no idea on how to create a reduced test case.
Ok, thanks for the update.
My stack is not that recent though: gtk++ : 3.8.6 pygobject : 3.10.0 John Ralls is a Gramps developers, you could ping him perhaps to try with more recent version. It's a one line change in the Gramps code to see if it still happens.
Confirming. This is probably the same or very similar to bug 566571. The problem is vfuncs are overriding the *parent* class vfunc in GtkEntry which is very broken. This can be seen as follows: class E(Gtk.Entry): def do_changed(self): print('on_changed') e = Gtk.Entry() e.emit('changed') # prints changed
This is indeed the same bug since "changed" is actually a vfunc of the GtkEditable interface. A workaround is explicitly re-inherit from GtkEditable: class MyEntry(Gtk.Entry, Gtk.Editable): def do_changed(self): ... I recommend doing this since without it, all entries will contain overridden vfunc AFAICT... *** This bug has been marked as a duplicate of bug 566571 ***