Easily download, build, install, upgrade, and uninstall Python packages
—
Essential setuptools classes that provide the foundation for package building, extension compilation, and command execution. These classes extend distutils functionality with enhanced capabilities for modern Python packaging.
The Distribution class is the enhanced version of distutils.Distribution that handles setuptools-specific metadata and configuration.
class Distribution:
"""
Enhanced distribution class that extends distutils.Distribution.
This class handles package metadata, command execution, and configuration
parsing with setuptools-specific enhancements.
Key Attributes:
- metadata: Package metadata
- packages: List of packages to include
- py_modules: List of Python modules
- ext_modules: List of C/C++ extensions
- scripts: List of script files
- data_files: List of data files
- cmdclass: Dictionary of command classes
Key Methods:
"""
def __init__(self, attrs=None):
"""
Initialize Distribution with package attributes.
Parameters:
- attrs (dict): Package attributes and metadata
"""
def parse_config_files(self, filenames=None):
"""
Parse setup.cfg and other configuration files.
Parameters:
- filenames (list): Configuration files to parse
Returns:
None
"""
def get_command_class(self, command):
"""
Get command class by name.
Parameters:
- command (str): Command name (e.g., 'build', 'install')
Returns:
type: Command class
"""
def get_command_obj(self, command, create=1):
"""
Get command instance, creating if necessary.
Parameters:
- command (str): Command name
- create (int): Whether to create if not exists (default: 1)
Returns:
Command: Command instance
"""
def run_command(self, command):
"""
Execute a command by name.
Parameters:
- command (str): Command name to run
Returns:
None
"""
def run_commands(self):
"""Run all commands in command line order."""
def get_command_list(self):
"""Get list of available commands."""
def finalize_options(self):
"""Finalize and validate all options."""The Command class is the abstract base class for all setuptools commands, providing the interface and common functionality.
class Command:
"""
Abstract base class for all setuptools commands.
All setuptools commands must inherit from this class and implement
the three required methods: initialize_options, finalize_options, and run.
Attributes:
- distribution: Reference to Distribution instance
- _dry_run: Whether to perform actual operations
- verbose: Verbosity level
- force: Whether to force operations
"""
def __init__(self, dist):
"""
Initialize command with distribution reference.
Parameters:
- dist (Distribution): Distribution instance
"""
def initialize_options(self):
"""
Set default values for all command options.
This method must be implemented by subclasses to set default
values for all options that the command supports.
"""
def finalize_options(self):
"""
Validate and process command options.
This method must be implemented by subclasses to validate
option values and perform any necessary processing.
"""
def run(self):
"""
Execute the command.
This method must be implemented by subclasses to perform
the actual command operation.
"""
def announce(self, msg, level=1):
"""
Announce a message at given verbosity level.
Parameters:
- msg (str): Message to announce
- level (int): Verbosity level (default: 1)
"""
def debug_print(self, msg):
"""Print debug message if in debug mode."""
def ensure_dirname(self, option):
"""Ensure an option value is a directory name."""
def ensure_filename(self, option):
"""Ensure an option value is a filename."""
def ensure_string(self, option, default=None):
"""Ensure an option value is a string."""
def ensure_string_list(self, option):
"""Ensure an option value is a list of strings."""
def copy_file(self, infile, outfile, preserve_mode=1, preserve_times=1, link=None, level=1):
"""Copy a file with optional preservation of metadata."""
def copy_tree(self, indir, outdir, preserve_mode=1, preserve_times=1, preserve_symlinks=0, level=1):
"""Copy an entire directory tree."""
def make_file(self, infiles, outfile, func, args, exec_msg=None, skip_msg=None, level=1):
"""Make a file by calling a function if inputs are newer than output."""
def spawn(self, cmd, search_path=1, level=1):
"""Spawn a subprocess command."""
def mkpath(self, name, mode=0o777):
"""Create a directory path."""
def execute(self, func, args, msg=None, level=1):
"""Execute a function with optional message."""The Extension class describes C/C++ extension modules to be built.
class Extension:
"""
Enhanced C/C++ extension module descriptor.
Extends distutils.Extension with additional features like Cython support,
limited API support, and enhanced configuration options.
Attributes:
- name: Extension module name
- sources: List of source files
- include_dirs: Include directories
- define_macros: Preprocessor macros
- undef_macros: Macros to undefine
- library_dirs: Library search directories
- libraries: Libraries to link against
- runtime_library_dirs: Runtime library directories
- extra_objects: Additional object files
- extra_compile_args: Extra compiler arguments
- extra_link_args: Extra linker arguments
- export_symbols: Symbols to export (Windows)
- swig_opts: SWIG options
- depends: Dependency files
- language: Programming language ('c' or 'c++')
- optional: Whether extension is optional
- py_limited_api: Whether to use stable ABI
"""
def __init__(self, name, sources, include_dirs=None, define_macros=None,
undef_macros=None, library_dirs=None, libraries=None,
runtime_library_dirs=None, extra_objects=None,
extra_compile_args=None, extra_link_args=None,
export_symbols=None, swig_opts=None, depends=None,
language=None, optional=None, py_limited_api=False, **kw):
"""
Initialize Extension with configuration.
Parameters:
- name (str): Fully qualified extension name (e.g., 'package.module')
- sources (list): List of source file paths
- include_dirs (list): Directories to search for header files
- define_macros (list): Macros to define (list of tuples)
- undef_macros (list): Macros to undefine
- library_dirs (list): Directories to search for libraries
- libraries (list): Libraries to link against
- runtime_library_dirs (list): Runtime library search directories
- extra_objects (list): Additional object files to link
- extra_compile_args (list): Additional compiler arguments
- extra_link_args (list): Additional linker arguments
- export_symbols (list): Symbols to export on Windows
- swig_opts (list): Options for SWIG
- depends (list): Files that extension depends on
- language (str): Programming language ('c' or 'c++')
- optional (bool): Whether extension is optional
- py_limited_api (bool): Whether to use Python stable ABI
"""The Library class describes C/C++ libraries to be built (similar to Extension but for libraries).
class Library:
"""
C/C++ library descriptor.
Like Extension but for building libraries instead of extension modules.
Libraries are built and can be used by extension modules.
Attributes: Same as Extension
"""
def __init__(self, name, sources, **kw):
"""
Initialize Library with configuration.
Parameters: Same as Extension.__init__
"""Classes that provide automatic discovery of Python packages and modules within a project directory structure.
class PackageFinder:
"""
Standard package discovery for traditional package layouts.
Finds regular Python packages (directories with __init__.py files).
"""
@classmethod
def find(cls, where='.', exclude=(), include=('*',)):
"""
Find all packages in the given directory.
Parameters:
- where (str): Root directory to search (default: '.')
- exclude (tuple): Glob patterns for packages to exclude
- include (tuple): Glob patterns for packages to include (default: ('*',))
Returns:
list[str]: List of discovered package names
"""
class PEP420PackageFinder(PackageFinder):
"""
Discovery for PEP 420 implicit namespace packages.
Finds both regular packages and namespace packages (directories without __init__.py).
"""
@classmethod
def find(cls, where='.', exclude=(), include=('*',)):
"""
Find all packages including PEP 420 namespace packages.
Parameters:
- where (str): Root directory to search (default: '.')
- exclude (tuple): Glob patterns for packages to exclude
- include (tuple): Glob patterns for packages to include (default: ('*',))
Returns:
list[str]: List of discovered package names (including namespace packages)
"""
class ModuleFinder:
"""
Discovery for standalone Python modules.
Finds individual .py files that should be included as modules.
"""
@classmethod
def find(cls, where='.', exclude=(), include=('*',)):
"""
Find all Python modules in the given directory.
Parameters:
- where (str): Root directory to search (default: '.')
- exclude (tuple): Glob patterns for modules to exclude
- include (tuple): Glob patterns for modules to include (default: ('*',))
Returns:
list[str]: List of discovered module names
"""
class FlatLayoutPackageFinder(PEP420PackageFinder):
"""
Package discovery for flat-layout projects.
Specialized finder for projects that don't use src-layout but have packages
directly under the project root.
"""
class FlatLayoutModuleFinder(ModuleFinder):
"""
Module discovery for flat-layout projects.
Specialized finder for discovering standalone modules in flat-layout projects.
"""
class ConfigDiscovery:
"""
Automatic configuration discovery for setuptools.
Provides automatic discovery of package configuration including packages,
modules, entry points, and other metadata from project structure.
"""
def __init__(self, distribution=None):
"""
Initialize configuration discovery.
Parameters:
- distribution (Distribution, optional): Distribution instance
"""
def __call__(self, dist=None):
"""
Perform automatic discovery and apply to distribution.
Parameters:
- dist (Distribution, optional): Distribution to configure
Returns:
dict: Discovered configuration
"""from setuptools import setup, Command
import subprocess
class CustomCommand(Command):
"""Custom command example."""
description = 'Run custom command'
user_options = [
('option=', 'o', 'Custom option'),
]
def initialize_options(self):
"""Set default option values."""
self.option = None
def finalize_options(self):
"""Validate and process options."""
if self.option is None:
self.option = 'default_value'
def run(self):
"""Execute the custom command."""
self.announce(f'Running custom command with option: {self.option}')
# Custom command logic here
subprocess.run(['echo', f'Custom option: {self.option}'])
setup(
name='my-package',
cmdclass={
'custom': CustomCommand,
},
)from setuptools import setup, Extension
from Cython.Build import cythonize
extensions = [
Extension(
'my_package.fast_module',
sources=['src/fast_module.pyx'], # Cython source
include_dirs=['src/include'],
libraries=['m'],
extra_compile_args=['-O3'],
language='c++',
py_limited_api=True, # Use stable ABI
)
]
setup(
name='my-package',
ext_modules=cythonize(extensions),
)from setuptools import setup, Extension
import numpy
ext_modules = [
Extension(
'my_package.numerical',
sources=[
'src/numerical.c',
'src/utils.c',
],
include_dirs=[
'src/include',
numpy.get_include(), # NumPy headers
],
library_dirs=['/usr/local/lib'],
libraries=['blas', 'lapack'],
define_macros=[
('NPY_NO_DEPRECATED_API', 'NPY_1_7_API_VERSION'),
('VERSION', '"1.0.0"'),
],
extra_compile_args=['-O3', '-fopenmp'],
extra_link_args=['-fopenmp'],
depends=['src/numerical.h', 'src/utils.h'],
optional=False, # Required extension
)
]
setup(
name='numerical-package',
ext_modules=ext_modules,
zip_safe=False,
)from setuptools import setup
from setuptools.dist import Distribution
class CustomDistribution(Distribution):
"""Custom distribution class."""
def __init__(self, attrs=None):
# Custom initialization
super().__init__(attrs)
# Add custom behavior
def run_commands(self):
"""Override command execution."""
self.announce('Running custom distribution')
super().run_commands()
setup(
name='my-package',
distclass=CustomDistribution,
)from setuptools import setup
from setuptools.extension import Library, Extension
libraries = [
Library(
'myutils',
sources=['src/utils.c', 'src/helpers.c'],
include_dirs=['src/include'],
)
]
extensions = [
Extension(
'my_package.core',
sources=['src/core.c'],
libraries=['myutils'], # Link against our library
library_dirs=['.'],
)
]
setup(
name='my-package',
libraries=libraries,
ext_modules=extensions,
)Install with Tessl CLI
npx tessl i tessl/pypi-setuptools