GNOME Bugzilla – Bug 70178
Gtk+-2.0 bindings conflict with 1.2
Last modified: 2004-12-22 21:47:04 UTC
As Gtk+-2.0 is a major API change, the developers allow both Gtk+-1.2 and Gtk+-2.0 to co-exist peacefully on the same machine. Good. However, gnome-python (which introduces even more radical API changes) uses the same module name ('gtk') for both. This means that installing any 2.0 python program will stop all existing 1.2 applications from working! The module should be named 'gtk2'. That way, a program can just do, 'from gtk2 import gtk, gdk' if it wants the new bindings and old programs will continue working. Thanks -- looking forward to migrating my apps to 2.0 :-)
Your arguments w.r.t. the gtk libraries are not very meaningful. In a single process, the two gtk versions are mutually exclusive (things die if you link to both of them, as many gdkxft users found out). The same is true with python. Even if the library was renamed, it would still be an error to do "import gtk, gtk2" (or import two modules which used different versions of pygtk). It would also require big changes to pygtk programs (I know there is already a lot of changes in pygtk, but these are not expected to be as big in the future -- much cruft is gone). If you want to have both versions on your system, the recommended method is to install to different directories, and set PYTHONPATH appropriately before running apps. Marking resolved as WONTFIX.
Using both versions within a single process isn't what I meant at all! I mean, I want to be able to install both the 1.2 bindings and the 2.0 bindings on the same system and be able to use both old and new programs together, in the way that I can with C programs. Setting PYTHONPATH is a totally unacceptable solution! ("OK mum, if you want to run these programs here, set the PYTHONPATH environment variable to this directory, but if you want to run these other ones, set it *there* instead. What do you mean "What's an environment variable?" No, you can't just click on the program you want!").
marking resolved WONTFIX. If setting PYTHONPATH manually is too difficult, I recommend using a shell script wrapper, which sets PYTHONPATH and exec's python.
Sets PYTHONPATH to what exactly? How do I know where the user has installed the old version? Could you give an example of a shell script that hacks into every computer in the world with the 1.2 bindings installed and modifies every python program using it so it won't break when 2.0 is installed? Or, do I have to do the shell script hack only for new programs that use 2.0? In that case, it would be easier just to rename the module. 1.2 and 2.0 are totally different. They link against different libraries. They have completely different APIs. They cannot use the same module name! For example, why don't you just call the module 'curses'. After all, no program will want to use both gtk and curses at the same time! Of course, installing it would break every existing curses application, but hey, there are probably less curses python programs than gtk ones, so less will break! Is there any reason at all NOT to make this change? I can't see why you're so reluctant to fix this...
Renaming all the modules is not an option. If you can think of a solution that does not involve this, I look forward to seeing it.
Could everything be moved one level down into a new module? Eg, from gtk2 import gtk w = gtk.Window() ... That way, the gtk modules themselves can continue to refer to 'gtk', 'gdk', etc. Another approach would be to get gtk2 to do the module path tricks (since it knows where it's installed): import gtk2 gtk2.fix_up_path() import gtk w = gtk.Window() Seems ugly, though. (of course, fix_up_path could be done within gtk2's init...) Yet another way is to define a symbol in __main__, eg: use_gtk2 = 1 import gtk What's the problem with renaming the gtk module, though? (gdk, etc can keep the same names as they're inside the other one).
How about making 'gtk2' an alias for 'gtk'? Then at least programs written for a (hypothetical) version of the package which doesn't break existing apps will still work with the main trunk version? [ Note: unassigning myself from this bug as I don't have CVS access and thus can't fix it ]
Started a gtk.compat module to help with porting apps over. Still needs a fair bit of work though.
Well, OK. As long as existing software will run without modification. Actually porting apps isn't much of a problem for me (in fact, I'm looking forward to it ;-). It's the stuff that's already installed and which, therefore, I have no control over which was my worry. Still don't understand the problem with using 'import gtk2 as gtk', though (or even, 'import gtk2 as g' if you want to recoup the extra typing at the start ;-).
Created attachment 9425 [details] [review] Possible patch
The above patch is the one I'm currently using to allow me to install both versions at once. Seems to be working OK so far. I've only included the patch for one of the example files since the changes are easy to do with a simple script. The other possibility is to move everything down one level (eg, import gtk.gtk.gdk rather than import gtk2.gdk) which might make for less changes in the source code. Also, it means a small bit of code can update sys.path and then 'import gtk.gdk' works as before. I'm going to put this code in ROX-Lib, so hopefully it can detect whether the ROX version of pygtk is installed or the GNOME version, and adjust sys.path to work correctly for either case...
For the final solution, I would like to have a system where only one version of pygtk is reachable in the Python path at one time. My current idea is to spin new releases of stable and devel pygtk that install into a subdir -- $(pythondir)/gtk-1.2 and $(pythondir)/gtk-2.0 respectively (where pythondir is the site-packages directory of the python installation). Each version would also install pygtk.pth pointing at their respective directory. This would make parallel installation a lot easier, and distributors could decide which version would be the default version. A new module (identical for both stable and devel versions, and not likely to change ever) could be added that allowed an app to request a particular version. It's use would look like this: try: import pygtk pygtk.require("2.0") except ImportError: pass (or something similar). The require() function would search for a gtk-2.0 directory under all the paths in sys.path, and prepend the gtk-2.0 dir to the path if found, and raise an exception otherwise. It would also raise an exception if the requested version did not exist. Maybe also raise an exception on a second call to require() if it requests a different version. This solution is similar to the __future__ system in recent Python's, and the Perl "require 5.6.1;" meta-statements. I don't want to have to handle cases where people accidentally load two versions of pygtk in the same process. It also provides a good way to handle this sort of issue going forward. What do you think of this? Matt: how does this sound from a packager's perspective?
Providing the same file in multiple packages sounds problematic. How about this to stop people importing both: >>> import gtk2 >>> sys.modules['gtk'] = gtk2 # do this in gtk2.__init__.py >>> import gtk >>> gtk.Window Or, in gtk2.__init.py: >>> import gtk2.dummy >>> sys.modules['gtk'] = gtk2.dummy Then: >>> import gtk2 >>> import gtk >>> dir(gtk) [] I intend to do something like this in my version, if noone can see any problems...
I know that RPM allows multiple packages to contain a file provided that the file is identical (as they would be in this case). Alternatively, the packager could only include the version from the newer pygtk and make the 1.2 version depend on the newer one (or vice versa ...). If it was just a single module this might be workable. However, we have a collection of modules. I would prefer a solution where I can keep the entire set of modules mutually exclusive, to reduce the likelyhood of a conflict. It would also make it easier for addon packages (such as gnome-python) to install in such a way that their code won't be used with the wrong pygtk version).
After a little discussion and prototyping with Johan, we came up with this system: http://www.daa.com.au/~james/files/pygtk-version-jh.tar.gz Here is a small summary: 1. each major version of pygtk (1.2, 2.0, etc) installs under: $(prefix)/lib/python?.?/site-packages/gtk-x.y 2. each version of pygtk installs a file called pygtk.pth into: $(prefix)/lib/python?.?/site-packages containing a single line: gtk-x.y 3. each version of pygtk installs the file pygtk.py into $(prefix)/lib/python?.?/site-packages This file is identical for all pygtk versions. Addon packages install into the appropriate gtk-x.y directory. Results are: a. Files for individual pygtk "platforms" are kept separate, and prevented from being imported together. b. sysadmins and/or distributors can decide which version of pygtk is the default by adjusting pygtk.pth c. Programs can request a particular major version of pygtk with: import pygtk ; pygtk.require('x.y') If they want a particular version, this can be followed with an assert: import pygtk ; pygtk.require('2.0') import gtk assert gtk.pygtk_version >= (1,99,12), 'pygtk version too old'
Created attachment 10509 [details] patch for pygtk 2.0 head
Created attachment 10510 [details] [review] patch for pygtk 0.6.x head
Checked in the parallel install patch on both branches. The next releases of each branch should parallel install with each other without problem.
There is a slight problem if, eg, pygtk is installed in /usr and gnome-python in /usr/local... only one of the directories gets added to the path... Eg, if Debian has installed the python-gtk2 package then installing gnome-python2 from source breaks it (also, make uninstall doesn't remove the directory, so it stays broken!). Thanks,
mass reassign of open pygtk and gnome-python bugs.
Consider this closed, Thomas, open up a new bug for the different prefix bug (found in debian) if needed.