Installing PyInstaller is no different than installing any other Python library.
pip install PyInstaller
This is how you can check the version of PyInstaller.
I am using PyInstaller version 4.2.
Creating an exe file with PyInstaller
The PyInstaller builds the Python application and all the libraries it needs into one package as follows:
- Reads the script file.
- Analyzes the code to identify any dependencies needed to work.
- Creates a spec file that contains the script name, dependency libraries, and any files, including those parameters that have been passed to the PyInstaller command.
- Collects copies of all libraries and files along with the active Python interpreter.
- Creates a BUILD folder in the script folder and writes logs along with the working files to BUILD.
- Creates a DIST folder in the script folder if it does not already exist.
- Writes all necessary files along with the script either to one folder or to one executable file.
If you use the
-D command parameter when generating the executable, then everything will be placed in the same folder. This is the default behavior. If you use the
-F parameter, however, everything will end up in the same executable file. Let’s take as an example a simple Python script called simple.py that contains this code.
import time name = input("type your name ") print("your name ", name) time.sleep(5)
Create one executable file. On the command line type:
pyinstaller --onefile simple.py
When the installation is complete, there will be two folders, BUILD and DIST, and a new file with a .spec extension. The spec file will have the same name as the script file. Python creates a distribution directory that contains the main executable as well as all the dynamic libraries. This is what happens after you run the file.
Adding data files to be used by the exe file
There is a CSV file netflix_titles.csv, and a Python-script that reads the number of entries in it. Now we need to add this file to the bundle with the executable file. Let’s call the Python-script file simply simple1.py.
import time # pip install pandas import pandas as pd def count_records(): data = pd.read_csv('netflix_titles.csv') print("Total movies:", data.shape) if __name__ == "__main__": count_records() time.sleep(5)
Let’s create an executable file with the data in the folder.
pyinstaller --add-data "netflix_titles.csv;." simple1.py
--add-data parameter allows you to add data files that you want to keep in the same bundle as the executable file. This parameter can be applied many times. The syntax of add-data:
- add-data – Windows.
- add-data – Linux.
You can see that the file is now added to the DIST folder along with the executable. Also by opening the spec file you can see the datas section which indicates that the netflix_titles.csv file is being copied to the current directory.
... a = Analysis(['simple1.py'], pathex=['E:\\myProject\\\pyinstaller-tutorial'], binaries=, datas=[('netflix_titles.csv', '.')], ...
Run the simple1.exe file, a console will appear with the following output:
Total movies: 7787.
Adding Data Files and the onefile option
If the parameter
--onefile is given, the PyInstaller unpack all the files in the TEMP folder, execute the script and delete TEMP. If you specify onefile along with add-data, it reads the data from the folder. The folder path changes and looks like “_MEIxxxxxxx-folder”.
import time import sys import os # pip install pandas import pandas as pd def count_records(): os.chdir(sys._MEIPASS) data = pd.read_csv('netflix_titles.csv') print("Total movies:", data.shape) if __name__ == "__main__": count_records() time.sleep(5)
The script is updated to read the TEMP folder and the data files. Let’s create an exe file with onefile and add-data.
pyinstaller --onefile --add-data "netflix_titles.csv;." simple1.py
After successful creation the simple1.exe file will appear in the DIST folder. You can copy the executable file to the desktop and run it to make sure that there is no error related to the missing file.
Additional Imports with Hidden Imports
The executable requires all the imports that the Python script needs. Sometimes PyInstaller may skip dynamic or second-level imports, returning an
ImportError: No module named.. To solve this error, pass the name of the missing library to hidden-import. For example, to add os library, write like this:
pyinstaller --onefile --add-data "netflix_titles.csv;." - hidden-import "os" simple1.py
The spec file is the first file that PyInstaller creates to encode the contents of the Python script along with the parameters passed at startup. PyInstaller reads the contents of the file to create the executable, defining everything it might need for it. A file with a .spec extension is saved by default in the current directory. If you have any of the following requirements, you can change the spec file:
- Build into one bundle with executable data files.
- Include other executable files: .dll or .so.
- Use libraries to build several programs into one bundle.
For example, there is a simpleModel.py script that uses TensorFlow and outputs the version number of that library.
import time import tensorflow as tf def view_model(): print(tf.__version__) if __name__ == "__main__" : model = view_model() time.sleep(5)
We compile the model with PyInstaller:
pyinstaller -F simpleModel.py
After a successful compilation, run the executable, which returns the following error.
... File "site-packages\tensorflow_core\python_init_.py", line 49, in ImportError: cannot import name 'pywrap_tensorflow' from 'tensorflow_core.python'
Let’s fix it by updating the spec file. One solution is to create a spec file.
$ pyi-makespec simpleModel.py -F wrote E:\pyinstaller-tutorial\simpleModel.spec now run pyinstaller.py to build the executable
The pyi-makespec command creates a default spec file containing all the parameters you can specify on the command line. The simpleModel.spec file is created in the current directory. Since the
--onefile parameter was used, there will only be an exe section inside the file.
... exe = EXE(pyz, a.scripts, a.binaries, a.zipfiles, a.datas, , name='simpleModel', debug=False, bootloader_ignore_signals=False, strip=False, upx=True, upx_exclude=, runtime_tmpdir=None, console=True )
If the default or onedir parameter is used, there will also be a collect partition along with the exe partition. You can open simpleModel.spec and add the following text to create the hooks
# -*- mode: python ; coding: utf-8 -*- block_cipher = None import os spec_root = os.path.realpath(SPECPATH) options =  from PyInstaller.utils.hooks import collect_submodules, collect_data_files tf_hidden_imports = collect_submodules('tensorflow_core') tf_datas = collect_data_files('tensorflow_core', subdir=None, include_py_files=True) a = Analysis(['simpleModel.py'], pathex=['E:\\myProject\\\pyinstaller-tutorial'], binaries=, datas=tf_datas + , hiddenimports=tf_hidden_imports + , hookspath=, ...
We create hooks and add them to the hidden imports and data section.
Hook files extend PyInstaller’s ability to handle requirements such as the need to include additional data or import dynamic libraries. Normally, Python packages use normal methods to import their dependencies, but in some cases, like TensorFlow, there is a need to import dynamic libraries. PyInstaller may not find all the libraries, or there may be too many. In such a case, it is recommended to use the import helper tool from
PyInstaller.utils.hooks and collect all the submodules for the library. Let’s compile the model after updating the simpleModel.spec file.
Copy the executable file to the desktop and see that it now displays the TensorFlow version correctly.
PyInstaller offers several options for creating simple and complex executables from Python scripts:
- The executable can build all the required data into a single bundle using the
- The executable and dependent data with libraries can be bundled into a single file or folder using
- Dynamic imports and second-level libraries can be enabled with
- The spec file allows you to create an executable to handle hidden-imports and other data files with hooks.