I want a function to accept a YAML style argument, that can be either a list or a dict. e.g
foo({'a' : 1})
, or foo([{'a' : 1}, {'b' : 2, 'c' : [1,2]}])
, or foo({'a' : {'b' : 1}})
If it is a dict, the key has to be a string, and the value has to be a Union[int, float, str]
, a list of these, another dict with the same typing rules as itself, or a list of dicts with the same rules. If it is a list it can be a list of Union[int, float, str]
, a list of dicts, or a list of lists with the same rules as itself.
No custom classes should be allowed, and the key for any dict must be a string.
I could simply do:
def foo(yaml_args : Union[List[Any], Dict[str, Any]):
pass
But I want to avoid using Any
.
My best attempt so far is:
from typing import Dict, List, Union
ScalarPod = Union[int, float, str]
Pod = Union[ScalarPod, List[ScalarPod]]
NestedDict = Dict[str, Union[
Pod,
Dict[str, Union[
Pod,
Dict[str, Union[
Pod,
Dict[str, Pod]
]]
]]
]]
def foo(yaml_args : NestedDict):
print(str(yaml_args))
foo({
'number' : 1,
'number_list' : [1, 2, 3],
'dict_a' :
{
'number_list_b' : [2,3,4],
'number_b' : 3
},
'dict_b' :
{
'nested_dict' :
{
'number' : 1,
'number_b' : 2,
}
},
'dict_c' :
{
'nested_dict' :
{
'nested_2_dict' :
{
'number' : 1
}
}
},
'dict_list' : [
{
'a' : 1
},
{
'b' : 2
}
]
}
)
This works apart from the list of dicts that I cant seem to fix.
It also has the disadvantage that it is limited to a max depth of 3 nested dicts, but this isn't a game killer. I would prefer if it had unlimtied depth, but it is not a requirement.
How could I achieve this? Thanks in advance!