In this Pyinstaller Tutorial, we will discuss how to manage, modify, and use the Spec File to compile EXE’s.
Generating a single executable file that works flawlessly on every platform is not an easy task. That’s where the PyInstaller spec file comes into play. In this article, we’ll discuss what the PyInstaller spec file is and how it can be used to generate a standalone executable file.
What is a PyInstaller Spec File?
A PyInstaller spec file is a configuration file that is used by PyInstaller to package a Python script or application into a standalone executable file. This file specifies all the necessary details about the application, such as its name, version, icon, and any additional data files it requires. The spec file is written in Python and can be customized to suit the needs of the application.
Why Use a PyInstaller Spec File?
By default, PyInstaller creates a standalone executable file based on some default settings, which may not be suitable for every application. For instance, if the application requires additional data files, such as images, audio files, or configuration files, they need to be included in the executable file.
Instead of having to write all of these options out every single time you want to compile your EXE, just include them once inside your Spec File instead!
Here’s a little example which shows you how much pain you can avoid by using a spec file. Instead of writing out the same command below, over and over again, we will teach you how to create a spec file for it instead.
pyinstaller app.py --onefile --noconsole --add-data="C:/Users/CodersLegacy/image.jpg;" --icon="C:/Users/CodersLegacy/icon.ico"
Just incase you don’t know what the above commands are, let me give you a little run down.
- –onefile : This settings compiles the EXE as a single file, rather than a folder full of files
- –noconsole : Disables the default console window
- –add-data : Adds a data file, which will be included within the EXE
- –icon : Used to change the default icon on an EXE
Creating a PyInstaller Spec File
To create a PyInstaller spec file, we need to run PyInstaller with the --name
and --specpath
options, followed by the path to the Python script or application. For example, to create a spec file for a script called myscript.py
, we can run the following command:
pyinstaller --name myspecfile --specpath C:/Users/CodersLegacy app.py
This command creates a spec file named myspecfile.spec
in the C:/Users/CodersLegacy
directory, using the app.py
file in the C:/Users/CodersLegacy
directory.
We ran the above command, and it generated this spec file for us. Right now this spec file contains the default values. We need to make some adjustments to include our customizations, images, and other settings.
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(
['app.py'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
[],
exclude_binaries=True,
name='myspecfile',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)
coll = COLLECT(
exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='myspecfile',
)
Here’s a brief explanation of the structure of the PyInstaller spec file: (We will cover each and every option in detail later in this tutorial)
- The
block_cipher
variable is used to specify the encryption algorithm used for the binary files. - The
Analysis
class is used to specify the entry point of the application, the path of the source files, the data files to be included, the hidden imports, and the excluded modules. - The
PYZ
class is used to create the bundled archive file that contains the Python interpreter and the compressed code of the application. - The
EXE
class is used to create the executable file, specifying the bundled archive, the entry point script, the excluded binaries, the name of the executable, and other options such as debugging and stripping symbols. - The
COLLECT
class is used to collect all the necessary files and create the final distribution directory or archive, specifying the executable file, the binary files, the data files, and other options such as stripping and compression.
Modifying the Spec File
Now let’s modify our spec file to include the configurations from that pyinstaller command from earlier. Let’s copy-paste the command down here, for our convenience.
pyinstaller app.py --onefile --noconsole --add-data "C:/Users/CodersLegacy/image.jpg" --icon="C:/Users/CodersLegacy/icon.ico"
Allright, so let’s begin.
We will show you how we add each option in, one by one. First, let’s add the icon into the spec file. This can be done by using the “icon” option, at the end of the EXE Class in the spec file. We marked it using an arrow. (Don’t include the arrow in your code please)
exe = EXE(
pyz,
a.scripts,
[],
exclude_binaries=True,
name='myspecfile',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon="C:\\Users\\CodersLegacy\\icon.ico" <--
)
Next, we are going to add in the data-file (the image).
All of the datafiles are meant to go into the “datas
” option. We basically need to include a list of tuples inside this option. Each tuple represents one data-file, and consists of two values.
a = Analysis(
['app.py'],
pathex=[],
binaries=[],
datas=[('C:/Users/CodersLegacy/image.jpg', '.')], <---
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
In the case of the ('C:/Users/CodersLegacy/image.jpg', '.')
tuple, the source file is 'C:/Users/CodersLegacy/image.jpg'
, and the destination directory in the final executable is '.'
, which means the root directory of the final executable.
This means that the image file will be included in the root directory of the final executable, and can be accessed using a relative path (e.g. 'image.jpg'
). If you did ('C:/Users/CodersLegacy/image.jpg', './Images')
, you would have to access it within the program as 'Images/image.jpg'
.
To disable the console, come down to the EXE class, and change the “console” setting from “True” to “False”.
exe = EXE(
pyz,
a.scripts,
[],
exclude_binaries=True,
name='myspecfile',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=False, <----
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon="C:\\Users\\RaahimSiddiqi\\Desktop\\Code\\VSC\\Tutorials\\py_installer\\bulb.ico"
)
Spec File to Pyinstaller EXE
Now all you have to do is run the following command. You may have noticed that we still needed to include the –onefile option here. There are some options like this, which cannot be included inside a spec file unfortunately. Luckily, its pretty short and easy to remember.
pyinstaller --onefile myspecfile.spec
This will generate the EXE for you, with all the settings we applied in the spec file. You can run this short and simple command as many times as you like, without having to rewrite anything. Pretty cool, right?
Spec Files Options
We decided to make a proper list on all the options in the Analysis and EXE classes, where most of the customizations are. We have also included a brief description, and a one-line example to help you understand how to use it better.
Analysis
pathex
A list of paths to search for modules to include. This is an empty list by default, so it’s usually necessary to include at least the path to your main script.
pathex=['/path/to/my/app', '/path/to/other/module']
binaries
A list of (module_name, path) tuples specifying additional binary files to include. These files will be extracted to the same directory as the executable at runtime.
binaries=[('/path/to/file', '/path/to/destination'), ('/path/to/another', None)]
datas
A list of (source, destination) tuples specifying additional data files to include. The first element of each tuple is the path to the file, and the second element is the path where it should be placed in the distribution directory.
datas=[('/path/to/file', 'my_destination'), ('/path/to/another', None)]
hiddenimports
A list of additional modules to include, even if they are not directly imported by the script. This can be necessary if you are using dynamic imports or if PyInstaller is not able to automatically detect all dependencies.
hiddenimports=['my_module', 'my_other_module']
excludes
A list of modules to exclude from the distribution. This can be useful to reduce the size of the distribution or to avoid conflicts with other modules.
excludes=['my_module', 'my_other_module']
win_no_prefer_redirects
On Windows, PyInstaller tries to prefer the system DLLs over the ones included in the distribution. This option disables this behavior.
win_no_prefer_redirects=True
win_private_assemblies
On Windows, PyInstaller creates a manifest file that specifies the version of the C runtime library to use. This option forces PyInstaller to use private assemblies instead of the system ones.
win_private_assemblies=True
cipher
Specifies the encryption method to use for the archive. The default is to use no encryption.
cipher='AES-256'
noarchive
This determines whether to store frozen Python source files as individual files in the output directory or package them as an archive within the resulting executable.
noarchive=True
EXE
exclude_binaries
Specifies whether to include any binary files in the executable file. The default is to exclude them.
exclude_binaries=False
name
Specifies the name of the executable file. The default is to use the name of the main script.
name='my_program.exe'
debug
Specifies whether to include debugging information in the executable file. The default is to exclude it.
debug=True
strip
Specifies whether to strip debugging information from the executable file. The default is to include it.
exe = EXE(pyz, a.scripts, strip=True
upx
Specifies whether to use the UPX executable compressor to reduce the size of the executable file. The default is to use it.
upx=True
console
:
Controls whether to show a console window or not. Default is True.
console=True
icon:
Path to the icon file. By default, this is empty, and pyinstaller shows the default icon (depending on the OS).
icon='/path/to/icon.ico'
uac_admin:
Whether the EXE will require administrative privileges on Windows, or not.
uac_admin=True
This marks the end of the Pyinstaller Spec File Tutorial. Any suggestions or contributions for CodersLegacy are more than welcome. Questions regarding the tutorial content can be asked in the comments section below.