Repository: beeware/toga

Issue:
Recommend to install pygobject from pip
I apologize to override the default template, but I don't think its applicable for this issue.

pygobject has been available from `pip` for a while now, and is always at the latest stable release.

Distro package managers are generally a little slow in getting packages updated (in this case its just a 3 months older release for Fedora)

`pip` on the other hand always has the latest version, and is great for people who use virtualenvs, since you have to do some ugly linking to get the system pygobject on the virtualenv

It also removes the intent to have code like this https://github.com/pybee/toga/blob/master/src/gtk/toga_gtk/app.py#L22

This code suggested me to use `pacman` to install pygobject on Fedora (might throw off beginners)


Discussion:
Most users wont actually need to run pacman - the whole point of Toga is to use the system graphics libraries, and pygobject *should* be installed if you've got a graphical desktop. 

However, your point is valid - it would be vastly preferable to use PyPI, rather than the nasty symlink hack.

The reason we haven't done this historically is that PyGObject was only recently packaged in a way that it *could* be installed from PyPI. If you look at the history for the package, only the 3.27 series has been released to PyPI. That means this approach has only been possible for a little over 2 months.

If you'd like to submit a patch that modifies the Toga GTK backend to use a pip-installable PyGObject, it would definitely be merged.

Resolving patch:
diff --git a/src/gtk/setup.py b/src/gtk/setup.py
--- a/src/gtk/setup.py
+++ b/src/gtk/setup.py
@@ -1,13 +1,9 @@
 #/usr/bin/env python
 import io
 import re
-import sys
 
 from setuptools import setup, find_packages
 
-if sys.version_info[:3] < (3, 4):
-    raise SystemExit("Toga requires Python 3.4+.")
-
 
 with io.open('toga_gtk/__init__.py', encoding='utf8') as version_file:
     version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", version_file.read(), re.M)
@@ -33,7 +29,10 @@
     install_requires=[
         'toga-core==%s' % version,
         'gbulb>=0.5.3',
+        'pycairo>=1.17.0',
+        'pygobject>=3.14.0',
     ],
+    python_requires='~=3.4',
     tests_require=[
         'toga-dummy==%s' % version
     ],
diff --git a/src/gtk/toga_gtk/app.py b/src/gtk/toga_gtk/app.py
--- a/src/gtk/toga_gtk/app.py
+++ b/src/gtk/toga_gtk/app.py
@@ -1,84 +1,11 @@
 import asyncio
-import os
 import signal
 import sys
 
-try:
-    import gi
-except ImportError:
-    # app.py is the first module that will be imported when you import toga_gtk.
-    #
-    # If Gtk can't be imported, it may be because we're in a virtualenv,
-    # and the system python libraries aren't visible. This can be fixed by
-    # creating a symlink into the site-packages
-    # Try creating a symlink to the system library location.
-    # base_packages_dir is where the packages installed by the package manager
-    # can be found.
-    # gi_system_install_path is where gi can be found in the packages dir.
-    # installer_command is the command the user can run to install gi.
-    py_version = "%d.%d" % (sys.version_info.major, sys.version_info.minor)
-
-    if sys.version_info.major == 3:
-        if os.path.isdir('/usr/lib64/python%s/site-packages/' % (py_version,)):
-            # Fedora
-            base_packages_dir = '/usr/lib64/python%s/site-packages/' % (py_version,)
-            gi_system_install_path = '/usr/lib64/python%s/site-packages/gi' % (py_version,)
-            installer_command = 'dnf install pygobject3 python3-gobject'
-        elif os.path.isdir('/usr/lib/python3/dist-packages/'):
-            # Ubuntu, Debian
-            base_packages_dir = '/usr/lib/python3/dist-packages/'
-            gi_system_install_path = '/usr/local/lib/python3/dist-packages/gi'
-            installer_command = 'apt-get install python3-gi'
-        elif os.path.isdir('/usr/lib/python%s/site-packages/' % (py_version,)):
-            # Arch
-            base_packages_dir = '/usr/lib/python%s/site-packages/' % (py_version,)
-            gi_system_install_path = '/usr/lib/python%s/site-packages/gi' % (py_version,)
-            installer_command = 'pacman -S python-gobject'
-        else:
-            raise RuntimeError("Unable to locate your Python packages dir.")
-    else:
-        raise RuntimeError("Toga requires Python 3.")
-
-    # Use the location of this package to guide us to
-    # the location of the virtualenv.
-    gi_symlink_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'gi')
-    pygtkcompat_symlink_path = os.path.join(os.path.dirname(os.path.dirname(__file__)),  'pygtkcompat')
-    cairo_symlink_path = os.path.join(os.path.dirname(os.path.dirname(__file__)),  'cairo')
-
-    if gi_symlink_path == gi_system_install_path:
-        # If we're not in a virtualenv, just raise the original import error.
-        raise
-    else:
-        gi_path = os.path.join(base_packages_dir, 'gi')
-        pygtkcompat_path = os.path.join(base_packages_dir, 'pygtkcompat')
-        cairo_path = os.path.join(base_packages_dir, 'cairo')
-        if os.path.exists(gi_path) and os.path.isdir(gi_path):
-
-            # If we can identify the gi library, create a symlink to it.
-            try:
-                print("Creating symlink (%s & %s) to system GTK+ libraries..." % (gi_symlink_path, pygtkcompat_symlink_path))
-                os.symlink(gi_path, gi_symlink_path)
-                os.symlink(pygtkcompat_path, pygtkcompat_symlink_path)
-
-                try:
-                    print("Creating symlink (%s) to system Cairo libraries..." % cairo_symlink_path)
-                    os.symlink(cairo_path, cairo_symlink_path)
-                except OSError:
-                    # If we can't create the symlink, we'll get an error importing cairo;
-                    # report the error at time of use, rather than now.
-                    pass
-
-                # The call to os.symlink will return almost immediately,
-                # but for some reason, it may not be fully flushed to
-                # the file system. One way to fix this is to start
-                # the process again. This call to os.execl restarts the
-                # program with the same arguments, replacing the original
-                # operating system process.
-                os.execl(sys.executable, sys.executable, *sys.argv)
-            except OSError:
-                raise RuntimeError("Unable to automatically create symlink to system Python GTK+ bindings.")
-        else:
-            raise RuntimeError("Unable to locate the Python GTK+ bindings. Have you run '%s'?" % installer_command)
+if sys.version_info[:3] < (3, 4):
+    raise SystemExit("Toga requires Python 3.4+.")
+
+import gi
 
 gi.require_version('Gtk', '3.0')
 from gi.repository import Gtk, Gio, GLib


Test patch: