hbutils.reflection.func
Function reflection and transformation utilities.
This module provides a collection of decorators and helper functions for working with Python callables. It focuses on manipulating function attributes, dynamically adapting call signatures, and implementing reusable pre/post-processing logic.
The module contains the following main components:
fassign()- Assign arbitrary attributes to a functionfrename()- Rename a function by updating its__name__fcopy()- Create a wrapped copy of a functionargs_iter()- Iterate over positional and keyword arguments with indicessigsupply()- Attach a supplemental signature to callablesdynamic_call()- Enable flexible argument handling for callablesstatic_call()- Restore the original function from a dynamic wrapperpre_process()- Apply argument pre-processing before function executionpost_process()- Apply return-value post-processingraising()- Convert returned exceptions into raised exceptionswarning_()- Convert returned warnings into emitted warningsfreduce()- Turn a binary operation into a variadic reductionget_callable_hint()- Build atyping.Callablehint from annotations
Example:
>>> @fassign(author='hbutils')
... def add(a, b):
... return a + b
>>> add.author
'hbutils'
>>>
>>> dynamic_call(lambda x, y: x ** y)(2, 3, 4)
8
>>>
>>> @freduce(init=0)
... def plus(a, b):
... return a + b
>>> plus(1, 2, 3)
6
Note
Some utilities (e.g., dynamic_call()) require inspectable signatures. For
builtin callables without signatures, use sigsupply() to provide one.
__all__
- hbutils.reflection.func.__all__ = ['fassign', 'frename', 'fcopy', 'args_iter', 'sigsupply', 'dynamic_call', 'static_call', 'pre_process', 'post_process', 'raising', 'warning_', 'freduce', 'get_callable_hint']
Built-in mutable sequence.
If no argument is given, the constructor creates a new empty list. The argument must be an iterable if specified.
NO_INITIAL
- hbutils.reflection.func.NO_INITIAL = <SingletonMark 'no_initial'>
Singleton mark for some situation.
Can be used when some default value is needed, especially when None has meaning which is not default. This class creates unique marker objects that can be used as sentinel values.
- Example::
>>> NO_VALUE = SingletonMark("no_value") >>> NO_VALUE is SingletonMark("no_value") # True
Note
SingletonMarkis a value-based singleton class, can be used to create an unique value, especially in the cases whichNoneis not suitable for the default value.
fassign
- hbutils.reflection.func.fassign(**assigns: Any) Callable[[Callable[[...], Any]], Callable[[...], Any]][source]
Do assignments to function attributes.
This decorator allows you to assign arbitrary attributes to a function object. It’s useful for adding metadata or custom properties to functions.
- Parameters:
assigns (Any) – Keyword arguments representing attribute names and their values to assign.
- Returns:
A decorator function that assigns the specified attributes to the target function.
- Return type:
Callable
Examples:
>>> @fassign(__name__='fff') >>> def func(a, b): >>> return a + b >>> func.__name__ 'fff'
frename
- hbutils.reflection.func.frename(new_name: str) Callable[[Callable[[...], Any]], Callable[[...], Any]][source]
Rename the given function.
This decorator changes the
__name__attribute of a function to the specified new name.- Parameters:
new_name (str) – New name of function.
- Returns:
Decorator to rename the function.
- Return type:
Callable
Examples:
>>> @frename('fff') >>> def func(a, b): >>> return a + b >>> func.__name__ 'fff'
fcopy
- hbutils.reflection.func.fcopy(func: _FuncType) _FuncType[source]
Make a copy of given function.
Creates a new function that wraps the original function, effectively creating a copy with the same behavior but a different identity. The wrapper preserves the original function’s metadata using
functools.wraps.- Parameters:
func (Callable) – Function to be copied.
- Returns:
Copied function.
- Return type:
Callable
Examples:
>>> def func(a, b): ... return a + b >>> nfunc = fcopy(func) >>> nfunc(1, 2) 3 >>> nfunc is func False
args_iter
- hbutils.reflection.func.args_iter(*args: Any, **kwargs: Any) Generator[Tuple[int | str, Any], None, None][source]
Iterate all the arguments with index and value.
This generator function yields (index, value) pairs for all arguments. For positional arguments, indices are integers starting from 0. For keyword arguments, indices are strings representing the argument names. Keyword arguments are yielded in sorted order by key.
- Parameters:
args (Tuple[Any]) – Positional arguments to iterate over.
kwargs (Dict[str, Any]) – Keyword arguments to iterate over.
- Yield:
Tuples of (index, value) where index is int for positional args and str for keyword args.
- Return type:
Generator[Tuple[Union[int, str], Any], None, None]
Examples:
>>> for index, value in args_iter(1, 2, 3, a=1, b=2, c=3): ... print(index, value) 0 1 1 2 2 3 a 1 b 2 c 3
sigsupply
- hbutils.reflection.func.sigsupply(func: Callable[[...], Any], sfunc: Callable[[...], Any]) Callable[[...], Any][source]
Supply a signature for builtin functions or methods.
This function provides a workaround for builtin functions that don’t have inspectable signatures. It attaches a supplemental function’s signature to the builtin function, allowing it to be processed by
dynamic_call()and other signature-dependent operations.- Parameters:
func (Callable) – Original function, can be a native function or builtin function.
sfunc (Callable) – Supplemental function with a valid signature. Its implementation doesn’t matter, only its signature is used.
- Returns:
The original function if it already has a signature, or a wrapped version with the supplemental signature attached.
- Return type:
Callable
Examples:
>>> dynamic_call(max)([1, 2, 3]) # no sigsupply ValueError: no signature found for builtin <built-in function max> >>> dynamic_call(sigsupply(max, lambda x: None))([1, 2, 3]) # use it as func(x) when builtin 3
dynamic_call
- hbutils.reflection.func.dynamic_call(func: Callable[[...], Any]) Callable[[...], Any][source]
Decorate function to support dynamic calling with flexible arguments.
This decorator makes a function accept any number of arguments, automatically filtering them based on the function’s signature. Extra positional arguments are ignored unless the function has *args, and extra keyword arguments are ignored unless the function has **kwargs.
- Parameters:
func (Callable) – Original function to be decorated.
- Returns:
Decorated function that supports dynamic calling.
- Return type:
Callable
Examples:
>>> dynamic_call(lambda x, y: x ** y)(2, 3) # 8 8 >>> dynamic_call(lambda x, y: x ** y)(2, 3, 4) # 8, 3rd is ignored 8 >>> dynamic_call(lambda x, y, t, *args: (args, (t, x, y)))(1, 2, 3, 4, 5) # ((4, 5), (3, 1, 2)) ((4, 5), (3, 1, 2)) >>> dynamic_call(lambda x, y: (x, y))(y=2, x=1) # (1, 2), keyword supported (1, 2) >>> dynamic_call(lambda x, y, **kwargs: (kwargs, x, y))(1, k=2, y=3) # ({'k': 2}, 1, 3) ({'k': 2}, 1, 3)
Note
Simple
dynamic_call()cannot support builtin functions because they do not have python signatures. If you need to deal with builtin functions, you can usesigsupply()to add a signature onto the function when necessary.
static_call
- hbutils.reflection.func.static_call(func: Callable[[...], Any], static_ok: bool = True) Callable[[...], Any][source]
Convert a dynamic-call function back to its original static form.
This function unwraps a function that has been decorated with
dynamic_call(), returning the original function. It’s the inverse operation ofdynamic_call().- Parameters:
func (Callable) – Given dynamic function to convert.
static_ok (bool) – Allow given function to be already static, default is
True.
- Returns:
Original static function.
- Return type:
Callable
- Raises:
TypeError – If
static_okis False and the function is already static.
pre_process
- hbutils.reflection.func.pre_process(processor: Callable[[...], Any]) Callable[[Callable[[...], Any]], Callable[[...], Any]][source]
Create a decorator that pre-processes function arguments.
This decorator applies a processor function to the arguments before passing them to the original function. The processor can transform both positional and keyword arguments.
- Parameters:
processor (Callable) – Pre-processor function that transforms arguments.
- Returns:
Function decorator that applies pre-processing.
- Return type:
Callable
Examples:
>>> @pre_process(lambda x, y: (-x, (x + 2) * y)) >>> def plus(a, b): >>> return a + b >>> >>> plus(1, 2) # 5, 5 = -1 + (1 + 2) * 2 5
Note
The processor can return: - A tuple of
(args_list, kwargs_dict)for both positional and keyword arguments - A tuple/list for positional arguments only - A dict for keyword arguments only - A single value which will be passed as the first positional argument
post_process
- hbutils.reflection.func.post_process(processor: Callable[[...], Any]) Callable[[Callable[[...], Any]], Callable[[...], Any]][source]
Create a decorator that post-processes function return values.
This decorator applies a processor function to the return value of the original function before returning it to the caller.
- Parameters:
processor (Callable) – Post-processor function that transforms the return value.
- Returns:
Function decorator that applies post-processing.
- Return type:
Callable
Examples:
>>> @post_process(lambda x: -x) >>> def plus(a, b): >>> return a + b >>> >>> plus(1, 2) # -3 -3
raising
- hbutils.reflection.func.raising(func: Callable[[...], Any] | BaseException | Type[BaseException]) Callable[[...], Any][source]
Decorate function to raise exceptions instead of returning them.
This decorator transforms functions that return exception objects into functions that raise those exceptions. It can also be used directly with exception classes or instances to create raising callables.
- Parameters:
func (Union[Callable, BaseException, Type[BaseException]]) – Function that returns exceptions, or an exception class/instance.
- Returns:
Decorated function that raises exceptions.
- Return type:
Callable
Examples:
>>> raising(RuntimeError)() # Raises RuntimeError RuntimeError >>> raising(lambda x: ValueError('value error - %s' % (repr(x), )))(1) # Raises ValueError ValueError: value error - 1
warning_
- hbutils.reflection.func.warning_(func: Callable[[...], Any] | Warning | Type[Warning] | str) Callable[[...], Any][source]
Decorate function to issue warnings instead of returning them.
This decorator transforms functions that return warning objects into functions that issue those warnings using the warnings module. It can also be used directly with warning classes, instances, or strings to create warning callables.
- Parameters:
func (Union[Callable, Warning, Type[Warning], str]) – Function that returns warnings, or a warning class/instance/string.
- Returns:
Decorated function that issues warnings.
- Return type:
Callable
Examples:
>>> warning_(RuntimeWarning)() # Issues RuntimeWarning >>> warning_(lambda x: Warning('value warning - %s' % (repr(x), )))(1) # Issues Warning
freduce
- hbutils.reflection.func.freduce(init: ~typing.Any = <SingletonMark 'no_initial'>, pass_kwargs: bool = True) Callable[[Callable[[...], _ElementType]], Callable[[...], _ElementType]][source]
Make a binary function reducible over multiple arguments.
This decorator transforms a binary function into a variadic function that applies the binary operation repeatedly (reduction). Similar to functools.reduce but as a decorator with more flexibility.
- Parameters:
init (Any) – Initial value or generator function. If
NO_INITIAL, the first argument is used as the initial value. Can be a value or a callable that returns a value.pass_kwargs (bool) – Whether to pass keyword arguments to the initial function and wrapped function.
- Returns:
Decorator for the original binary function.
- Return type:
Callable
- Raises:
SyntaxError – If no initial value is provided and no arguments are passed to the function.
Examples:
>>> @freduce(init=0) >>> def plus(a, b): >>> return a + b >>> >>> plus() # 0 0 >>> plus(1) # 1 1 >>> plus(1, 2) # 3 3 >>> plus(1, 2, 3, 4) # 10 10
get_callable_hint
- hbutils.reflection.func.get_callable_hint(f: Callable[[...], Any]) Any[source]
Get the type hint of a callable as a Callable type annotation.
This function extracts type hints from a callable and returns a Callable type annotation that represents the function’s signature. If the function has only positional parameters, it returns a specific Callable type; otherwise, it returns Callable[…, Any].
- Parameters:
f (Callable) – Callable object to extract type hints from.
- Returns:
Type hint representing the callable’s signature.
- Return type:
type
Examples:
>>> def f1(x: float, y: str) -> int: ... pass >>> get_callable_hint(f1) # Callable[[float, str], int] typing.Callable[[float, str], int] >>> >>> def f2(x: float, y: str, *, z: int): ... pass >>> get_callable_hint(f2) # Callable[..., Any] typing.Callable[..., typing.Any]