PyInstaller bundles a Python application and all its dependencies into a single package.
—
PyInstaller hooks are Python modules that provide additional instructions for collecting dependencies that cannot be automatically detected. Hook utilities provide functions for discovering modules, collecting data files, and handling special packaging requirements.
Functions for discovering and collecting Python modules and packages.
def collect_submodules(package, filter=lambda name: True, on_error="warn once"):
"""
Recursively collect all submodules of a package.
Args:
package (str): Package name to collect submodules from
filter (callable): Function to filter submodule names (default: lambda name: True)
on_error (str): Error handling mode ("warn once", "ignore", "raise")
Returns:
list: List of module names that can be imported
Example:
# Collect all numpy submodules
hiddenimports = collect_submodules('numpy')
# Collect with filter
hiddenimports = collect_submodules('scipy',
filter=lambda name: 'test' not in name)
"""
def collect_all(package_name, include_py_files=True, filter_submodules=None,
exclude_datas=None, include_datas=None, on_error="warn once"):
"""
Collect all components (submodules, data files, binaries) for a package.
Args:
package_name (str): Package to collect from
include_py_files (bool): Include .py files in data collection
filter_submodules (callable): Filter function for submodule collection
exclude_datas (list): Data file exclusion patterns
include_datas (list): Data file inclusion patterns
on_error (str): Error handling mode
Returns:
tuple: (datas, binaries, hiddenimports) containing collected components
Example:
datas, binaries, hiddenimports = collect_all('requests')
"""
def can_import_module(module_name):
"""
Test if a module can be imported.
Args:
module_name (str): Module name to test
Returns:
bool: True if module can be imported, False otherwise
Example:
if can_import_module('tensorflow'):
hiddenimports.extend(['tensorflow.python'])
"""
def is_package(module_name):
"""
Check if module name refers to a package.
Args:
module_name (str): Module name to check
Returns:
bool: True if name refers to a package, False otherwise
"""Functions for collecting data files, configuration files, and other non-Python resources.
def collect_data_files(package, include_py_files=False, subdir=None,
excludes=None, includes=None):
"""
Collect data files from a package installation.
Args:
package (str): Package name to collect data from
include_py_files (bool): Include .py files as data files
subdir (str): Specific subdirectory to collect from
excludes (list): File patterns to exclude
includes (list): File patterns to include (overrides excludes)
Returns:
list: List of (source, destination) tuples for data files
Example:
# Collect all data files from package
datas = collect_data_files('my_package')
# Collect only template files
datas = collect_data_files('django',
includes=['*.html', '*.txt'],
subdir='templates')
"""
def collect_system_data_files(path, destdir=None, include_py_files=False):
"""
Collect data files from a system path.
Args:
path (str): System path to collect from
destdir (str): Destination directory in bundle
include_py_files (bool): Include Python files
Returns:
list: List of (source, destination) tuples
Example:
# Collect system certificates
datas = collect_system_data_files('/etc/ssl/certs', 'certs')
"""
def collect_delvewheel_libs_directory(package_name, libdir_name=None,
datas=None, binaries=None):
"""
Collect delvewheel .libs directory for Windows packages.
Args:
package_name (str): Package name
libdir_name (str): Library directory name (auto-detected if None)
datas (list): Existing datas list to extend
binaries (list): Existing binaries list to extend
Returns:
tuple: (datas, binaries) with delvewheel libraries added
"""Functions for collecting shared libraries, DLLs, and other binary dependencies.
def collect_dynamic_libs(package, destdir=None, search_patterns=None):
"""
Collect dynamic libraries (.so, .dll, .dylib) from a package.
Args:
package (str): Package name to collect libraries from
destdir (str): Destination directory in bundle
search_patterns (list): Filename patterns to search for
Returns:
list: List of (source, destination) tuples for libraries
Example:
# Collect all dynamic libraries from package
binaries = collect_dynamic_libs('numpy')
# Collect to specific destination
binaries = collect_dynamic_libs('opencv_python', destdir='cv2')
"""Functions for obtaining package information and metadata.
def get_package_paths(package):
"""
Get all paths associated with a package.
Args:
package (str): Package name
Returns:
tuple: (package_paths, package_dir) where package_paths is list
of all paths and package_dir is the base directory
"""
def get_all_package_paths(package):
"""
Get all paths for PEP 420 namespace packages.
Args:
package (str): Package name
Returns:
list: All paths associated with namespace package
"""
def get_module_file_attribute(package):
"""
Get a module's __file__ attribute safely.
Args:
package (str): Module name
Returns:
str: Path to module file, or None if not available
"""
def get_module_attribute(module_name, attr_name):
"""
Get an arbitrary attribute from a module.
Args:
module_name (str): Module name to import
attr_name (str): Attribute name to retrieve
Returns:
object: Attribute value, or None if not available
Example:
version = get_module_attribute('requests', '__version__')
"""
def copy_metadata(package_name, recursive=False):
"""
Collect package distribution metadata.
Args:
package_name (str): Package name
recursive (bool): Include metadata for dependencies
Returns:
list: List of (source, destination) tuples for metadata files
Example:
# Collect metadata for package discovery
datas = copy_metadata('setuptools')
"""Functions for checking package versions and requirements.
def check_requirement(requirement):
"""
Check if a PEP 508 requirement specification is satisfied.
Args:
requirement (str): PEP 508 requirement string
Returns:
bool: True if requirement is satisfied, False otherwise
Example:
if check_requirement('numpy>=1.18.0'):
# Include numpy-specific optimizations
hiddenimports.extend(['numpy.core._multiarray_umath'])
"""
def get_installer(dist_name):
"""
Determine which package manager installed a distribution.
Args:
dist_name (str): Distribution name
Returns:
str: Installer name ('pip', 'conda', etc.) or None
"""Functions for safely executing code in isolated subprocesses.
def exec_statement(statement):
"""
Execute a Python statement in an isolated subprocess.
Args:
statement (str): Python code to execute
Returns:
str: Stdout from the subprocess
Raises:
ExecCommandFailed: If subprocess fails
Example:
# Get package installation path
result = exec_statement("import numpy; print(numpy.__path__[0])")
"""
def exec_statement_rc(statement):
"""
Execute statement and return exit code.
Args:
statement (str): Python statement to execute
Returns:
int: Exit code from subprocess
"""
def eval_statement(statement):
"""
Execute a Python expression and evaluate its output.
Args:
statement (str): Python expression to evaluate
Returns:
object: Evaluated result from subprocess
Example:
# Get list of submodules
submodules = eval_statement(
"import pkgutil; import mypackage; "
"[name for _, name, _ in pkgutil.iter_modules(mypackage.__path__)]"
)
"""
def get_pyextension_imports(module_name):
"""
Get imports required by a C extension module.
Args:
module_name (str): C extension module name
Returns:
list: List of required import names
"""Functions for handling setuptools entry points.
def collect_entry_point(name):
"""
Collect modules and metadata for entry point exporters.
Args:
name (str): Entry point name
Returns:
tuple: (datas, hiddenimports) for entry point support
Example:
# Support pytest plugins
datas, hiddenimports = collect_entry_point('pytest11')
"""General utility functions for hook development.
def get_homebrew_path(formula=""):
"""
Get Homebrew installation path on macOS.
Args:
formula (str): Specific formula name (optional)
Returns:
str: Path to Homebrew installation or formula
"""
def remove_prefix(string, prefix):
"""
Remove prefix from string if present.
Args:
string (str): Input string
prefix (str): Prefix to remove
Returns:
str: String with prefix removed
"""
def remove_suffix(string, suffix):
"""
Remove suffix from string if present.
Args:
string (str): Input string
suffix (str): Suffix to remove
Returns:
str: String with suffix removed
"""
def remove_file_extension(filename):
"""
Remove file extension from filename.
Args:
filename (str): Filename with extension
Returns:
str: Filename without extension
"""
def is_module_or_submodule(name, mod_or_submod):
"""
Check if name is a module or submodule of mod_or_submod.
Args:
name (str): Module name to check
mod_or_submod (str): Parent module name
Returns:
bool: True if name is module or submodule of mod_or_submod
"""
def get_hook_config(hook_api, module_name, key):
"""
Get hook configuration value.
Args:
hook_api: Hook API object
module_name (str): Module name
key (str): Configuration key
Returns:
object: Configuration value or None
"""
def include_or_exclude_file(filename, include_list=None, exclude_list=None):
"""
Generic file inclusion/exclusion decision.
Args:
filename (str): File to check
include_list (list): Inclusion patterns
exclude_list (list): Exclusion patterns
Returns:
bool: True if file should be included
"""PyInstaller hooks are Python files with specific naming conventions:
hook-{module_name}.pyrthook_{module_name}.pypre_find_module_path/hook-{module_name}.py# hook-mypackage.py
from PyInstaller.utils.hooks import collect_submodules, collect_data_files
# Collect all submodules
hiddenimports = collect_submodules('mypackage')
# Collect data files
datas = collect_data_files('mypackage')
# Add specific binary dependencies
binaries = [
('/usr/lib/libmylib.so.1', '.'),
]
# Exclude unnecessary modules to reduce size
excludedimports = ['mypackage.tests', 'mypackage.dev_tools']# rthook_matplotlib.py - Runtime hook for matplotlib
import os
import sys
# Set matplotlib backend for headless operation
os.environ['MPLBACKEND'] = 'Agg'
# Add font directories to matplotlib
if hasattr(sys, '_MEIPASS'):
import matplotlib
matplotlib.matplotlib_fname = os.path.join(sys._MEIPASS, 'matplotlib', 'mpl-data', 'matplotlibrc')# File extension patterns
PY_IGNORE_EXTENSIONS: list # Python extensions to ignore in collection
PY_DYLIB_PATTERNS: list # Dynamic library filename patterns
# Hook variables dictionary
hook_variables: dict # Global variables for hook communicationHooks can be configured via the hooksconfig parameter in Analysis:
# In spec file
a = Analysis(
['myapp.py'],
hooksconfig={
'gi': {
'icons': ['Adwaita'],
'themes': ['Adwaita'],
'languages': ['en_US', 'de_DE']
},
'matplotlib': {
'backends': ['Qt5Agg', 'TkAgg']
}
}
)can_import_module() before collectingInstall with Tessl CLI
npx tessl i tessl/pypi-pyinstaller