Funcgen

A small module for generating sets of function signatures and corresponding function objects.

Installation

funcgen requires Python >= 3.6 because it relies on modern type annotations.

pip install funcgen

Example

>>> import funcgen
>>>
>>> def wrapper(present):
...     log(f'Wrapped {present.__name__}')
...     return present
...
>>> def test_wrapper():
...     for funcs in funcgen.all_valid_functions():
...         assert all(wrapper(f) == f for f in funcs)
...
>>> test_wrapper()

API

Contents

funcgen.valid_signatures

This will generate every combination of the parameters and parameter attributes passed to it, if that combination results in a valid Python function signature.

funcgen.all_valid_signatures

A convenience function that will generate an example of every category of valid function signature for Python.

funcgen.valid_functions

For every signature in signatures this function will yield a sequence of callable objects representing various forms that signature could take.

funcgen.all_valid_functions

A convenience function that feeds all_valid_signatures into valid_functions to produce all callable forms of all valid signatures.

funcgen.valid_parameters

Takes in parameter names, defaults, and annotations and generates every sequence of parameters possible from every combination of those attributes.

Documentation

funcgen.valid_signatures(args: Sequence[Tuple[Sequence[str], Sequence[Any], Sequence[Type]]] = [], kwargs: Sequence[Tuple[Sequence[str], Sequence[Any], Sequence[Type]]] = [], var_args: Tuple[Sequence[str], Sequence[Type]] = ([], []), var_kwargs: Tuple[Sequence[str], Sequence[Type]] = ([], []), return_annotations: Sequence[object] = [<class 'inspect._empty'>]) → Generator[inspect.Signature, None, None][source]

This will generate every combination of the parameters and parameter attributes passed to it, if that combination results in a valid Python function signature.

A VarParamTuple describes the range of attributes to give a variadic parameter. It is a tuple of two sequences: names and type annotations, respectively. The cross product of that tuple represents the range of attributes to give that parameter in the results.

Use Parameter.empty to specify a missing type annotation or default value, and Signature.empty to specify a missing return type annotation.

>>> args = [(['arg1'], [Parameter.empty, 42], [int])]
>>> kwargs = []
>>> var_args = (['args'], [float])
>>> var_kwargs = ([], [])
>>> return_annotations = [Signature.empty, int]
>>> [str(s) for s in valid_signatures(args, kwargs, var_args, var_kwargs, return_annotations)]
['()',
 '() -> int',
 '(*args:float)',
 '(*args:float) -> int',
 '(arg1:int)',
 '(arg1:int) -> int',
 '(arg1:int, *args:float)',
 '(arg1:int, *args:float) -> int',
 '(arg1:int=42)',
 '(arg1:int=42) -> int',
 '(arg1:int=42, *args:float)',
 '(arg1:int=42, *args:float) -> int']
Parameters
  • args (Sequence[ParamTuple]) – A sequence of ParamTuples used to create Parameter.POSITIONAL_OR_KEYWORD Parameters (see valid_parameters)

  • kwargs (Sequence[ParamTuple]) – A sequence of ParamTuples used to create Parameter.KEYWORD_ONLY Parameters (see valid_parameters)

  • var_args (Sequence[VarParamTuple]) – A sequence of VarParamTuples used to create Parameter.VAR_POSITIONAL Parameters (see above)

  • var_kwargs (Sequence[VarParamTuple]) – A sequence of VarParamTuples used to create Parameter.VAR_KEYWORD Parameters (see above)

  • return_annotations – A sequence of return annotations.

funcgen.all_valid_signatures() → Generator[inspect.Signature, None, None][source]

A convenience function that will generate an example of every category of valid function signature for Python. That is all combinations of

  • Zero, one, and two positional parameters with and without type annotations and default values.

  • Zero, one, and two keyword only parameters with and without type annotations and default values.

  • With and without *args, with and without a type annotation.

  • With and without **kwargs, with and without a type annotation.

  • With and without a return type annotation.

See the source for the call to valid_signatures

funcgen.valid_functions(signatures: Iterable[inspect.Signature]) → Generator[Sequence[Callable], None, None][source]

For every signature in signatures this function will yield a sequence of callable objects representing various forms that signature could take.

Given an example signature like:

(arg1:int=42, *args:str, kwarg1=False, kwarg2:bool) -> bytes

The sequence yielded is equivalent to this:

# Regular function
def f(arg1:int=42, *args:str, kwarg1=False, kwarg2:bool) -> bytes:
    pass

# Bound Method
class Foo:
    def f(arg1:int=42, *args:str, kwarg1=False, kwarg2:bool) -> bytes:
        pass

# Static Class Method
class FooStatic:
    @staticmethod
    def f(arg1:int=42, *args:str, kwarg1=False, kwarg2:bool) -> bytes:
        pass

# Sequence yielded
return f, Foo().f, FooStatic.f, FooStatic().f
Parameters

signatures

funcgen.all_valid_functions() → Generator[Sequence[Callable], None, None][source]

A convenience function that feeds all_valid_signatures into valid_functions to produce all callable forms of all valid signatures.

funcgen.valid_parameters(param_kind: inspect._ParameterKind, params: Sequence[Tuple[Sequence[str], Sequence[Any], Sequence[Type]]]) → Generator[List[inspect.Parameter], None, None][source]

Takes in parameter names, defaults, and annotations and generates every sequence of parameters possible from every combination of those attributes.

A ParamTuple is a tuple of three sequences: names, default values, and annotations, respectively. params is a sequence of ParamTuples such that the cross product of params[i] represents the range of desired values for the ith parameter.

Given every subset params[:i] for i in range(len(params)), this function will yield items from the cross product of the desired values for those parameters in the subset as a list of Parameters.

If param_kind is Parameter.POSITIONAL_OR_KEYWORD or Parameter.POSITIONAL_ONLY, then those lists where some parameter has a default value and previous parameter does not are not yielded because they would be invalid.

Use Parameter.empty to specify the abscence of type annotation or default value.

>>> [str(x) for x in valid_parameters(Parameter.POSITIONAL_OR_KEYWORD,
...                                   [(['arg1'],
...                                     [42, Parameter.empty],
...                                     [int, Parameter.empty])])]
['[]',
 '[<Parameter "arg1:int=42">]',
 '[<Parameter "arg1=42">]',
 '[<Parameter "arg1:int">]',
 '[<Parameter "arg1">]']
>>> [str(x) for x in valid_parameters(Parameter.POSITIONAL_OR_KEYWORD,
...                                   [(['arg1'], [42, Parameter.empty], [int]),
...                                    (['arg2'], [107.7, Parameter.empty], [float])])]
['[]',
 '[<Parameter "arg1:int=42">]',
 '[<Parameter "arg1:int">]',
 '[<Parameter "arg1:int=42">, <Parameter "arg2:float=107.7">]',
 '[<Parameter "arg1:int">, <Parameter "arg2:float=107.7">]',
 '[<Parameter "arg1:int">, <Parameter "arg2:float">]']
>>> [str(x) for x in valid_parameters(Parameter.KEYWORD_ONLY,
...                                   [(['arg1'], [42, Parameter.empty], [int]),
...                                    (['arg2'], [107.7, Parameter.empty], [float])])]
['[]',
 '[<Parameter "arg1:int=42">]',
 '[<Parameter "arg1:int">]',
 '[<Parameter "arg1:int=42">, <Parameter "arg2:float=107.7">]',
 '[<Parameter "arg1:int">, <Parameter "arg2:float=107.7">]',
 '[<Parameter "arg1:int=42">, <Parameter "arg2:float">]',
 '[<Parameter "arg1:int">, <Parameter "arg2:float">]']
Parameters
  • param_kind – must be Parameter.POSITIONAL_ONLY, Parameter.KEYWORD_ONLY, or Parameter.POSITIONAL_OR_KEYWORD.

  • params (Sequence[ParamTuple]) –