CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pyinstaller

PyInstaller bundles a Python application and all its dependencies into a single package.

Pending
Overview
Eval results
Files

hook-development.mddocs/

Hook Development

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.

Capabilities

Module Discovery Functions

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
    """

Data File Collection

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
    """

Binary and Dynamic Library Collection

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')
    """

Package Path and Metadata Functions

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')
    """

Requirements and Version Checking

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
    """

Isolated Execution Functions

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
    """

Entry Point Collection

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')
    """

Utility Functions

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
    """

Hook File Structure

PyInstaller hooks are Python files with specific naming conventions:

Hook Types

  1. Module hooks: hook-{module_name}.py
  2. Runtime hooks: rthook_{module_name}.py
  3. Pre-import hooks: pre_find_module_path/hook-{module_name}.py

Example Hook File

# 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']

Runtime Hook Example

# 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')

Constants

# 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 communication

Hook Configuration

Hooks 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']
        }
    }
)

Hook Development Best Practices

  1. Test thoroughly: Hooks should work across different package versions
  2. Handle missing modules: Use can_import_module() before collecting
  3. Minimize collection: Only collect what's actually needed
  4. Document requirements: Explain why specific collections are needed
  5. Use filters: Filter out test modules and development tools
  6. Handle platform differences: Account for OS-specific behaviors

Install with Tessl CLI

npx tessl i tessl/pypi-pyinstaller

docs

cli-interface.md

cli-utilities.md

hook-development.md

index.md

platform-features.md

spec-file-classes.md

tile.json