Hello World!

Distributing Python Programs, Part 1: The Easy Stuff

Hello World! Computer Programming for Kids and Other Beginners is about learning to code.  One of the first things you need to do is install Python, so you can run your code.  But what if you want to share your program with someone who doesn’t have Python installed?

In some programming languages, this is pretty easy.  Languages like C and C++ are compiled, which means the code is transformed into runnable or executable code.  You can then share the executable and anyone can run it on their machine.

But Python is an interpreted language.   There’s no compiler – instead, the Python interpreter executes the code. That means there’s no executable version of your program you can share.  (Well, technically there is a compiler, but it compiles to Python bytecode, not to something that you can run directly.) To run a Python program, you need to have the Python interpreter on the computer.  But that doesn’t mean you can’t share your Python programs.  It’s just a little trickier.

Basically, to share a Python program so it can be run on a computer that doesn’t have Python installed, you need to bundle it up with a copy of the Python interpreter.  There are some tools that help you to do that, and make sure that the program you’re trying to share knows how to use the bundled version of the interpreter.  One of them is called PyInstaller.  It can bundle up your Python program with the interpreter and any other “dependencies” (that means things your program needs to run), so that it acts like a standalone program.  PyInstaller claims to work on Windows, Mac and Linux, but I’ve only tried it on Windows, so that’s what the rest of this article will talk about – making a shareable Python program on Windows.

The first thing you need to do is install PyInstaller.  Rather than repeat the instructions, I’ll point you to the PyInstaller home page:  http://pythonhosted.org/PyInstaller/#installing-pyinstaller   I recommend using pip (the Python package installer).

Let’s start with the simplest case: a text-only program that doesn’t use libraries like Pygame or PyQt.  We’ll make a shareable version of the NumberGuess game from Chapter 1.  PyInstaller is controlled from a console (Command Prompt in Windows) – it doesn’t have a GUI.  (If you haven’t already, you should get familiar with the basic commands for navigating around your folders in the Command Prompt.)

The first thing you should do is put a copy of the NumberGuess code in a new folder.  Call it something like “NumGuessSharable”

E:\Warren\PythonScripts\NumGuessSharable>dir

 Directory of E:\Warren\PythonScripts\NumGuessSharable

07/04/2015  02:42 PM    <DIR>          .
07/04/2015  02:42 PM    <DIR>          ..
01/26/2013  04:37 PM             1,062 NumGuess.py
               1 File(s)          1,062 bytes
               2 Dir(s)  19,015,139,328 bytes free

Now we’re going to run the command to make PyInstaller create an executable that we can share.

If you read the PyInstaller documentation, you’ll see that it builds your shareable app as either a single folder or a single file.  We’ll try the single file option.

At the command prompt, first type the following:

pyinstaller --version

It should respond with something like “2.1”.  If it doesn’t. that means it’s not installed correctly, and you’ll have to look through the PyInstaller documentation and try and figure out why.

Once you know PyInstaller is installed, type the following:

pyinstaller --onefile NumGuess.py

PyInstaller will then start building the shareable version of NumGuess.  It will take a few minutes, and you will see something like this:

E:\Warren\PythonScripts\NumGuessSharable>pyinstaller --onefile NumGuess.py
32 INFO: wrote E:\Warren\PythonScripts\NumGuessSharable\NumGuess.spec
125 INFO: Testing for ability to set icons, version resources...
531 INFO: ... resource update available
1077 INFO: UPX is available.
1233 INFO: Processing hook hook-os
1436 INFO: Processing hook hook-time
1482 INFO: Processing hook hook-cPickle
1654 INFO: Processing hook hook-_sre
1825 INFO: Processing hook hook-cStringIO
1982 INFO: Processing hook hook-encodings
2028 INFO: Processing hook hook-codecs
4539 INFO: Extending PYTHONPATH with E:\Warren\PythonScripts\NumGuessSharable
4539 INFO: checking Analysis
4539 INFO: building Analysis because out00-Analysis.toc non existent
4555 INFO: running Analysis out00-Analysis.toc
4555 INFO: Adding Microsoft.VC90.CRT to dependent assemblies of final executable
...
53001 INFO: building PKG (CArchive) out00-PKG.pkg
57134 INFO: checking EXE
57134 INFO: rebuilding out00-EXE.toc because NumGuess.exe missing
57134 INFO: building EXE from out00-EXE.toc
57618 INFO: Executing - upx --lzma -q C:\Users\wsande\AppData\Roaming\pyinstaller\bincache01_py27\run.exe
58216 INFO: Appending archive to EXE E:\Warren\PythonScripts\NumGuessSharable\dist\NumGuess.exe

If you look in the new folder, NumGuessSharable, you should see a couple of new subfolders there, ‘build’ and ‘dist’. The ‘dist’ folder has our shareable, executable version of NumGuess, called ‘NumGuess.exe’   This is a file you can give to anyone and they can run it on their (Windows) computer, even if they don’t have Python.

You will also see in the NumGuessSharable folder, a new file called ‘NumGuess.spec’.  This ‘spec’ file is something that contains all the options and settings that PyInstaller used to create the executable.

If you run the NumGuess.exe program, you will notice that it opens its own command window in which to run.  When the program stops, the command window closes right away, which means the user doesn’t see the final message about winning or losing.  That’s something you can fix by modifying the code of NumGuess.  Give it a try!

Pyinstaller spec files

When we did the first example, we gave PyInstaller the name of the Python code and the ‘–onefile’ option.  The other way to run PyInstaller is to give it the name of a ‘spec’ file.  That file contains the name of the Python program, as well as the options we want and some other information.  It looks like this:

 # -*- mode: python -*-
a = Analysis(['NumGuess.py'],
             pathex=['E:\\Warren\\PythonScripts\\NumGuessSharable'],
             hiddenimports=[],
             hookspath=None,
             runtime_hooks=None)
pyz = PYZ(a.pure)
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          name='NumGuess.exe',
          debug=False,
          strip=None,
          upx=True,
          console=True)

This is the spec file that Pyinstaller created when we first ran it.  But we can modify it (if needed) and use it when we run Pyinstaller again to build the updated version of NumGuess:

pyinstaller NumGuess.spec

It runs the same as before, and creates the executable in the ‘dist’ folder.

We mentioned before that PyInstaller can make either single-file or single-folder shareable programs. Single-file is what we used here, and the ‘dist’ folder just contains a single .exe file you can share. A single-folder shareable has multiple files in the ‘dist’ folder, including the executable and a bunch of other files. If you want to share that, you have to share the whole folder.

When we first ran PyInstaller, we used the --onefile option to indicate we wanted a single-file shareable. But you might have noticed that the spec file doesn’t contain onefile anywhere.  That’s because the ‘--onefile’ option is encoded in the structure of the spec file.  Spec files for single-folder shareables have a section called coll, which doesn’t appear here. Spec files for single-file shareables don’t have a coll section.

You’ll see more of that in Part 2 when we discuss using PyInstaller to package up Pygame programs for distribution.