Python and PyInstaller — Introduction and Troubleshooting

  • Distributing your workflow to non-technical users
  • Obfuscating your code

Introduction to PyInstaller

In this tutorial we will look at compiling Python code using PyInstaller. PyInstaller is a specially designed compiler for Python code that can compile for Windows, MacOS, and Linux systems. This tutorial will be done using the Windows operating system. There are some small differences when compiling which unfortunately I cannot cover because I do not own a MacOS system. We will look at how to troubleshoot problems that are often encountered when compiling and how to troubleshoot them. I will also go over a few basic steps and considerations if you are considering compiling your Python code.

pip install pyinstaller
pyinstaller [python_file]
pyinstaller [python_file] --onefile

PyInstaller Spec File

For more advanced users there is the spec file. This file is created when you run the PyInstaller command on a Python script. It essentially tells the compiler how to compile your script and where to look for relevant data. You can also make a spec file before compiling so you can compile the parameters beforehand. You can create just a spec file using this command which will generate a spec file in the current working directory of the command prompt:

pyi-makespec [python_file]
  • Line 5: The filename of the Python script being compiled
  • Line 6: The directory of the Python script being compiled
  • Line 7–8: Additional binary and non-binary files. Binary files are often .dll files. You can try manually linking as mentioned above or link them here. Additional non-binary files can include pictures, database files, or others. If you get errors about missing files you should include them here.
  • Line 9: Additional imports that may be required by the compiler. Compiled software will require additional library imports compared to a non-compiled script (I will go over this later below). You should put the additional libraries here. The input is a list with each item in the list containing the name of the library as a string. For example: [‘numpy’, ‘rasterio’, ‘fiona’]
  • Line 10–11: If a library requires specific environmental variables they can be called upon here using a runtime hook. These are small scripts that manipulate the environment before your main script runs, effectively providing additional top-level code to your script. I often use them to manipulate the environment parameters using something like: os.environ[‘PARAM_NAME’] . There is more info later in this tutorial regarding this section.
pyinstaller your-spec-file.spec

Planning and Testing for PyInstaller

If you are even thinking about compiling Python code you have to plan it and test the Python libraries that are going to be compiled. Python and its libraries are not designed to be compiled so there will often be problems when you try to compile libraries. There may be cases that a compiled program may need additional imports compared to your original Python code. There may be cases that libraries may just completely fail to compile for some unknown reason. Sometimes libraries like pandas will need unique solutions.

General test workflow

Troubleshooting the ModuleNotFoundError

In this section I will focus on the ModuleNotFoundError error — a common issue I encounter when compiling. In this case, the compiled program needs additional imports for it to work. This is a rather easy problem to fix but can be tedious because you have to re-compile your program every time you troubleshoot.

cd "your/project/folder/here"
pyinstaller import_tests.py
Output of PyInstaller while it is compiling our script
New files and folders in the project folder after compilation
cd "your/dist/folder"
import_tests.exe
ModuleNotFoundError when importing Rasterio. Traceback reveals rasterio._shim is missing
pyinstaller import_tests.py
The missing import is highlighted in red
New line of code seen in line 3

Setting Environment Parameters with Runtime Hooks

As seen in the section above. The import errors were fixed but there is now an error related to missing files. The library is looking for the files but PyInstaller did not configure this, it has to be set manually. This has to be done in a separate file. If you change the environment within your main Python script PyInstaller will ignore it.

Final Thoughts

Hopefully this clears up things on PyInstaller and what you should look out for when compiling Python code. I have gotten suggestions on other compilers but those can be for another time.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Panji Brotoisworo

Panji Brotoisworo

Researcher working on geospatial sciences and general programming