Small library to dynamically create python functions.
npx @tessl/cli install tessl/pypi-makefun@1.16.0A comprehensive Python library for dynamically creating functions at runtime, enabling developers to programmatically generate functions with custom signatures, parameters, and behavior. Makefun provides advanced capabilities for function introspection, signature manipulation, and dynamic code generation, making it particularly useful for creating decorators, proxies, and meta-programming utilities.
pip install makefunimport makefunCommon import pattern for main functionality:
from makefun import create_function, with_signature, wraps, partialFor signature manipulation utilities:
from makefun import add_signature_parameters, remove_signature_parametersFor exception handling:
from makefun import UndefinedSymbolError, UnsupportedForCompilation, SourceUnavailableFor version information:
from makefun import __version__from makefun import create_function, with_signature, wraps
from inspect import signature
# Create a function from a signature string
def my_impl(a, b, c=None):
return f"Called with a={a}, b={b}, c={c}"
# Generate a function with specific signature
dynamic_func = create_function("foo(x: int, y: str, z=42)", my_impl)
print(dynamic_func(1, "hello")) # "Called with a=1, b=hello, c=42"
# Use as decorator to change function signature
@with_signature("(name: str, age: int = 0)")
def greet(name, age):
return f"Hello {name}, you are {age} years old"
print(greet("Alice", 30)) # "Hello Alice, you are 30 years old"
# Enhanced wrapper with signature preservation
@wraps(greet, new_sig="(person_name: str, person_age: int = 25)")
def enhanced_greet(person_name, person_age):
return greet(person_name, person_age)
print(enhanced_greet("Bob")) # "Hello Bob, you are 25 years old"Makefun's design centers around three core concepts:
inspect.signature() and help()functools.wraps and functools.partial with better signature control and documentationThe library handles complex scenarios including generators, coroutines, async generators, and maintains compatibility across Python versions (2.7+ and 3.5+) using appropriate backports.
Core functionality for creating functions dynamically from signature specifications, supporting both string and Signature object inputs with comprehensive metadata control.
def create_function(
func_signature: Union[str, Signature],
func_impl: Callable[[Any], Any],
func_name: str = None,
inject_as_first_arg: bool = False,
add_source: bool = True,
add_impl: bool = True,
doc: str = None,
qualname: str = None,
co_name: str = None,
module_name: str = None,
**attrs
) -> FunctionType:
"""
Creates a function with signature func_signature that calls func_impl.
Parameters:
- func_signature: Union[str, Signature], signature specification
- func_impl: Callable[[Any], Any], implementation function to call
- func_name: str, optional name override
- inject_as_first_arg: bool, inject created function as first arg
- add_source: bool, add __source__ attribute
- add_impl: bool, add __func_impl__ attribute
- doc: str, optional docstring override
- qualname: str, optional qualified name
- co_name: str, optional code object name
- module_name: str, optional module name
- **attrs: additional attributes to set
Returns:
FunctionType: Generated function with specified signature
"""Decorators for modifying function signatures while preserving metadata and introspection capabilities, offering enhanced alternatives to standard Python decorators.
def with_signature(
func_signature: Union[str, Signature],
func_name: str = None,
inject_as_first_arg: bool = False,
add_source: bool = True,
add_impl: bool = True,
doc: str = None,
qualname: str = None,
co_name: str = None,
module_name: str = None,
**attrs
) -> Callable[[Callable], Callable]:
"""
Decorator to change function signature.
Parameters:
- func_signature: Union[str, Signature], new signature specification
- func_name: str, optional name override
- inject_as_first_arg: bool, inject created function as first arg
- add_source: bool, add __source__ attribute
- add_impl: bool, add __func_impl__ attribute
- doc: str, optional docstring override
- qualname: str, optional qualified name
- co_name: str, optional code object name
- module_name: str, optional module name
- **attrs: additional attributes to set
Returns:
Callable[[Callable], Callable]: Decorator function
"""Advanced function wrapping capabilities that extend functools.wraps with signature modification, parameter addition/removal, and better introspection support.
def wraps(
wrapped_fun: Callable,
new_sig: Union[str, Signature] = None,
prepend_args: Union[str, Parameter, Iterable[Union[str, Parameter]]] = None,
append_args: Union[str, Parameter, Iterable[Union[str, Parameter]]] = None,
remove_args: Union[str, Iterable[str]] = None,
func_name: str = None,
co_name: str = None,
inject_as_first_arg: bool = False,
add_source: bool = True,
add_impl: bool = True,
doc: str = None,
qualname: str = None,
module_name: str = None,
**attrs
) -> Callable[[Callable], Callable]:
"""
Enhanced functools.wraps with signature modification capabilities.
Parameters:
- wrapped_fun: Callable, function to wrap
- new_sig: Union[str, Signature], new signature specification
- prepend_args: Union[str, Parameter, Iterable], arguments to prepend
- append_args: Union[str, Parameter, Iterable], arguments to append
- remove_args: Union[str, Iterable[str]], arguments to remove
- func_name: str, optional name override
- co_name: str, optional code object name
- inject_as_first_arg: bool, inject created function as first arg
- add_source: bool, add __source__ attribute
- add_impl: bool, add __func_impl__ attribute
- doc: str, optional docstring override
- qualname: str, optional qualified name
- module_name: str, optional module name
- **attrs: additional attributes to set
Returns:
Callable[[Callable], Callable]: Decorator function
"""
def create_wrapper(
wrapped: Callable,
wrapper: Callable,
new_sig: Union[str, Signature] = None,
prepend_args: Union[str, Parameter, Iterable[Union[str, Parameter]]] = None,
append_args: Union[str, Parameter, Iterable[Union[str, Parameter]]] = None,
remove_args: Union[str, Iterable[str]] = None,
func_name: str = None,
inject_as_first_arg: bool = False,
add_source: bool = True,
add_impl: bool = True,
doc: str = None,
qualname: str = None,
co_name: str = None,
module_name: str = None,
**attrs
) -> Callable:
"""
Creates signature-preserving wrapper function.
Equivalent to wraps(wrapped, **kwargs)(wrapper).
Parameters: Same as wraps()
Returns:
Callable: Generated wrapper function
"""Enhanced partial function implementation with better introspection, documentation generation, and signature handling compared to functools.partial.
def partial(
f: Callable,
*preset_pos_args: Any,
**preset_kwargs: Any
) -> Callable:
"""
Enhanced functools.partial with better introspection and documentation.
Parameters:
- f: Callable, function to partially apply
- *preset_pos_args: Any, positional arguments to preset
- **preset_kwargs: Any, keyword arguments to preset
Returns:
Callable: Partial function with enhanced metadata
"""
def with_partial(
*preset_pos_args: Any,
**preset_kwargs: Any
) -> Callable[[Callable], Callable]:
"""
Decorator version of partial function.
Parameters:
- *preset_pos_args: Any, positional arguments to preset
- **preset_kwargs: Any, keyword arguments to preset
Returns:
Callable[[Callable], Callable]: Decorator function
"""Utilities for programmatically modifying function signatures by adding or removing parameters, enabling dynamic signature construction.
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.
Parameters:
- s: Signature, original signature to modify
- first: Union[str, Parameter, Iterable], parameters to add at beginning
- last: Union[str, Parameter, Iterable], parameters to add at end
- custom: Union[Parameter, Iterable[Parameter]], parameters to add at custom position
- custom_idx: int, position for custom parameters
Returns:
Signature: New signature with added parameters
"""
def remove_signature_parameters(
s: Signature,
*param_names: str
) -> Signature:
"""
Removes parameters from an existing signature.
Parameters:
- s: Signature, original signature to modify
- *param_names: str, names of parameters to remove
Returns:
Signature: New signature with removed parameters
"""Function compilation utilities for masking implementation details from debuggers while preserving source code access for development purposes.
def compile_fun(
recurse: Union[bool, Callable] = True,
except_names: Iterable[str] = ()
) -> Union[Callable, Callable[[Callable], Callable]]:
"""
Decorator to compile functions for debugging convenience.
Parameters:
- recurse: Union[bool, Callable], recursively compile referenced functions
- except_names: Iterable[str], function names to exclude from compilation
Returns:
Union[Callable, Callable[[Callable], Callable]]: Decorator or compiled function
"""__version__: str
"""Package version string, managed by setuptools_scm."""class UndefinedSymbolError(NameError):
"""Exception raised by compile_fun when function requires undefined symbols."""
class UnsupportedForCompilation(TypeError):
"""Exception raised by compile_fun when target is not supported for compilation."""
class SourceUnavailable(OSError):
"""Exception raised by compile_fun when function source code is not available."""