As I wrote in a previous installment of my links of the week, I discovered a really nice replacement for py2exe. However, pyinstaller doesn’t seem to play nice with PyQt…
The documentation and mailing lists suggest adding hooks for “hidden imports” in the pyinstaller/hooks
directory. I’ve been having problems with this for quite some time:
Traceback (most recent call last): File "", line 47, in NameError: name 'QtGui' is not defined
Whenever I attempt to run an executable built from my Qt application. I’ve tried creating a hooks-PyQt4.QtGui.py
, hooks-PyQt4.QtGui.py
, and a number of permutations thereof without much luck. So, I decided to go back to trying out py2exe only to discover that the problem I was having with it was due to a really stupid mistake on my part.
As it turns out, you cannot simply create a setup.py
setup script anywhere you like, even during testing. Here’s my application layout (roughly):
Chatly/ chatly/ client/ ui/ __init__.py qtui.py ui.py __init__.py client.py server/ __init__.py
I had placed my setup.py
under Chatly/chatly/client
temporarily in the hopes it’d save some typing when indicating the script path during the build process. ‘Course, if I had been thinking clearly about previous .eggs I’ve built, I should have known this wouldn’t work. Nevertheless, I tried it and ran into this:
D:\python25\lib\distutils\dist.py:263: UserWarning: Unknown distribution option: 'console' warnings.warn(msg) usage: setup.py [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...] or: setup.py --help [cmd1 cmd2 ...] or: setup.py --help-commands or: setup.py cmd --help error: invalid command 'py2exe'
(Yeah, this is from Windows. Since I’m building a Windows app in Python, it’s a necessity. Cygwin doesn’t work for this in particular, unfortunately. I hate the command prompt–it’s too anemic and lacks the utility of a proper shell.)
Since I’ve always created Python applications in distributable packages (like eggs) the right way, I’ve never experienced this particular error. When I was searching Google for clues, I expected some obvious answer. There weren’t any. Some people discovered they had py2exe installed twice (how?) and others were simply not using the correct arguments passed to setup()
. Since my setup.py
looked like this:
1 2 3 | from setuptools import setup import py2exe setup(windows=["chatly/client/ui/qtui.py"]) |
I was pretty sure that wasn’t a problem. I did read the py2exe documentation, after all.
Then I tried something. I figured that if, perhaps, py2exe were causing a problem, I could simply uninstall it, run the setup.py
as it existed, and it’d generate an ImportError
, right?
Nope. Same error.
That was when I began to realize it was some rather stupid mistake on my part with the choice of positioning for setup.py
. When I moved it to the project root outside any package where it’s supposed to live, it worked fine. Oops.
The problem with building a PyQt application still troubled me, though. The documentation for py2exe is fairly extensive (thankfully), and after some digging around, I discovered that the missing QtGui
import–rather, the one that wasn’t working–could be resolved similarly to the _qt
issue mentioned in py2exe’s documentation. The result was a setup.py
that looks like this:
1 2 3 4 | from setuptools import setup import py2exe setup(windows=["chatly/client/ui/qtui.py"], options={"py2exe": { "includes": ["sip", "PyQt4.QtGui"]}}) |
PyQt4.QtGui
is required to import the Qt GUI classes since they’re evidently not imported by py2exe’s internals during build. sip
is also required (it’s a part of the PyQt build process) and without it, nothing will work.
The finished product is a distributable package that works rather nicely–on Windows.