How to create an exe file for Python code with PyInstaller

by Alex
How to create an exe file for Python code with PyInstaller

Installing PyInstaller

Installing PyInstaller is no different than installing any other Python library.

pip install PyInstaller

This is how you can check the version of PyInstaller.

pyinstaller --version

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:

  1. Reads the script file.
  2. Analyzes the code to identify any dependencies needed to work.
  3. 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.
  4. Collects copies of all libraries and files along with the active Python interpreter.
  5. Creates a BUILD folder in the script folder and writes logs along with the working files to BUILD.
  6. Creates a DIST folder in the script folder if it does not already exist.
  7. Writes all necessary files along with the script either to one folder or to one executable file.

If you use the onedir or -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 onefile or -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. папки, BUILD и DIST, а также файл .spec 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[0])
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

The --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[0])
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. Добавление файлов с данными и параметр onefile

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

File spec

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.

Hooks

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.

pyinstaller simpleModel.spec

Copy the executable file to the desktop and see that it now displays the TensorFlow version correctly.

Conclusion:

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 --add-data parameter.
  • The executable and dependent data with libraries can be bundled into a single file or folder using --onefile or --onedir, respectively.
  • Dynamic imports and second-level libraries can be enabled with hidden-imports.
  • The spec file allows you to create an executable to handle hidden-imports and other data files with hooks.

Related Posts

LEAVE A COMMENT