Modifer and shortcut API

Contents

Modifer and shortcut API#

modifiers#

The modifiers are defined as decorator functions that can modify a function and take additional input parameters. See documentation for functools.wraps. The modifiers can be applied to a node or a model. It is important to note that the modifier only sees the function rather than the node object, meaning modifiers do not have access to the node information. The decision is made to simplify the modifier definition. Modifying the function does not require the modifiers to handle the passing down of the node information properly, increasing the compatibility of chained modifiers.

Here is an example of a loop modifier:

def loop_input(parameter: str):
    """Modify function to iterate one given parameter.

    :param list parameter: target parameter to loop
        The target parameter name is changed to f"{param}_loop"
    """

    def loop(func):
        param_list = []
        for param in signature(func).parameters.values():
            if param.name == parameter:
                param_list.append(Parameter(f"{param}_loop", kind=1))
            else:
                param_list.append(param)

        new_sig = Signature(param_list)

        @wraps(func)
        def loop_wrapped(**kwargs):
            """Isolate the loop parameter and loop over the values."""
            loop_values = kwargs.pop(f"{parameter}_loop")

            return [func(**kwargs, **{parameter: value}) for value in loop_values]

        loop_wrapped.__signature__ = new_sig
        return loop_wrapped

    loop.metadata = f"loop_input({repr(parameter)})"
    return loop

The modifier takes an additional argument “parameter” and returns a modified function. For a node, the equivalent function is loop_input(parameter)(func). The function signature is modified under the loop function to indicate that the parameter requires an iterable input. Under the loop_wrapped function, the loop parameter is isolated, and the function loops over the iterable to create a list result.

Notice that the loop_wrapped function takes keyword-only arguments. The decision is made to reduce the overhead of the function call. All modifiers should have keyword-only arguments.

Note

mmodel requires modifiers to have a proper signature. If the modifier changes the function signature, add __signature__ attribute with inspect.Signature to the wrapped function.

The metadata of the modifier is used to generate the string displayed in the metadata at the node and model level. The metadata is a string passed to the “metadata” attribute of the modifier function.

shortcuts#

There are not many restrictions of shortcuts. To ensure the same behavior, the shortcut should take the model as the frist argument and return a new model. It is recommended to use model.edit method to create a new model.

To allow the shortcuts to be used in inherited model, make sure to generate new node, graph and model using the same class as the input model. The class of the input model and graph can be directly accessed using model.__class__ and model.graph.__class__ or type(model) and type(model.graph). The graph carries the information of the node, accessed by model.graph.graph[node_type].

See modifier and shortcut tutorial for how to use modifiers and shortcuts. See modifier reference and shortcut reference for all available modifiers.