I was talking to a colleague and we were not 100% sure in which functions VIKTOR requires **kwargs in the input definition. Could someone explain when this is needed exactly?
The reason for VIKTOR to require **kwargs in certain controller methods and callback functions (e.g. action button methods), is that it allows us to pass new arguments to the signature of that function without breaking (older) apps, since the new argument is silently passed into **kwargs.
An example of such an addition is the entity_name
argument that was introduced in v12.12.0. Note that apps implementing this would crash:
def callback_function(self, params, entity_id): # error: missing entity_name!
...
But having **kwargs makes this no problem:
def callback_function(self, params, entity_id, **kwargs): # entity_name is in kwargs now
...
Thank you!
I was wondering if there is a clear definition somewhere of ‘certain’ controller methods and callback functions?
For clarity reasons I would like to only add **kwargs wherever it is needed but not anywhere else to make sure it is clear that when a **kwargs is present in my code it should be there. Right now I often just add it in every function to avoid errors but this goes at a cost of code readability.
The way I understand it now is that it should be present in controller methods and methods that are connected to action buttons. Is this always the case or are there exceptions to this rule?
I could look and sum up for you all functions/methods that now require **kwargs, but I think it would be better to follow the general rule: when VIKTOR calls your function (view methods, action button methods, field visibility callback functions), use **kwargs.
Thank you, I will follow that rule :D!
Hello, I have a related question on this topic:
If I define a function in parametrization that takes values of named Fields and local variables, I cannot call the function within the DesignParametrization. Example:
This function works fine:
def complex_kenmerk_GBO(params,**kwargs):
return float(np.round(params.P_general_gebruiksoppervlak,1))
When I call it as such without any variables, e.g. to set a value of an OutputField:
configurator.Archetypes.gbo_output = OutputField("Resulterend GBO [m2]", value=complex_kenmerk_GBO)
Otherwise for visibility functions I have a function with variables but no ‘params’ and that works fine via Function Lookup:
def visible_multi_contained(L,b):
result = False
if b in L:
result = True
return result
used in a NumberFiled for as:
visible=FunctionLookup(visible_multi_contained, Lookup('P_multiAT'), COMPLEX_OPTIONS[_ATindex - 1])
But when I try to define a more intricate function of the form
def intricate_function(Pms, a, b):
return f(a, b) * Pms.foo
I cannot call the function because it needs ‘params’ which I cannot fill in because is not defined as such within DesignParametrization and also when it is omitted, it requests that the variable ‘Pms’ is filled in.
configurator.Archetypes.gbo_output = OutputField("Resulterend GBO [m2]", value=intricate_function(params, a, b))
Is it possible to combine input of the form ‘params’ and other variables?
Hi Boudewijn,
Some arguments such as the visible
argument on a normal field and the value
argument on the OutputField
can take a callable
as type. A callable
is a reference to an unevaluated function.
Like in your first example, the function complex_kenmerk_GBO
is referenced, but not ‘called’ because there are no (arg1, arg2)
behind the function that is referenced.
The function will be called on a later moment by the platform when the current filled in params (and some other things) are known.
I know from you other post, that you where working on dynamically generating the parametrization. (generating fields in a loop)
In this usecase, you can utilize the ‘higer order’ function built in Python. Such as the partial
function.
This function fills in part of the arguments and returns a new reference to a function. This is perfect for your usecase.
This would look like this
configurator.Archetypes.gbo_output = OutputField("Resulterend GBO [m2]", value=partial(intricate_function, a=a,b=b)
where the ‘intricate_function’ would look like this:
def intricate_function(a, b, params, **kwargs):
return f(a, b) * params.foo
the params
should still be called params
in the signature of the function.
hope this helps, happy coding.