2. Functions¶

Functions can be configured using a variety of pconfig tools.

2.1. Configure a function¶

Make source/modules/line_func.py

from pconfigs.pinnable import pconfig
from external_library import line_func

## This function is imported from an external library that we cannot modify.
#
# def line_func(x: float, slope: float = 1.0, offset: float = 0.0) -> float:
#     return x * slope + offset
#

@pconfig(calls=line_func)              # This config calls line_func()
class LineFunc:                        # Use suffix 'Func' because this class is callable!
    pass                               # Params, typehints, and defaults are auto generated.

The default LineFunc is automatically set:

>>> from source.modules.line_func import LineFunc
>>> print(pdefaults(LineFunc))
LineFunc(
    funcname=external_library.line_func,  # ClassVar (omit from config)
    slope=1.0,
    offset=0.0,
)

Notice that the required function parameter x: float is not included in the printed config for LineFunc. @pconfig creates config parameters only for function arguments that have a default value.

We are free to change the function defaults, so let’s add to source/modules/line_func.py,

pdefaults += LineFunc(
    slope=2.0,                            # Only the default slope is changed.
)

The default config is updated accordingly. Configuring external functions therefore allows us to reconfigure and document the parameters that functions require.

2.2. Use configured functions¶

Let’s take this example further by making a line plotting tool. Make source/modules/line_plotter.py

from source.modules.line_func import LineFunc
from pconfigs import pdefaults, pconfig, pconfiged

@pconfiged(runnable=True)
class LinePlotter:
    config: LinePlotterConfig

    def main(self, *args, **kwargs):
        x = range(self.config.x_lo, self.config.x_hi)
        y = [
            self.config.line_func(x=c)   # Calls external_library.line_func().
            for c in x                   #  ..with configured slope & offset.
        ]
        self.plot(x, y)


@pconfig(constructs=LinePlotter)
class LinePlotterConfig:
    line_func: LineFunc
    x_lo: int
    x_hi: int


pdefaults += LinePlotterConfig(
    line_func=pdefaults(LineFunc),
    x_lo=-10,
    x_hi=10,
)

Now we can configure and document any line plotter system.

Make source/pconfig/line_experiment.py

from source.modules.line_plotter import LinePlotter
from sourcs.modules.line_func import LineFunc

config = LinePlotter(
    line_func=LineFunc(
        slope=4.0, 
    )
)

The parameters of this particular line and its plotting process can now be printed and run.

$ python -m pconfigs.print source.pconfig.line_experiment.config
$ python -m pconfigs.run   source.pconfig.line_experiment.config