Tkinter calls fail in fresh VirtualEnv

Bug #449537 reported by Shawn Wheatley
12
This bug affects 2 people
Affects Status Importance Assigned to Milestone
Virtualenv
New
Undecided
Unassigned

Bug Description

Environment:
Tested on Windows XP SP3 and Windows 7
Python 2.6.3
Virtualenv 1.3.4

Within a fresh, just activated VirtualEnv, I get the following error trying to run a simple Tkinter window:

H:\My Documents\pythondev>virtualenv H:\testvirtualenv
New python executable in H:\testvirtualenv\Scripts\python.exe
Installing setuptools...................done.

H:\My Documents\pythondev>H:\testvirtualenv\Scripts\activate.bat
(testvirtualenv) H:\My Documents\pythondev>python
Python 2.6.3 (r263rc1:75186, Oct 2 2009, 20:40:30) [MSC v.1500 32 bit (Intel)]
on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import Tkinter
>>> Tkinter._test()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python26\Lib\lib-tk\Tkinter.py", line 3749, in _test
    root = Tk()
  File "C:\Python26\Lib\lib-tk\Tkinter.py", line 1643, in __init__
    self.tk = _tkinter.create(screenName, baseName, className, interactive, want
objects, useTk, sync, use)
_tkinter.TclError: Can't find a usable init.tcl in the following directories:
    C:/Python26/lib/tcl8.5 H:/testvirtualenv/lib/tcl8.5 H:/lib/tcl8.5 H:/testvir
tualenv/library H:/library H:/tcl8.5.2/library H:/tcl8.5.2/library

This probably means that Tcl wasn't installed properly.

>>>

Revision history for this message
Shawn Wheatley (swheatley) wrote :

Virtualenv does not copy the Tcl library file(s) (or any core C extensions, that I can see) to the new virtualenv, but instead adds a reference to the PYTHONPATH. If I copy the "tcl" folder from C:\Python26\ over to the root of the new Virtualenv, Tkinter.Tk() shows a new window without throwing an exception.

Revision history for this message
Jannis Leidel (jezdez) wrote :

Just suspecting here but could you create a virtualenv on the same drive as the system Python (C:)? I have the feeling it could be related to https://bugs.launchpad.net/virtualenv/+bug/352844.

Revision history for this message
Shawn Wheatley (swheatley) wrote :

Same problem when creating an environment on C:

C:\Temp>virtualenv TestTkinterBug
New python executable in TestTkinterBug\Scripts\python.exe
Installing setuptools...................done.

C:\Temp>cd TestTkinterBug

C:\Temp\TestTkinterBug>Scripts\activate.bat
(TestTkinterBug) C:\Temp\TestTkinterBug>python
Python 2.6.3 (r263rc1:75186, Oct 2 2009, 20:40:30) [MSC v.1500 32 bit (Intel)]
on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import Tkinter
>>> Tkinter._test()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python26\Lib\lib-tk\Tkinter.py", line 3749, in _test
    root = Tk()
  File "C:\Python26\Lib\lib-tk\Tkinter.py", line 1643, in __init__
    self.tk = _tkinter.create(screenName, baseName, className, interactive, want
objects, useTk, sync, use)
_tkinter.TclError: Can't find a usable init.tcl in the following directories:
    C:/Python26/lib/tcl8.5 C:/Temp/TestTkinterBug/lib/tcl8.5 C:/Temp/lib/tcl8.5
C:/Temp/TestTkinterBug/library C:/Temp/library C:/Temp/tcl8.5.2/library C:/tcl8.
5.2/library

This probably means that Tcl wasn't installed properly.

>>>

Revision history for this message
Shawn Wheatley (swheatley) wrote :

I've figured out the problem, but wondering if someone could give me a suggestion on a "proper" solution. I dug into the Python source and found that importing Tkinter on win32 causes an import of a module called FixTk:

http://svn.python.org/view/python/tags/r263/Lib/lib-tk/FixTk.py?revision=75184&view=markup

This file checks to see if the folder "tcl" exists in sys.prefix ("C:\python26\tcl"), or if the folder tcltk\lib exists in the parent of sys.prefix ("C:\tcltk\lib"). Once it finds an appropriate folder, it drills in to find the actual Tcl library folder, and sets appropriate environment variables (TCL_LIBRARY, TK_LIBRARY, TIX_LIBRARY). Since virtualenv doesn't copy the first folder to the new location, and the second folder doesn't exist (at least on my system), the rest of the module exits without completion--without setting any environment variables. You can see an example of this in a virtualenv on win32 by doing the following:

>>> import os
>>> os.environ.keys().index('TCL_LIBRARY')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: list.index(x): x not in list
>>> import Tkinter
>>> os.environ.keys().index('TCL_LIBRARY')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: list.index(x): x not in list

Compare this with stock Python on win32:

>>> import os
>>> os.environ.keys().index('TCL_LIBRARY')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: list.index(x): x not in list
>>> import Tkinter
>>> os.environ.keys().index('TCL_LIBRARY')
26

I see a few ways to solve this problem, some more elegant than others:

1) virtualenv copies the "tcl" folder on win32 to the target folder

Pros: the least impact on both virtualenv and the environment variables; this will continue to allow Tkinter to function as expected in the system Python.
Cons: feels kind of hacky compared to how virtualenv references the rest of the standard library

2) virtualenv performs the functions of FixTk.py and sets the appropriate environment variables in activate.bat

Pros: this change is isolated to a Windows-only file (the batch file) and should also cause minimal "damage" in the case where the *_LIBRARY variables are already set (unless changing these in a batch file affects them system wide, I don't remember how exactly that works)
Cons: depending on how variables are set, this may destroy any system-wide *_LIBRARY variables associated with Tcl.

3) something similar to VirtualEnvWrapper, set a post deploy hook that sets the appropriate variables

Pros: no patch to virtualenv (yay!)
Cons: Tkinter support on win32 under virtualenv is still broken, this is a workaround that would need to be applied separately on every fresh install (although I'm sure avid virtualenv users already have some bootstrap scripts they use in this fashion anyway)

I seem to be the only Tkinter/virtualenv user on Windows :) so I'd be happy to work on a patch, but I'd like some suggestions as to the approach.

Revision history for this message
Ian Bicking (ianb) wrote : Re: [Bug 449537] Re: Tkinter calls fail in fresh VirtualEnv

On Thu, Oct 15, 2009 at 3:30 PM, Shawn Wheatley <email address hidden> wrote:
> 2) virtualenv performs the functions of FixTk.py and sets the
> appropriate environment variables in activate.bat
>
> Pros: this change is isolated to a Windows-only file (the batch file) and should also cause minimal "damage" in the case where the *_LIBRARY variables are already set (unless changing these in a batch file affects them system wide, I don't remember how exactly that works)
> Cons: depending on how variables are set, this may destroy any system-wide *_LIBRARY variables associated with Tcl.

This seems reasonable to me. I'm not clear if the same problem exists
on other platforms? It doesn't seem to for me.

After thinking a bit, I think the best option to implement this would
be to put the FixTk code into the virtualenv site.py. Then activation
won't be required to get Tkinter to work. The FixTk code would be
modified to use sys.real_prefix in addition to sys.prefix.

--
Ian Bicking | http://blog.ianbicking.org | http://topplabs.org/civichacker

To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.