Subject: pyhoca-gui fails to fall back to Gtk-2.0 notifications (pynotify)

From: Ondřej Grover <[email-masked]>
Date: Sun, 31 Jan 2016 09:04:01 +0100

Package: pyhoca-gui
Version: 0.5.0.5-0x2go1+git20160128.1329+jessie.main.1

Dear maintainers,

I believe commit e44e848415eff3e4dab69e990adfc447e79143f8 which introduced
GTK3 notification support broke GTK2 notification support fallback. The
problem was not present in 0.5.0.4

I believe the problem lies in this import construct in
pyhoca/wxgui/notify.py which will fail the same way even when put alone in
a file

try:
    from gi.repository import Notify as _Notify
except ImportError:
    import pynotify as _Notify

I think the problem is that even if the GTK3 Notify module is not
available, many GTK3 libraries get loaded and then the pynotify import
fails with

ImportError: could not import gobject (could not find _PyGObject_API object)

This is the same exception I see when running pyhoca-gui.

I think some more sophisticated GTK version selection mechanism is needed,
one that would not start loading conflicting libraries.

As a workaround for now I just removed that GTK3 import on my system.

My system is Debian 8.3 Jessie with the following (possibly relevant) gtk
packages installed

dpkg -l | grep '^.i.*gtk[23].*'

ii  libavahi-ui-gtk3-0:amd64               0.6.31-5
               amd64        Avahi GTK+ User interface library for GTK3
ii  libcanberra-gtk3-0:amd64               0.30-2.1
               amd64        GTK+ 3.0 helper for playing widget event sounds
with libcanberra
ii  libcanberra-gtk3-module:amd64          0.30-2.1
               amd64        translates GTK3 widgets signals to event sounds
ii  libdbusmenu-gtk3-4:amd64               12.10.2-1
                amd64        library for passing menus over DBus - GTK+
version
ii  libgirara-gtk3-1:amd64                 0.2.3-1
                amd64        library for minimalistic user interfaces
(shared libraries, GTK+ 3)
ii  libgtk2-ex-podviewer-perl              0.18-1
               all          Perl Gtk2 widget for displaying Plain Old
Documentation (POD)
ii  libgtk2-ex-simple-list-perl            0.50-2
               all          simple interface to Gtk2's complex MVC list
widget
ii  libgtk2-imageview-perl                 0.05-2+b1
                amd64        Perl bindings for the GtkImageView image
viewer widget
ii  libgtk2-perl                           2:1.2492-4
               amd64        Perl interface to the 2.x series of the Gimp
Toolkit library
ii  libgtk2.0-0:amd64                      2.24.25-3
                amd64        GTK+ graphical user interface library
ii  libgtk2.0-bin                          2.24.25-3
                amd64        programs for the GTK+ graphical user interface
library
ii  libgtk2.0-common                       2.24.25-3
                all          common files for the GTK+ graphical user
interface library
ii  libwxgtk3.0-0:amd64                    3.0.2-1+b1
               amd64        wxWidgets Cross-platform C++ GUI toolkit (GTK+
runtime
ii  pinentry-gtk2                          0.8.3-2
                amd64        GTK+-2-based PIN or pass-phrase entry dialog
for GnuPG
ii  python-gtk2                            2.24.0-4
               amd64        Python bindings for the GTK+ widget set
ii  python-wxgtk3.0                        3.0.1.1+dfsg-2
               amd64        Python interface to the wxWidgets
Cross-platform C++ GUI toolkit

Kind regards,
Ondřej Grover

---

From: Mihai Moldovan <[email-masked]>
Date: Thu, 4 Feb 2016 17:49:23 +0100

On 31.01.2016 09:04 AM, Ondřej Grover wrote:
> I believe commit e44e848415eff3e4dab69e990adfc447e79143f8 which introduced GTK3
> notification support broke GTK2 notification support fallback. The problem was
> not present in 0.5.0.4
> 
> pyhoca/wxgui/notify.py which will fail the same way even when put alone in a file
> 
> try:
> I think the problem is that even if the GTK3 Notify module is not available,
> many GTK3 libraries get loaded and then the pynotify import fails with 
> 
> I think some more sophisticated GTK version selection mechanism is needed, one
> that would not start loading conflicting libraries.

Thanks for the report. I think your analysis is spot-on.

It looks like a lot of modules from gobject-introspection are loaded, until it
hits an error importing the Notify module.

Then, importing pynotify fails, because the old, static python-gobject module
that pynotify depends on conflicts with the new python-gi
(gobject-introspection) modules.

> As a workaround for now I just removed that GTK3 import on my system.

But it's just that, a workaround.

I've been looking around for a way to actually rollback a failing module import
and came up with zit.

The only "actual" solution I currently see is removing pynotify support
completely, because the gobjects interface is deprecated anyway. However,
that'll break notification support on older systems not having GI/GTK3.

Not that I'd like it, of course. A working fallback would have been great.

Mihai

---

From: Ondřej Grover <[email-masked]>
Date: Thu, 4 Feb 2016 18:07:17 +0100

Thank you for looking into this.

> I've been looking around for a way to actually rollback a failing module
AFAIK that's not really possible in Python as of writing this, especially
with complicated binary modules.
I think a solution might be to abandon the common Python EAFP idiom,
because it assumes graceful failure without such ugly side-effects.
However, I'm not sure what the LBYL alternative is in this case. But I
think there should be one, possibly loading just some high-level gi module
to list available APIs?

Kind regards,
Ondřej Grover

---

From: Mihai Moldovan <[email-masked]>
Date: Fri, 5 Feb 2016 00:20:34 +0100

On 04.02.2016 06:07 PM, Ondřej Grover wrote:
> On Thu, Feb 4, 2016 at 5:49 PM, Mihai Moldovan <[email-masked]
> <mailto:[email-masked]>> wrote:
> 
> AFAIK that's not really possible in Python as of writing this, especially with
> complicated binary modules.
> I think a solution might be to abandon the common Python EAFP idiom, because it
> assumes graceful failure without such ugly side-effects. However, I'm not sure
> what the LBYL alternative is in this case. But I think there should be one,
> possibly loading just some high-level gi module to list available APIs?

Probably not.

In a new python2 interpreter, try this:

import sys
print sys.modules
import gi.repository
print sys.modules

I guess gi.repository is the only module that could be used to query additional
modules (like Notify.)

The modules list explodes. With GI, we end up in GI hell. And there's no exit.
Ever. Again.

I'd rather suggest the following: another try block, looking for pynotify2.

On Debian, I'd switch the dependencies to use gir1.2-notify-0.7 and python-gi,
or python-notify2 (dropping python-notify completely), while *SUSE, EPEL and
Fedora will continue depending upon the GI modules for newer versions and
pynotify for older versions (at least Fedora doesn't seem to have pynotify2.)

It should probably work as a drop-in replacement for pynotify in our case (i.e.,
we don't use any callbacks or anything fancy.)

Going forward, the deprecated gobject modules for GTK2 will likely be removed at
some point anyway and we should focus on GTK3.

Any objections?

Mihai