Validation/Normalization for Macro Recording
In Python, argument validation and normalization are very easy.
def func(arg1, arg2, arg3):
arg1, arg2, arg3 = _normalize_input(arg1, arg2, arg3)
# do something
However, normalization is always done in the function body, so that the arguments are
not normalized yet when macro expression is created. This behavior sometimes affects the
reproducibility. For example, if you pass None
as the default argument and changed the
default behavior later, recorded macro will change its behavior in the newer version:
from magicclass import magicclass
from magicclass.types import Optional
@magicclass
class Main:
# in version 0.1
def _normalize_i(self, i):
if i is not None:
return i
return 1
# in version 0.2
def _normalize_i(self, i):
if i is not None:
return i
return 2
def f(self, i: Optional[int] = None):
i = self._normalize_i(i)
print(i)
ui = Main()
ui.f() # macro is "f(i=None)"
magic-class
extends the typing system of magicgui
to support the "validator" key in
Annotated
types. The validator will be called on the passed argument before macro
creation.
@magicclass
class Main:
...
def f(self, i: Annotated[Optional[int], {"validator": _normalize_i}] = None):
print(i)
ui = Main()
ui.f() # macro is "f(i=1)" for v0.1 and "f(i=2)" for v0.2
Validators can accept the third argument, where a dictionary of all the arguments will be passed. This is useful when you want to normalize the arguments based on other arguments.
@magicclass
class Main:
def _normalize_i(self, i, values):
if i is not None:
return i
return values["j"]
def f(
self,
i: Annotated[Optional[int], {"validator": _normalize_i}] = None,
j: int = 1,
):
# if i is not given, use j instead
print(i, j)