A Python bindings generator for C and C++ libraries
—
Comprehensive configuration management system supporting pyproject.toml files, command-line overrides, and environment markers for flexible project setup. The system provides type-safe configuration with validation and help generation.
The Option class defines individual configuration parameters with type safety and validation.
class Option:
"""Defines configuration options for Configurable objects."""
def __init__(self, name, option_type=str, default=None, choices=None, help=None, metavar=None, tools=None):
"""
Create a configuration option.
Args:
name (str): Option name (used for command-line and config file)
option_type (type, optional): Option type (str, int, bool, list, float). Defaults to str.
default: Default value for the option
choices (list, optional): Valid choices for the option (for validation)
help (str, optional): Help text displayed in --help
metavar (str, optional): Metavar for help display (overrides default)
tools (list, optional): List of tools this option applies to
"""
pass
def validate(self, value):
"""
Validate option value against type and choices.
Args:
value: Value to validate
Returns:
Converted value of correct type
Raises:
UserException: If validation fails
"""
passThe Configurable class provides the foundation for all configurable SIP components.
class Configurable:
"""Base class for configurable objects with command-line option support."""
def add_options(self, parser):
"""
Add options to argument parser.
Args:
parser: ArgumentParser instance to add options to
"""
pass
def apply_options(self, options):
"""
Apply parsed options to configuration.
Args:
options: Parsed options namespace
"""
pass
def get_options(self):
"""
Get all available options.
Returns:
list: List of Option objects
"""
passThe PyProject class handles pyproject.toml file parsing and management.
class PyProject:
"""Parses and manages pyproject.toml configuration."""
def __init__(self, project_file='pyproject.toml'):
"""
Initialize PyProject configuration.
Args:
project_file (str): Path to pyproject.toml file
"""
pass
def get_bindings_configuration(self, name):
"""
Get bindings configuration by name.
Args:
name (str): Bindings name
Returns:
dict: Bindings configuration
"""
pass
def get_dunder_init(self):
"""
Get __init__.py configuration.
Returns:
dict: __init__.py configuration
"""
passThe Project class supports 37+ configuration options covering all aspects of build configuration.
# Build directories and paths
build_dir: str # Build directory path (default: 'build')
build_settings: dict # Platform-specific build settings
target_dir: str # Installation target directory
# Build behavior
distinfo: bool # Create .dist-info directories
verbose: bool # Enable verbose output
quiet: bool # Suppress output messages
build_tag: str # Build tag for wheel names# Python version targeting
py_debug: bool # Build for debug Python
py_include_dir: str # Python header files directory
py_platform: str # Target Python platform
py_major_version: int # Target Python major version
py_minor_version: int # Target Python minor version
minimum_glibc_version: str # Minimum GLIBC version for wheels
minimum_macos_version: str # Minimum macOS version for wheels# SIP module settings
abi_version: str # SIP ABI version (e.g., '12.8')
sip_module: str # Fully qualified SIP module name
sip_files_dir: str # Directory containing .sip files
sip_include_dirs: list # Additional .sip file search paths# Custom factories
bindings_factory: str # Custom bindings factory callable
builder_factory: str # Custom builder factory callable
project_factory: str # Custom project factory callable# Script generation
console_scripts: list # Console script entry points
gui_scripts: list # GUI script entry points
dunder_init: bool # Install __init__.py files# Source distributions
sdist_excludes: list # Files to exclude from sdist
# Wheel distributions
wheel_includes: list # Files to include in wheels
manylinux: bool # Use manylinux platform tags
# API files
api_dir: str # Generate QScintilla .api files# Metadata and documentation
metadata: dict # PEP 566 metadata overrides
documentation_dir: str # Documentation directory
license_dir: str # License files directory
# Advanced settings
jobs: int # Number of parallel build jobs
link_full_dll: bool # Link full DLL on Windows
no_docstrings: bool # Disable docstring generation
protected_is_public: bool # Treat protected as public
pyi_extract_dir: str # Type stub extraction directoryThe Bindings class supports 18+ configuration options for code generation.
# Primary bindings settings
sip_file: str # Main .sip specification file
sip_files: list # Alternative: list of .sip files
internal: bool # Mark bindings as internal only
static: bool # Build as static library# Code generation behavior
exceptions: bool # Enable C++ exception support
docstrings: bool # Generate Python docstrings
release_gil: bool # Always release Python GIL
generate_extracts: bool # Generate extract files for .sip
source_suffix: str # Generated source file suffix (.cpp/.c)# Compilation settings
include_dirs: list # C/C++ include directories
define_macros: list # Preprocessor macro definitions
extra_compile_args: list # Additional compiler arguments
extra_link_args: list # Additional linker arguments
extra_objects: list # Additional object files to link# Library linking
libraries: list # Libraries to link against
library_dirs: list # Library search directories# Additional sources
headers: list # Additional header files
sources: list # Additional C/C++ source files# Feature tags and settings
tags: list # Feature tags to enable
disabled_features: list # Feature tags to disable explicitly# Builder-specific settings
builder_settings: dict # Platform/builder-specific configurationfrom sipbuild import Project, Option
# Create project with default configuration
project = Project()
# Configure through code
project.build_dir = './build'
project.verbose = True
# Build with configuration
project.build()from sipbuild import Configurable, Option
class CustomConfigurable(Configurable):
def __init__(self):
super().__init__()
# Add custom options
self.custom_option = Option(
'custom-flag',
bool,
default=False,
help='Enable custom functionality'
)
self.output_format = Option(
'output-format',
str,
default='default',
choices=['default', 'compact', 'verbose'],
help='Output format selection'
)Complete pyproject.toml example:
[build-system]
requires = ["sip"]
build-backend = "sipbuild.api"
[project]
name = "mypackage"
version = "1.0.0"
description = "Python bindings for MyLib"
[tool.sip.project]
# Build configuration
build-dir = "build"
verbose = true
abi-version = "12.8"
# Python targeting
minimum-macos-version = "10.14"
minimum-glibc-version = "2.17"
# Distribution
wheel-includes = ["LICENSE", "README.md"]
api-dir = "api"
# Custom factories (optional)
project-factory = "mypackage.build:CustomProject"
builder-factory = "mypackage.build:CustomBuilder"
[tool.sip.bindings.mymodule]
sip-file = "mymodule.sip"
include-dirs = ["/usr/include/mylib"]
libraries = ["mylib"]
library-dirs = ["/usr/lib"]
exceptions = true
docstrings = true
release-gil = true
define-macros = [["MY_FEATURE", "1"]]
tags = ["FEATURE_X", "FEATURE_Y"]Python usage:
from sipbuild import PyProject, Project
# Load configuration from pyproject.toml
pyproject = PyProject()
project = Project()
# Apply configuration
bindings_config = pyproject.get_bindings_configuration('mymodule')
project.apply_bindings_configuration(bindings_config)Custom project factory:
# mypackage/build.py
from sipbuild import Project, AbstractBuilder
class CustomProject(Project):
def setup(self):
super().setup()
print("Setting up custom project configuration")
# Custom initialization logic
self.custom_setting = True
def build(self):
print("Building with custom logic")
super().build()
class CustomBuilder(AbstractBuilder):
def build(self):
print("Using custom build process")
# Custom build logic here
super().build()import argparse
from sipbuild import Project
# Create argument parser
parser = argparse.ArgumentParser()
# Add project options
project = Project()
project.add_options(parser)
# Parse arguments
args = parser.parse_args()
# Apply to project
project.apply_options(args)
# Build with applied configuration
project.build()All configuration options are validated against their declared types:
from sipbuild import Option, UserException
try:
option = Option('count', int, default=0)
option.validate('invalid') # Raises UserException
except UserException as e:
print(f"Validation error: {e}")Options with restricted choices are validated:
format_option = Option(
'format',
str,
choices=['json', 'xml', 'yaml'],
default='json'
)
# This would raise UserException
# format_option.validate('invalid_format')Configuration options support environment markers for conditional application:
# Only apply on Windows
windows_option = Option(
'windows-specific',
bool,
environment_marker='sys_platform == "win32"'
)Configuration errors are handled through specific exceptions:
class PyProjectOptionException(Exception):
"""Configuration option errors."""
pass
class PyProjectUndefinedOptionException(Exception):
"""Missing required options."""
passThese exceptions provide detailed error messages including:
Install with Tessl CLI
npx tessl i tessl/pypi-sip