Small library to dynamically create python functions.
—
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, ParameterAdd 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
"""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
"""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) -> strfrom 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') -> intfrom 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) -> dictfrom 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 presencefrom 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) -> dictfrom 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) -> strfrom 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) -> dictfrom 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}")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 configfrom 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) -> dictfrom 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