Search code examples
pythontkinterpython-2.xpyinstaller

Why does Python 3's tkinter importing syntax work in Python 2, but not with pyinstaller?


TL; DR: the first part of the title is answered simply below in the accepted answer (my own). The second part, regarding pyinstaller, was never answered.

I don't recommend wasting your time reading the rest of this question and the many comments.


I am running Python 2.7 via Anaconda and do not have Python 3 installed as far as I know. I'm confused about importing tkinter. Several other questions here on Stack Overflow indicate that there are separate modules and slightly different importing syntax for tkinter depending on whether you are running Python 2 or Python 3. However, the Python 3 syntax sort of works for me in Python 2 (see comments in code below). What gives?

import sys
print sys.version
# prints: 2.7.12 |Continuum Analytics, Inc.| (default, Jun 29 2016, 11:07:13) [MSC v.1500 64 bit (AMD64)]

# I hear these should not work in Python 2.  
# In reality, they work fine if run normally via the Python 2 interpreter.
# However, they do NOT work when I use pyinstaller to make an executable.
from tkinter import *
from tkinter import ttk, messagebox

# These work fine in Python 2, as they should, even if compiled into an exe.
from Tkinter import *
import ttk
import tkMessageBox

Edits:

In response to Bryan Oakley's comment, the result of print sys.path is:

['C:\\Users\\...\\tkinter test program', 
'C:\\Miniconda\\python27.zip', 
'C:\\Miniconda\\DLLs', 
'C:\\Miniconda\\lib', 
'C:\\Miniconda\\lib\\plat-win', 
'C:\\Miniconda\\lib\\lib-tk', 
'C:\\Miniconda', 
'C:\\Miniconda\\lib\\site-packages', 
'C:\\Miniconda\\lib\\site-packages\\win32', 
'C:\\Miniconda\\lib\\site-packages\\win32\\lib', 
'C:\\Miniconda\\lib\\site-packages\\Pythonwin', 
'C:\\Miniconda\\lib\\site-packages\\setuptools-23.0.0-py2.7.egg']

In response to Sun Bear's answer, here's what happens on my computer:

C:\>python
Python 2.7.12 |Continuum Analytics, Inc.| (default, Jun 29 2016, 11:07:13) [MSC
v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
Anaconda is brought to you by Continuum Analytics.
Please check out: http://continuum.io/thanks and https://anaconda.org
>>> import tkinter
>>>

In response to Łukasz Rogalski's comment:

>>> import Tkinter
>>> print Tkinter.__file__
C:\Miniconda\lib\lib-tk\Tkinter.pyc
>>> import tkinter
>>> print tkinter.__file__
C:\Miniconda\lib\site-packages\tkinter\__init__.pyc
>>>

In response to the discussion in the comments of Sun Bear's answer, this is the contents of C:\Miniconda\lib\site-packages\tkinter\__init__.pyc, which explains why import tkinter works even though I'm using Python 2:

from __future__ import absolute_import
import sys

if sys.version_info[0] < 3:
    from Tkinter import *
else:
    raise ImportError('This package should not be accessible on Python 3. '
                      'Either you are trying to run from the python-future src folder '
                      'or your installation of python-future is corrupted.')

Solution

  • Issue 1: Why can a Python 2 interpreter execute this Python 3 code?

    from tkinter import *
    from tkinter import ttk, messagebox
    

    Answer: (consolidated from my question updates and mine/others' comments) What makes it work is the module python-future. Installing that module creates various "wrapper" files that do nothing but redirect Python 3 elements to their Python 2 counterparts: tkinter -> Tkinter, tkinter.ttk -> ttk, tkinter.messagebox -> tkMessageBox, etc. That's one of the key purposes of the python-future module.

    For example, here's C:\Miniconda\lib\site-packages\tkinter\__init__.pyc:

    from __future__ import absolute_import
    import sys
    
    if sys.version_info[0] < 3:
        from Tkinter import *
    else:
        raise ImportError('This package should not be accessible on Python 3. '
                          'Either you are trying to run from the python-future src folder '
                          'or your installation of python-future is corrupted.')
    

    Issue 2: Why does that same trick seem to be incompatible with the module pyinstaller?

    Answer: I don't know. No one here has discussed it, and I don't care to revisit it 6 years later myself.