CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-makefun

Small library to dynamically create python functions.

Pending
Overview
Eval results
Files

signature-utils.mddocs/

Signature Manipulation

Utilities for programmatically modifying function signatures by adding or removing parameters. These functions enable dynamic signature construction and are the building blocks used by other makefun utilities for signature modifications.

from typing import Union, Iterable
from inspect import Signature, Parameter

Capabilities

Adding Parameters to Signatures

Add parameters to existing signatures at specific positions with automatic parameter kind inference.

def add_signature_parameters(s: Signature, 
                            first: Union[str, Parameter, Iterable[Union[str, Parameter]]] = (), 
                            last: Union[str, Parameter, Iterable[Union[str, Parameter]]] = (), 
                            custom: Union[Parameter, Iterable[Parameter]] = (), 
                            custom_idx: int = -1) -> Signature:
    """
    Adds parameters to an existing signature, returning a new Signature instance.
    
    Parameters:
    - s: Signature, original signature to modify
    - first: Union[str, Parameter, Iterable[Union[str, Parameter]]], default ()
        Parameters to add at the beginning of the parameter list.
        Strings are converted to Parameter objects with auto-inferred kinds.
    - last: Union[str, Parameter, Iterable[Union[str, Parameter]]], default ()
        Parameters to add at the end of the parameter list.
        Strings are converted to Parameter objects with auto-inferred kinds.
    - custom: Union[Parameter, Iterable[Parameter]], default ()
        Parameter objects to add at a custom position specified by custom_idx
    - custom_idx: int, default -1
        Position to insert custom parameters (supports negative indexing)
        
    Returns:
    Signature: New signature with added parameters
    
    Raises:
    ValueError: If parameter names conflict with existing parameters
    
    Note:
    - Parameter kinds are auto-inferred based on context when strings are provided
    - Maintains proper parameter ordering and kind constraints
    - Preserves return annotation from original signature
    """

Removing Parameters from Signatures

Remove specified parameters from existing signatures by name.

def remove_signature_parameters(s: Signature, *param_names: str) -> Signature:
    """
    Removes parameters from an existing signature, returning a new Signature instance.
    
    Parameters:
    - s: Signature, original signature to modify
    - *param_names: str, names of parameters to remove
    
    Returns:
    Signature: New signature with specified parameters removed
    
    Raises:
    KeyError: If any parameter name is not found in the signature
    """

Usage Examples

Basic Parameter Addition

from makefun import add_signature_parameters
from inspect import signature, Parameter

def original_func(x: int, y: str) -> str:
    return f"{x}: {y}"

original_sig = signature(original_func)

# Add parameters at the beginning
new_sig = add_signature_parameters(original_sig, first="prefix: str = 'Result'")
print(new_sig)  # (prefix: str = 'Result', x: int, y: str) -> str

# Add parameters at the end
new_sig2 = add_signature_parameters(original_sig, last=["suffix: str = '!'", "verbose: bool = False"])
print(new_sig2)  # (x: int, y: str, suffix: str = '!', verbose: bool = False) -> str

# Add parameters at both ends
new_sig3 = add_signature_parameters(original_sig, 
                                   first="timestamp: float",
                                   last="debug: bool = False")
print(new_sig3)  # (timestamp: float, x: int, y: str, debug: bool = False) -> str

Using Parameter Objects

from makefun import add_signature_parameters
from inspect import signature, Parameter

def base_func(data: list) -> int:
    return len(data)

base_sig = signature(base_func)

# Create Parameter objects explicitly
log_param = Parameter('log_level', Parameter.KEYWORD_ONLY, default='INFO', annotation=str)
timeout_param = Parameter('timeout', Parameter.POSITIONAL_OR_KEYWORD, default=30, annotation=int)

# Add using Parameter objects
enhanced_sig = add_signature_parameters(base_sig, 
                                       first=timeout_param,
                                       last=log_param)
print(enhanced_sig)  # (timeout: int = 30, data: list, *, log_level: str = 'INFO') -> int

Custom Position Insertion

from makefun import add_signature_parameters
from inspect import signature, Parameter

def func_with_many_params(a: int, b: str, c: float, d: bool = True) -> dict:
    return {"a": a, "b": b, "c": c, "d": d}

original_sig = signature(func_with_many_params)

# Insert parameter at specific position (between b and c)
middle_param = Parameter('inserted', Parameter.POSITIONAL_OR_KEYWORD, default="middle", annotation=str)
new_sig = add_signature_parameters(original_sig, custom=middle_param, custom_idx=2)
print(new_sig)  # (a: int, b: str, inserted: str = 'middle', c: float, d: bool = True) -> dict

# Insert multiple parameters at custom position
multi_params = [
    Parameter('opt1', Parameter.POSITIONAL_OR_KEYWORD, annotation=str),
    Parameter('opt2', Parameter.POSITIONAL_OR_KEYWORD, default=42, annotation=int)
]
new_sig2 = add_signature_parameters(original_sig, custom=multi_params, custom_idx=1)
print(new_sig2)  # (a: int, opt1: str, opt2: int = 42, b: str, c: float, d: bool = True) -> dict

Automatic Parameter Kind Inference

from makefun import add_signature_parameters
from inspect import signature, Parameter

def base_func(x: int, *, y: str) -> str:
    """Function with keyword-only parameter."""
    return f"{x}: {y}"

base_sig = signature(base_func)

# When adding to the beginning, kinds are inferred from first existing parameter
new_sig = add_signature_parameters(base_sig, first="prefix: str")
print(new_sig)  # (prefix: str, x: int, *, y: str) -> str

# When adding to the end, kinds are inferred from last existing parameter  
new_sig2 = add_signature_parameters(base_sig, last="suffix: str = '!'")
print(new_sig2)  # (x: int, *, y: str, suffix: str = '!') -> str

# Complex example with var-positional
def var_func(a: int, *args, **kwargs) -> None:
    pass

var_sig = signature(var_func)
new_var_sig = add_signature_parameters(var_sig, first="prefix: str")
# Results in positional-only for prefix due to *args presence

Basic Parameter Removal

from makefun import remove_signature_parameters
from inspect import signature

def complex_func(a: int, b: str, c: float = 1.0, d: bool = True, *, e: str = "default") -> dict:
    return {"a": a, "b": b, "c": c, "d": d, "e": e}

original_sig = signature(complex_func)

# Remove single parameter
simplified_sig = remove_signature_parameters(original_sig, "c")
print(simplified_sig)  # (a: int, b: str, d: bool = True, *, e: str = 'default') -> dict

# Remove multiple parameters
minimal_sig = remove_signature_parameters(original_sig, "c", "d", "e")
print(minimal_sig)  # (a: int, b: str) -> dict

Combined Operations

from makefun import add_signature_parameters, remove_signature_parameters
from inspect import signature

def original_func(old_param: int, deprecated_arg: str, x: float, y: bool = True) -> str:
    return f"Result: {old_param}, {deprecated_arg}, {x}, {y}"

original_sig = signature(original_func)

# First remove deprecated parameters
cleaned_sig = remove_signature_parameters(original_sig, "old_param", "deprecated_arg")
print(cleaned_sig)  # (x: float, y: bool = True) -> str

# Then add new parameters
modernized_sig = add_signature_parameters(cleaned_sig,
                                         first="config: dict",
                                         last="verbose: bool = False")
print(modernized_sig)  # (config: dict, x: float, y: bool = True, verbose: bool = False) -> str

Working with Complex Signatures

from makefun import add_signature_parameters, remove_signature_parameters
from inspect import signature, Parameter

def complex_original(a: int, b: str = "default", *args, c: float, d: bool = True, **kwargs) -> dict:
    """Function with all parameter types."""
    return {"a": a, "b": b, "args": args, "c": c, "d": d, "kwargs": kwargs}

original_sig = signature(complex_original)

# Remove some parameters
modified_sig = remove_signature_parameters(original_sig, "b", "d")
print(modified_sig)  # (a: int, *args, c: float, **kwargs) -> dict

# Add parameters respecting the existing structure
final_sig = add_signature_parameters(modified_sig,
                                    first="version: str = '1.0'",  # Before positional
                                    last="timeout: int = 30")       # After keyword-only
print(final_sig)  # (version: str = '1.0', a: int, *args, c: float, timeout: int = 30, **kwargs) -> dict

Error Handling

from makefun import add_signature_parameters, remove_signature_parameters
from inspect import signature

def sample_func(x: int, y: str) -> str:
    return f"{x}: {y}"

sample_sig = signature(sample_func)

# Duplicate parameter name error
try:
    add_signature_parameters(sample_sig, first="x: float")  # 'x' already exists
except ValueError as e:
    print(f"Duplicate parameter error: {e}")

# Parameter not found error
try:
    remove_signature_parameters(sample_sig, "nonexistent_param")
except KeyError as e:
    print(f"Parameter not found error: {e}")

Integration with Function Creation

These utilities are commonly used with create_function and other makefun functions:

from makefun import add_signature_parameters, create_function
from inspect import signature

def base_implementation(config, x, y, debug):
    if debug:
        print(f"Config: {config}, Processing x={x}, y={y}")
    return x + y

def simple_func(x: int, y: int) -> int:
    """Simple addition function."""
    return x + y

# Get base signature and enhance it
base_sig = signature(simple_func)
enhanced_sig = add_signature_parameters(base_sig,
                                       first="config: dict = {}",
                                       last="debug: bool = False")

# Create new function with enhanced signature
enhanced_func = create_function(enhanced_sig, base_implementation, 
                               func_name="enhanced_addition")

print(enhanced_func(5, 3))                    # 8 (basic usage)
print(enhanced_func(5, 3, debug=True))        # 8 with debug output
print(enhanced_func({"mode": "fast"}, 5, 3))  # 8 with config

Practical Applications

API Versioning

from makefun import remove_signature_parameters, add_signature_parameters
from inspect import signature

def api_v1(data: dict, format: str = "json", deprecated_param: bool = True) -> dict:
    """Original API version."""
    return {"version": "v1", "data": data, "format": format}

# Create v2 API signature by removing deprecated parameter and adding new ones
v1_sig = signature(api_v1)
v2_base = remove_signature_parameters(v1_sig, "deprecated_param")
v2_sig = add_signature_parameters(v2_base, last=["validate: bool = True", "timeout: int = 30"])

print(v2_sig)  # (data: dict, format: str = 'json', validate: bool = True, timeout: int = 30) -> dict

Configuration Management

from makefun import add_signature_parameters
from inspect import signature

def core_processor(data: list) -> dict:
    """Core data processing logic."""
    return {"processed": len(data), "items": data}

# Add configuration parameters for different environments
base_sig = signature(core_processor)

# Development environment - add debugging
dev_sig = add_signature_parameters(base_sig, 
                                  first="debug: bool = True",
                                  last="log_level: str = 'DEBUG'")

# Production environment - add performance monitoring
prod_sig = add_signature_parameters(base_sig,
                                   first="monitor: bool = True", 
                                   last=["timeout: int = 300", "retries: int = 3"])

print("Development:", dev_sig)
print("Production:", prod_sig)

Install with Tessl CLI

npx tessl i tessl/pypi-makefun

docs

compilation.md

decorators.md

function-creation.md

index.md

partial.md

signature-utils.md

wrapping.md

tile.json