Self written python action using non required arguments, always receive "None" for optional args

Hi,

I wrote a python action which is able to take several arguments.
Some of the parameters (arguments) I configured as “required: false” in the related action definition yaml file.
This works like expected and I don’t have to insert a value to start the action. But in the background it looks like the optional parameters are sent to the action as “None” if not set. This crashes my script as the optional argument is of type object and if now instead of an object, “None” is delivered it crashes. (not iterable)
Is there any possibility that if an parameter is optional and is not set, it really is not transferred to the action instead of containing “None”?

Is this expected behaviour or maybe a bug?
Any idea?

Thanks.

Update:

I think I found the issue in st2/param.py at master · StackStorm/st2 · GitHub

def _process_defaults(G, schemas):
    '''
    Process dependencies for parameters default values in the order schemas are defined.
    '''
    for schema in schemas:
        for name, value in six.iteritems(schema):
            absent = name not in G.node
            is_none = G.node.get(name, {}).get('value') is None
            immutable = value.get('immutable', False)
            if absent or is_none or immutable:
                _process(G, name, value.get('default'))

In this function the default values are assigned to the action params. But if a param has no default value and is not set, None will be assigned as a value. From my point of view this is a bug.

I fixed it now for me by changing one line:

if (absent or is_none or immutable) and (value.get('default') is not None):

If I do not recognize any side effects, I will open a issue/merge request.

What you’ve describe is correct behaviour by design.

The required option is not a way to conditionally include or exclude passing the parameter to the action code based on user input. It is to allow a user to execute an action without explicitly defining all the parameters declared for that action. If a parameter is defined in the action’s metadata, the parameter will always be passed to the underlying action code. The value of the parameter will be determined by user input, default value or None if neither were specified.

I see two options for your situation:

  1. Leave the parameter as optional and handle the None value in the action’s code.
  2. Define a default value in the metadata that satisfies the the data type expected by the underlying code.

Here is an example of an action that has an optional parameter consul_profile that is handled by the underlying code.

action metadata

action code

Hi Carlos,

thanks for your reply.

There are multiple possibilities to solve that. Sure I can do it in my action code. But why should I pass values which are not necessary or handle None values? In my case I have a value which can (not required) be a dictionary, therefore None is not valid as it can not be iterated. -> this brought the issue to my attention.

First option is now that I hand over an empty dictionary, second I handle the None object.

But I asked myself, why should I do that? If I have an optional parameter, without a useful default value (I don’t think an empty dict is a useful value) why should I pass that to an action? Why should I handle a None value if I do not need it?
So far I have not found an answer.

Therefore I made the change mentioned in my second post. After some time, I recognized that some actions need a “None” value which is then defined as default: null in their config files.

To fix this, I had to change my code to check for the existence of the default key and not the value:
if (absent or is_none or immutable) and 'default' in value:

Since I made this change, everything seems to be fine. This would be a solution for me.
It handles the case if an action needs a None value as well as if an action does not need it.