add optional param in the schema

ref #22
This commit is contained in:
gwen 2024-07-06 14:49:54 +02:00 committed by Emmanuel Garette
parent 7fcf5d6fc9
commit 6eafc16adb
52 changed files with 636 additions and 153 deletions

View file

@ -79,3 +79,15 @@ class UpgradeError(Exception):
class NotFoundError(Exception): class NotFoundError(Exception):
"not found error" "not found error"
pass pass
## ---- specific exceptions ----
class VariableCalculationDependencyError(Exception):
"""When an attribute is set, and
the target of this attribute doesn't exists.
"""
def __init__(self, msg, errno, xmlfiles):
if xmlfiles:
msg = _(f"{msg} in {display_xmlfiles(xmlfiles)}")
super().__init__(msg)
self.errno = errno

View file

@ -31,7 +31,7 @@ from pydantic import (
) )
from tiramisu import undefined from tiramisu import undefined
from .utils import get_jinja_variable_to_param, get_realpath from .utils import get_jinja_variable_to_param, get_realpath
from .error import DictConsistencyError from .error import DictConsistencyError, VariableCalculationDependencyError
BASETYPE = Union[StrictBool, StrictInt, StrictFloat, StrictStr, None] BASETYPE = Union[StrictBool, StrictInt, StrictFloat, StrictStr, None]
PROPERTY_ATTRIBUTE = ["frozen", "hidden", "disabled", "mandatory"] PROPERTY_ATTRIBUTE = ["frozen", "hidden", "disabled", "mandatory"]
@ -46,7 +46,7 @@ def convert_boolean(value: str) -> bool:
return True return True
elif value == "false": elif value == "false":
return False return False
elif value in ['', None]: elif value in ["", None]:
return None return None
raise Exception(f'unknown boolean value "{value}"') raise Exception(f'unknown boolean value "{value}"')
@ -61,34 +61,45 @@ CONVERT_OPTION = {
"unix_filename": dict(opttype="FilenameOption", example="/tmp/myfile.txt"), "unix_filename": dict(opttype="FilenameOption", example="/tmp/myfile.txt"),
"date": dict(opttype="DateOption", example="2000-01-01"), "date": dict(opttype="DateOption", example="2000-01-01"),
"unix_user": dict(opttype="UsernameOption", example="username"), "unix_user": dict(opttype="UsernameOption", example="username"),
"ip": dict(opttype="IPOption", initkwargs={"allow_reserved": True}, example="1.1.1.1"), "ip": dict(
opttype="IPOption", initkwargs={"allow_reserved": True}, example="1.1.1.1"
),
"cidr": dict(opttype="IPOption", initkwargs={"cidr": True}, example="1.1.1.0/24"), "cidr": dict(opttype="IPOption", initkwargs={"cidr": True}, example="1.1.1.0/24"),
"netmask": dict(opttype="NetmaskOption", example="255.255.255.0"), "netmask": dict(opttype="NetmaskOption", example="255.255.255.0"),
"network": dict(opttype="NetworkOption", example="1.1.1.0"), "network": dict(opttype="NetworkOption", example="1.1.1.0"),
"network_cidr": dict(opttype="NetworkOption", initkwargs={"cidr": True}, example="1.1.1.0/24"), "network_cidr": dict(
opttype="NetworkOption", initkwargs={"cidr": True}, example="1.1.1.0/24"
),
"broadcast": dict(opttype="BroadcastOption", example="1.1.1.255"), "broadcast": dict(opttype="BroadcastOption", example="1.1.1.255"),
"netbios": dict( "netbios": dict(
opttype="DomainnameOption", opttype="DomainnameOption",
initkwargs={"type": "netbios", "warnings_only": True}, initkwargs={"type": "netbios", "warnings_only": True},
example="example" example="example",
), ),
"domainname": dict( "domainname": dict(
opttype="DomainnameOption", initkwargs={"type": "domainname", "allow_ip": False}, opttype="DomainnameOption",
example="example.net" initkwargs={"type": "domainname", "allow_ip": False},
example="example.net",
), ),
"hostname": dict( "hostname": dict(
opttype="DomainnameOption", initkwargs={"type": "hostname", "allow_ip": False}, opttype="DomainnameOption",
example="example" initkwargs={"type": "hostname", "allow_ip": False},
example="example",
), ),
"web_address": dict( "web_address": dict(
opttype="URLOption", initkwargs={"allow_ip": False, "allow_without_dot": True}, opttype="URLOption",
example="https://example.net" initkwargs={"allow_ip": False, "allow_without_dot": True},
example="https://example.net",
),
"port": dict(
opttype="PortOption", initkwargs={"allow_private": True}, example="111"
), ),
"port": dict(opttype="PortOption", initkwargs={"allow_private": True}, example="111"),
"mac": dict(opttype="MACOption", example="00:00:00:00:00"), "mac": dict(opttype="MACOption", example="00:00:00:00:00"),
"unix_permissions": dict( "unix_permissions": dict(
opttype="PermissionsOption", initkwargs={"warnings_only": True}, func=int, opttype="PermissionsOption",
example="644" initkwargs={"warnings_only": True},
func=int,
example="644",
), ),
"choice": dict(opttype="ChoiceOption", example="a_choice"), "choice": dict(opttype="ChoiceOption", example="a_choice"),
# #
@ -100,7 +111,8 @@ class Param(BaseModel):
key: str key: str
model_config = ConfigDict(extra="forbid") model_config = ConfigDict(extra="forbid")
def __init__(self, def __init__(
self,
path, path,
attribute, attribute,
family_is_dynamic, family_is_dynamic,
@ -127,12 +139,13 @@ class SuffixParam(Param):
type: str type: str
suffix: Optional[int] = None suffix: Optional[int] = None
def __init__(self, def __init__(
self,
**kwargs, **kwargs,
) -> None: ) -> None:
if not kwargs['family_is_dynamic']: if not kwargs["family_is_dynamic"]:
msg = f'suffix parameter for "{kwargs["attribute"]}" in "{kwargs["path"]}" cannot be set none dynamic family' msg = f'suffix parameter for "{kwargs["attribute"]}" in "{kwargs["path"]}" cannot be set none dynamic family'
raise DictConsistencyError(msg, 10, kwargs['xmlfiles']) raise DictConsistencyError(msg, 10, kwargs["xmlfiles"])
super().__init__(**kwargs) super().__init__(**kwargs)
@ -145,17 +158,17 @@ class InformationParam(Param):
class IndexParam(Param): class IndexParam(Param):
type: str type: str
def __init__(self, def __init__(
self,
**kwargs, **kwargs,
) -> None: ) -> None:
if not kwargs["is_follower"]: if not kwargs["is_follower"]:
msg = f'the variable "{kwargs["path"]}" is not a follower, so cannot have index type for param in "{kwargs["attribute"]}"' msg = f'the variable "{kwargs["path"]}" is not a follower, so cannot have index type for param in "{kwargs["attribute"]}"'
raise DictConsistencyError(msg, 25, kwargs['xmlfiles']) raise DictConsistencyError(msg, 25, kwargs["xmlfiles"])
super().__init__(**kwargs) super().__init__(**kwargs)
PARAM_TYPES = { PARAM_TYPES = {
"any": AnyParam, "any": AnyParam,
"variable": VariableParam, "variable": VariableParam,
@ -170,8 +183,8 @@ class Calculation(BaseModel):
path: str path: str
inside_list: bool inside_list: bool
version: str version: str
ori_path: Optional[str]=None ori_path: Optional[str] = None
default_values: Any=None default_values: Any = None
namespace: Optional[str] namespace: Optional[str]
xmlfiles: List[str] xmlfiles: List[str]
@ -195,7 +208,12 @@ class Calculation(BaseModel):
else: else:
path = self.ori_path path = self.ori_path
variable, suffix = objectspace.paths.get_with_dynamic( variable, suffix = objectspace.paths.get_with_dynamic(
param["variable"], self.path_prefix, path, self.version, self.namespace, self.xmlfiles param["variable"],
self.path_prefix,
path,
self.version,
self.namespace,
self.xmlfiles,
) )
if not variable: if not variable:
if not param.get("optional"): if not param.get("optional"):
@ -214,7 +232,12 @@ class Calculation(BaseModel):
else: else:
path = self.ori_path path = self.ori_path
variable, suffix = objectspace.paths.get_with_dynamic( variable, suffix = objectspace.paths.get_with_dynamic(
param["variable"], self.path_prefix, path, self.version, self.namespace, self.xmlfiles param["variable"],
self.path_prefix,
path,
self.version,
self.namespace,
self.xmlfiles,
) )
if not variable: if not variable:
msg = f'cannot find variable "{param["variable"]}" defined in "{self.attribute_name}" for "{self.path}"' msg = f'cannot find variable "{param["variable"]}" defined in "{self.attribute_name}" for "{self.path}"'
@ -231,7 +254,14 @@ class Calculation(BaseModel):
class JinjaCalculation(Calculation): class JinjaCalculation(Calculation):
attribute_name: Literal[ attribute_name: Literal[
"frozen", "hidden", "mandatory", "disabled", "default", "validators", "choices", "dynamic" "frozen",
"hidden",
"mandatory",
"disabled",
"default",
"validators",
"choices",
"dynamic",
] ]
jinja: StrictStr jinja: StrictStr
params: Optional[List[Param]] = None params: Optional[List[Param]] = None
@ -264,7 +294,7 @@ class JinjaCalculation(Calculation):
}, },
} }
if self.default_values: if self.default_values:
default["params"]['__default_value'] = self.default_values default["params"]["__default_value"] = self.default_values
if add_help: if add_help:
default["help"] = function + "_help" default["help"] = function + "_help"
if self.params: if self.params:
@ -340,7 +370,7 @@ class JinjaCalculation(Calculation):
False, False,
objectspace, objectspace,
add_help=True, add_help=True,
params={None: [self.attribute_name], 'when': True, 'inverse': False}, params={None: [self.attribute_name], "when": True, "inverse": False},
) )
elif self.attribute_name == "choices": elif self.attribute_name == "choices":
return_type = self.return_type return_type = self.return_type
@ -362,31 +392,42 @@ class JinjaCalculation(Calculation):
raise Exception("hu?") raise Exception("hu?")
class VariableCalculation(Calculation): class _VariableCalculation(Calculation):
attribute_name: Literal[
"default", "choices", "dynamic"
]
variable: StrictStr variable: StrictStr
propertyerror: bool = True propertyerror: bool = True
allow_none: bool = False allow_none: bool = False
def get_params(self, def get_variable(self,
objectspace, objectspace,
needs_multi: Optional[bool] = None, ) -> "Variable":
):
if self.ori_path is None: if self.ori_path is None:
path = self.path path = self.path
else: else:
path = self.ori_path path = self.ori_path
variable, suffix = objectspace.paths.get_with_dynamic( variable, suffix = objectspace.paths.get_with_dynamic(
self.variable, self.path_prefix, path, self.version, self.namespace, self.xmlfiles self.variable,
self.path_prefix,
path,
self.version,
self.namespace,
self.xmlfiles,
) )
if variable and not isinstance(variable, objectspace.variable):
# FIXME remove the pfff
raise Exception("pfff it's a family")
return variable, suffix
def get_params(
self,
objectspace,
variable: "Variable",
suffix: Optional[str],
*,
needs_multi: Optional[bool] = None,
):
if not variable: if not variable:
msg = f'Variable not found "{self.variable}" for attribut "{self.attribute_name}" for variable "{self.path}"' msg = f'Variable not found "{self.variable}" for attribut "{self.attribute_name}" for variable "{self.path}"'
raise DictConsistencyError(msg, 88, self.xmlfiles) raise DictConsistencyError(msg, 88, self.xmlfiles)
if not isinstance(variable, objectspace.variable):
# FIXME remove the pfff
raise Exception("pfff it's a family")
param = { param = {
"type": "variable", "type": "variable",
"variable": variable, "variable": variable,
@ -396,7 +437,7 @@ class VariableCalculation(Calculation):
param["suffix"] = suffix param["suffix"] = suffix
params = {None: [param]} params = {None: [param]}
if self.default_values: if self.default_values:
params['__default_value'] = self.default_values params["__default_value"] = self.default_values
if self.allow_none: if self.allow_none:
params["allow_none"] = True params["allow_none"] = True
if needs_multi is None: if needs_multi is None:
@ -406,11 +447,15 @@ class VariableCalculation(Calculation):
needs_multi = self.path in objectspace.multis needs_multi = self.path in objectspace.multis
calc_variable_is_multi = variable.path in objectspace.multis calc_variable_is_multi = variable.path in objectspace.multis
if not calc_variable_is_multi: if not calc_variable_is_multi:
if variable.path in objectspace.paths._dynamics and (suffix is None or suffix[-1] is None): if variable.path in objectspace.paths._dynamics and (
suffix is None or suffix[-1] is None
):
self_dyn_path = objectspace.paths._dynamics.get(self.path) self_dyn_path = objectspace.paths._dynamics.get(self.path)
if self_dyn_path is not None: if self_dyn_path is not None:
var_dyn_path = objectspace.paths._dynamics[variable.path] var_dyn_path = objectspace.paths._dynamics[variable.path]
if self_dyn_path != var_dyn_path and not self_dyn_path.startswith(f'{var_dyn_path}.'): if self_dyn_path != var_dyn_path and not self_dyn_path.startswith(
f"{var_dyn_path}."
):
calc_variable_is_multi = True calc_variable_is_multi = True
else: else:
calc_variable_is_multi = True calc_variable_is_multi = True
@ -430,18 +475,33 @@ class VariableCalculation(Calculation):
raise DictConsistencyError(msg, 21, self.xmlfiles) raise DictConsistencyError(msg, 21, self.xmlfiles)
return params return params
class VariableCalculation(_VariableCalculation):
attribute_name: Literal["default", "choices", "dynamic"]
optional: bool = False
def to_function( def to_function(
self, self,
objectspace, objectspace,
) -> dict: ) -> dict:
params = self.get_params(objectspace) if self.attribute_name != "default" and self.optional is True:
msg = f'"{self.attribute_name}" variable shall not have an "optional" attribute for variable "{self.variable}"'
raise DictConsistencyError(msg, 33, self.xmlfiles)
variable, suffix = self.get_variable(objectspace)
if not variable and self.optional:
msg = f'the dependent variable was not found "{self.optional}" for attribute "{self.attribute_name}" in variable "{self.path}"'
raise VariableCalculationDependencyError(msg, 90, self.xmlfiles)
params = self.get_params(objectspace,
variable,
suffix,
)
return { return {
"function": "calc_value", "function": "calc_value",
"params": params, "params": params,
} }
class VariablePropertyCalculation(VariableCalculation): class VariablePropertyCalculation(_VariableCalculation):
attribute_name: Literal[*PROPERTY_ATTRIBUTE] attribute_name: Literal[*PROPERTY_ATTRIBUTE]
when: Any = undefined when: Any = undefined
when_not: Any = undefined when_not: Any = undefined
@ -450,10 +510,14 @@ class VariablePropertyCalculation(VariableCalculation):
self, self,
objectspace, objectspace,
) -> dict: ) -> dict:
params = self.get_params(objectspace, False) variable, suffix = self.get_variable(objectspace)
params = self.get_params(objectspace,
variable,
suffix,
needs_multi=False,)
variable = params[None][0]["variable"] variable = params[None][0]["variable"]
if self.when is not undefined: if self.when is not undefined:
if self.version == '1.0': if self.version == "1.0":
msg = f'when is not allowed in format version 1.0 for attribute "{self.attribute_name}" for variable "{self.path}"' msg = f'when is not allowed in format version 1.0 for attribute "{self.attribute_name}" for variable "{self.path}"'
raise DictConsistencyError(msg, 103, variable.xmlfiles) raise DictConsistencyError(msg, 103, variable.xmlfiles)
if self.when_not is not undefined: if self.when_not is not undefined:
@ -462,7 +526,7 @@ class VariablePropertyCalculation(VariableCalculation):
when = self.when when = self.when
inverse = False inverse = False
elif self.when_not is not undefined: elif self.when_not is not undefined:
if self.version == '1.0': if self.version == "1.0":
msg = f'when_not is not allowed in format version 1.0 for attribute "{self.attribute_name}" for variable "{self.path}"' msg = f'when_not is not allowed in format version 1.0 for attribute "{self.attribute_name}" for variable "{self.path}"'
raise DictConsistencyError(msg, 104, variable.xmlfiles) raise DictConsistencyError(msg, 104, variable.xmlfiles)
when = self.when_not when = self.when_not
@ -473,9 +537,10 @@ class VariablePropertyCalculation(VariableCalculation):
when = True when = True
inverse = False inverse = False
params[None].insert(0, self.attribute_name) params[None].insert(0, self.attribute_name)
params['when'] = when params["when"] = when
params['inverse'] = inverse params["inverse"] = inverse
return {"function": "variable_to_property", return {
"function": "variable_to_property",
"params": params, "params": params,
"help": "variable_to_property", "help": "variable_to_property",
} }
@ -490,10 +555,13 @@ class InformationCalculation(Calculation):
self, self,
objectspace, objectspace,
) -> dict: ) -> dict:
params = {None: [{ params = {
None: [
{
"type": "information", "type": "information",
"information": self.information, "information": self.information,
}] }
]
} }
if self.variable: if self.variable:
if self.ori_path is None: if self.ori_path is None:
@ -501,13 +569,18 @@ class InformationCalculation(Calculation):
else: else:
path = self.ori_path path = self.ori_path
variable, suffix = objectspace.paths.get_with_dynamic( variable, suffix = objectspace.paths.get_with_dynamic(
self.variable, self.path_prefix, path, self.version, self.namespace, self.xmlfiles self.variable,
self.path_prefix,
path,
self.version,
self.namespace,
self.xmlfiles,
) )
if variable is None or suffix is not None: if variable is None or suffix is not None:
raise Exception("pfff") raise Exception("pfff")
params[None][0]["variable"] = variable params[None][0]["variable"] = variable
if self.default_values: if self.default_values:
params['__default_value'] = self.default_values params["__default_value"] = self.default_values
return { return {
"function": "calc_value", "function": "calc_value",
"params": params, "params": params,
@ -524,7 +597,7 @@ class SuffixCalculation(Calculation):
) -> dict: ) -> dict:
suffix = {"type": "suffix"} suffix = {"type": "suffix"}
if self.suffix is not None: if self.suffix is not None:
suffix['suffix'] = self.suffix suffix["suffix"] = self.suffix
return { return {
"function": "calc_value", "function": "calc_value",
"params": {None: [suffix]}, "params": {None: [suffix]},
@ -582,7 +655,7 @@ class Family(BaseModel):
class Dynamic(Family): class Dynamic(Family):
# None only for format 1.0 # None only for format 1.0
variable: str=None variable: str = None
dynamic: Union[List[Union[StrictStr, Calculation]], Calculation] dynamic: Union[List[Union[StrictStr, Calculation]], Calculation]
@ -612,11 +685,6 @@ class Variable(BaseModel):
model_config = ConfigDict(extra="forbid", arbitrary_types_allowed=True) model_config = ConfigDict(extra="forbid", arbitrary_types_allowed=True)
#class Choice(Variable):
# type: Literal["choice"] = "choice"
# choices: Union[List[BASETYPE_CALC], Calculation]
class SymLink(BaseModel): class SymLink(BaseModel):
type: Literal["symlink"] = "symlink" type: Literal["symlink"] = "symlink"
name: str name: str

View file

@ -33,7 +33,7 @@ from json import dumps
from os.path import isfile, basename from os.path import isfile, basename
from .i18n import _ from .i18n import _
from .error import DictConsistencyError from .error import DictConsistencyError, VariableCalculationDependencyError
from .utils import normalize_family from .utils import normalize_family
from .object_model import Calculation, CONVERT_OPTION from .object_model import Calculation, CONVERT_OPTION
@ -78,7 +78,9 @@ class TiramisuReflector:
) )
if self.objectspace.export_with_import: if self.objectspace.export_with_import:
self.text["header"].extend( self.text["header"].extend(
["from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription"] [
"from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription"
]
) )
if funcs_paths: if funcs_paths:
for funcs_path in sorted(funcs_paths, key=sorted_func_name): for funcs_path in sorted(funcs_paths, key=sorted_func_name):
@ -105,7 +107,7 @@ class TiramisuReflector:
baseelt = BaseElt() baseelt = BaseElt()
self.objectspace.reflector_names[ self.objectspace.reflector_names[
baseelt.path baseelt.path
] = f'option_0{self.objectspace.suffix}' ] = f"option_0{self.objectspace.suffix}"
basefamily = Family( basefamily = Family(
baseelt, baseelt,
self, self,
@ -121,33 +123,33 @@ class TiramisuReflector:
elt, elt,
self, self,
) )
# else: # else:
# path_prefixes = self.objectspace.paths.get_path_prefixes() # path_prefixes = self.objectspace.paths.get_path_prefixes()
# for path_prefix in path_prefixes: # for path_prefix in path_prefixes:
# space = self.objectspace.space.variables[path_prefix] # space = self.objectspace.space.variables[path_prefix]
# self.set_name(space) # self.set_name(space)
# baseprefix = Family( # baseprefix = Family(
# space, # space,
# self, # self,
# ) # )
# basefamily.add(baseprefix) # basefamily.add(baseprefix)
# for elt in self.reorder_family(space): # for elt in self.reorder_family(space):
# self.populate_family( # self.populate_family(
# baseprefix, # baseprefix,
# elt, # elt,
# ) # )
# if not hasattr(baseprefix.elt, "information"): # if not hasattr(baseprefix.elt, "information"):
# baseprefix.elt.information = self.objectspace.information( # baseprefix.elt.information = self.objectspace.information(
# baseprefix.elt.xmlfiles # baseprefix.elt.xmlfiles
# ) # )
# for key, value in self.objectspace.paths.get_providers_path( # for key, value in self.objectspace.paths.get_providers_path(
# path_prefix # path_prefix
# ).items(): # ).items():
# setattr(baseprefix.elt.information, key, value) # setattr(baseprefix.elt.information, key, value)
# for key, value in self.objectspace.paths.get_suppliers_path( # for key, value in self.objectspace.paths.get_suppliers_path(
# path_prefix # path_prefix
# ).items(): # ).items():
# setattr(baseprefix.elt.information, key, value) # setattr(baseprefix.elt.information, key, value)
baseelt.name = normalize_family(self.objectspace.base_option_name) baseelt.name = normalize_family(self.objectspace.base_option_name)
baseelt.description = self.objectspace.base_option_name baseelt.description = self.objectspace.base_option_name
self.reflector_objects[baseelt.path].get( self.reflector_objects[baseelt.path].get(
@ -201,7 +203,9 @@ class Common:
self.populate_attrib() self.populate_attrib()
if self.informations: if self.informations:
for information in self.informations: for information in self.informations:
self.tiramisu.text['option'].append(f'{information}.set_option({self.option_name})') self.tiramisu.text["option"].append(
f"{information}.set_option({self.option_name})"
)
return self.option_name return self.option_name
def populate_attrib(self): def populate_attrib(self):
@ -275,7 +279,7 @@ class Common:
informations = self.objectspace.informations.get(self.elt.path) informations = self.objectspace.informations.get(self.elt.path)
if not informations: if not informations:
return return
keys['informations'] = informations keys["informations"] = informations
def populate_param( def populate_param(
self, self,
@ -299,14 +303,20 @@ class Common:
if param["variable"].path == self.elt.path: if param["variable"].path == self.elt.path:
return f'ParamSelfInformation("{param["information"]}", {default})' return f'ParamSelfInformation("{param["information"]}", {default})'
information_variable_path = param["variable"].path information_variable_path = param["variable"].path
information_variable = self.tiramisu.reflector_objects[information_variable_path] information_variable = self.tiramisu.reflector_objects[
information_variable_path
]
if information_variable_path not in self.calls: if information_variable_path not in self.calls:
option_name = information_variable.get(self.calls, self.elt.path) option_name = information_variable.get(self.calls, self.elt.path)
return f'ParamInformation("{param["information"]}", {default}, option={option_name})' return f'ParamInformation("{param["information"]}", {default}, option={option_name})'
else: else:
information = f'ParamInformation("{param["information"]}", {default})' information = (
f'ParamInformation("{param["information"]}", {default})'
)
information_name = self.tiramisu.get_information_name() information_name = self.tiramisu.get_information_name()
self.tiramisu.text["option"].append(f'{information_name} = {information}') self.tiramisu.text["option"].append(
f"{information_name} = {information}"
)
information_variable.informations.append(information_name) information_variable.informations.append(information_name)
return information_name return information_name
return f'ParamInformation("{param["information"]}", {default})' return f'ParamInformation("{param["information"]}", {default})'
@ -385,9 +395,10 @@ class Common:
ret = ret + ")" ret = ret + ")"
return ret return ret
def populate_calculation(self, def populate_calculation(
self,
datas: Union[Calculation, str, list], datas: Union[Calculation, str, list],
return_a_tuple: bool=False, return_a_tuple: bool = False,
) -> str: ) -> str:
if isinstance(datas, str): if isinstance(datas, str):
return self.convert_str(datas) return self.convert_str(datas)
@ -398,15 +409,18 @@ class Common:
params = [] params = []
for idx, data in enumerate(datas): for idx, data in enumerate(datas):
if isinstance(data, Calculation): if isinstance(data, Calculation):
try:
params.append(self.calculation_value(data)) params.append(self.calculation_value(data))
except VariableCalculationDependencyError:
pass
elif isinstance(data, str): elif isinstance(data, str):
params.append(self.convert_str(data)) params.append(self.convert_str(data))
else: else:
params.append(str(data)) params.append(str(data))
if return_a_tuple: if return_a_tuple:
ret = '(' ret = "("
else: else:
ret = '[' ret = "["
ret += ", ".join(params) ret += ", ".join(params)
if return_a_tuple: if return_a_tuple:
if len(params) <= 1: if len(params) <= 1:
@ -441,18 +455,28 @@ class Variable(Common):
) )
return return
if self.elt.type == "choice": if self.elt.type == "choice":
keys["values"] = self.populate_calculation(self.elt.choices, return_a_tuple=True) keys["values"] = self.populate_calculation(
self.elt.choices, return_a_tuple=True
)
if self.elt.path in self.objectspace.multis: if self.elt.path in self.objectspace.multis:
keys["multi"] = self.objectspace.multis[self.elt.path] keys["multi"] = self.objectspace.multis[self.elt.path]
if not hasattr(self.elt, "default"):
print('FIXME CA EXISTE!!!')
if hasattr(self.elt, "default") and self.elt.default is not None: if hasattr(self.elt, "default") and self.elt.default is not None:
try:
keys["default"] = self.populate_calculation(self.elt.default) keys["default"] = self.populate_calculation(self.elt.default)
except VariableCalculationDependencyError:
pass
if self.elt.path in self.objectspace.default_multi: if self.elt.path in self.objectspace.default_multi:
keys["default_multi"] = self.populate_calculation(self.objectspace.default_multi[self.elt.path]) try:
keys["default_multi"] = self.populate_calculation(
self.objectspace.default_multi[self.elt.path]
)
except VariableCalculationDependencyError:
pass
if self.elt.validators: if self.elt.validators:
keys["validators"] = self.populate_calculation(self.elt.validators) keys["validators"] = self.populate_calculation(self.elt.validators)
for key, value in CONVERT_OPTION.get(self.elt.type, {}).get("initkwargs", {}).items(): for key, value in (
CONVERT_OPTION.get(self.elt.type, {}).get("initkwargs", {}).items()
):
if isinstance(value, str): if isinstance(value, str):
value = self.convert_str(value) value = self.convert_str(value)
keys[key] = value keys[key] = value

View file

@ -7,7 +7,7 @@ my_variable:
type: choice type: choice
choices: choices:
- type: variable - type: variable
variable: rougail.source_variable_1 variable: _.source_variable_1
- type: variable - type: variable
variable: rougail.source_variable_2 variable: _.source_variable_2
default: val1 default: val1

View file

@ -0,0 +1,11 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_1 = StrOption(name="source_variable_1", doc="the first source variable", default="val1", properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
option_2 = StrOption(name="source_variable_2", doc="the second source variable", default="val2", properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
option_3 = ChoiceOption(name="my_variable", doc="a variable", values=(Calculation(func['calc_value'], Params((ParamOption(option_1)))), Calculation(func['calc_value'], Params((ParamOption(option_2))))), default="val1", properties=frozenset({"mandatory", "standard"}), informations={'type': 'choice'})
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[option_1, option_2, option_3])

View file

@ -0,0 +1,13 @@
---
version: 1.1
my_variable:
default: val1
my_calculated_variable:
multi: true
default:
- type: variable
variable: _.my_variable
optional: true
- type: variable
variable: _.my_variable_unexists
optional: true

View file

@ -0,0 +1,12 @@
{
"rougail.my_variable": {
"owner": "default",
"value": "val1"
},
"rougail.my_calculated_variable": {
"owner": "default",
"value": [
"val1"
]
}
}

View file

@ -0,0 +1,6 @@
{
"rougail.my_variable": "val1",
"rougail.my_calculated_variable": [
"val1"
]
}

View file

@ -0,0 +1,12 @@
{
"rougail.my_variable": {
"owner": "default",
"value": "val1"
},
"rougail.my_calculated_variable": {
"owner": "default",
"value": [
"val1"
]
}
}

View file

@ -0,0 +1,11 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_2 = StrOption(name="my_variable", doc="my_variable", default="val1", properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
option_3 = StrOption(name="my_calculated_variable", doc="my_calculated_variable", multi=True, default=[Calculation(func['calc_value'], Params((ParamOption(option_2))))], default_multi=Calculation(func['calc_value'], Params((ParamOption(option_2)))), properties=frozenset({"mandatory", "notempty", "standard"}), informations={'type': 'string'})
optiondescription_1 = OptionDescription(name="rougail", doc="Rougail", children=[option_2, option_3], properties=frozenset({"standard"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1])

View file

@ -0,0 +1,16 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_3 = StrOption(name="my_variable", doc="my_variable", default="val1", properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
option_4 = StrOption(name="my_calculated_variable", doc="my_calculated_variable", multi=True, default=[Calculation(func['calc_value'], Params((ParamOption(option_3))))], default_multi=Calculation(func['calc_value'], Params((ParamOption(option_3)))), properties=frozenset({"mandatory", "notempty", "standard"}), informations={'type': 'string'})
optiondescription_2 = OptionDescription(name="rougail", doc="Rougail", children=[option_3, option_4], properties=frozenset({"standard"}))
optiondescription_1 = OptionDescription(name="1", doc="1", children=[optiondescription_2], properties=frozenset({"standard"}))
option_7 = StrOption(name="my_variable", doc="my_variable", default="val1", properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
option_8 = StrOption(name="my_calculated_variable", doc="my_calculated_variable", multi=True, default=[Calculation(func['calc_value'], Params((ParamOption(option_7))))], default_multi=Calculation(func['calc_value'], Params((ParamOption(option_7)))), properties=frozenset({"mandatory", "notempty", "standard"}), informations={'type': 'string'})
optiondescription_6 = OptionDescription(name="rougail", doc="Rougail", children=[option_7, option_8], properties=frozenset({"standard"}))
optiondescription_5 = OptionDescription(name="2", doc="2", children=[optiondescription_6], properties=frozenset({"standard"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1, optiondescription_5])

View file

@ -0,0 +1,10 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_1 = StrOption(name="my_variable", doc="my_variable", default="val1", properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
option_2 = StrOption(name="my_calculated_variable", doc="my_calculated_variable", multi=True, default=[Calculation(func['calc_value'], Params((ParamOption(option_1))))], default_multi=Calculation(func['calc_value'], Params((ParamOption(option_1)))), properties=frozenset({"mandatory", "notempty", "standard"}), informations={'type': 'string'})
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[option_1, option_2])

View file

@ -0,0 +1,13 @@
---
version: 1.1
my_variable:
default: val1
my_calculated_variable:
multi: true
default:
- type: variable
variable: _.my_variable_unexists
optional: true
- type: variable
variable: _.my_variable
optional: true

View file

@ -0,0 +1,12 @@
{
"rougail.my_variable": {
"owner": "default",
"value": "val1"
},
"rougail.my_calculated_variable": {
"owner": "default",
"value": [
"val1"
]
}
}

View file

@ -0,0 +1,6 @@
{
"rougail.my_variable": "val1",
"rougail.my_calculated_variable": [
"val1"
]
}

View file

@ -0,0 +1,12 @@
{
"rougail.my_variable": {
"owner": "default",
"value": "val1"
},
"rougail.my_calculated_variable": {
"owner": "default",
"value": [
"val1"
]
}
}

View file

@ -0,0 +1,11 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_2 = StrOption(name="my_variable", doc="my_variable", default="val1", properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
option_3 = StrOption(name="my_calculated_variable", doc="my_calculated_variable", multi=True, default=[Calculation(func['calc_value'], Params((ParamOption(option_2))))], properties=frozenset({"mandatory", "notempty", "standard"}), informations={'type': 'string'})
optiondescription_1 = OptionDescription(name="rougail", doc="Rougail", children=[option_2, option_3], properties=frozenset({"standard"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1])

View file

@ -0,0 +1,16 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_3 = StrOption(name="my_variable", doc="my_variable", default="val1", properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
option_4 = StrOption(name="my_calculated_variable", doc="my_calculated_variable", multi=True, default=[Calculation(func['calc_value'], Params((ParamOption(option_3))))], properties=frozenset({"mandatory", "notempty", "standard"}), informations={'type': 'string'})
optiondescription_2 = OptionDescription(name="rougail", doc="Rougail", children=[option_3, option_4], properties=frozenset({"standard"}))
optiondescription_1 = OptionDescription(name="1", doc="1", children=[optiondescription_2], properties=frozenset({"standard"}))
option_7 = StrOption(name="my_variable", doc="my_variable", default="val1", properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
option_8 = StrOption(name="my_calculated_variable", doc="my_calculated_variable", multi=True, default=[Calculation(func['calc_value'], Params((ParamOption(option_7))))], properties=frozenset({"mandatory", "notempty", "standard"}), informations={'type': 'string'})
optiondescription_6 = OptionDescription(name="rougail", doc="Rougail", children=[option_7, option_8], properties=frozenset({"standard"}))
optiondescription_5 = OptionDescription(name="2", doc="2", children=[optiondescription_6], properties=frozenset({"standard"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1, optiondescription_5])

View file

@ -0,0 +1,10 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_1 = StrOption(name="my_variable", doc="my_variable", default="val1", properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
option_2 = StrOption(name="my_calculated_variable", doc="my_calculated_variable", multi=True, default=[Calculation(func['calc_value'], Params((ParamOption(option_1))))], properties=frozenset({"mandatory", "notempty", "standard"}), informations={'type': 'string'})
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[option_1, option_2])

View file

@ -0,0 +1,8 @@
---
version: 1.1
my_calculated_variable:
multi: true
default:
type: variable
variable: _.my_variable
optional: true

View file

@ -0,0 +1,6 @@
{
"rougail.my_calculated_variable": {
"owner": "default",
"value": []
}
}

View file

@ -0,0 +1,3 @@
{
"rougail.my_calculated_variable": []
}

View file

@ -0,0 +1,6 @@
{
"rougail.my_calculated_variable": {
"owner": "default",
"value": []
}
}

View file

@ -0,0 +1 @@
["rougail.my_calculated_variable"]

View file

@ -0,0 +1,10 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_2 = StrOption(name="my_calculated_variable", doc="my_calculated_variable", multi=True, properties=frozenset({"mandatory", "notempty", "standard"}), informations={'type': 'string'})
optiondescription_1 = OptionDescription(name="rougail", doc="Rougail", children=[option_2], properties=frozenset({"standard"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1])

View file

@ -0,0 +1,14 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_3 = StrOption(name="my_calculated_variable", doc="my_calculated_variable", multi=True, properties=frozenset({"mandatory", "notempty", "standard"}), informations={'type': 'string'})
optiondescription_2 = OptionDescription(name="rougail", doc="Rougail", children=[option_3], properties=frozenset({"standard"}))
optiondescription_1 = OptionDescription(name="1", doc="1", children=[optiondescription_2], properties=frozenset({"standard"}))
option_6 = StrOption(name="my_calculated_variable", doc="my_calculated_variable", multi=True, properties=frozenset({"mandatory", "notempty", "standard"}), informations={'type': 'string'})
optiondescription_5 = OptionDescription(name="rougail", doc="Rougail", children=[option_6], properties=frozenset({"standard"}))
optiondescription_4 = OptionDescription(name="2", doc="2", children=[optiondescription_5], properties=frozenset({"standard"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1, optiondescription_4])

View file

@ -0,0 +1,9 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_1 = StrOption(name="my_calculated_variable", doc="my_calculated_variable", multi=True, properties=frozenset({"mandatory", "notempty", "standard"}), informations={'type': 'string'})
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[option_1])

View file

@ -0,0 +1,13 @@
---
version: 1.1
my_variable:
multi: true
default:
- val1
- val2
my_calculated_variable:
multi: true
default:
type: variable
variable: _.my_variable
optional: true

View file

@ -0,0 +1,16 @@
{
"rougail.my_variable": {
"owner": "default",
"value": [
"val1",
"val2"
]
},
"rougail.my_calculated_variable": {
"owner": "default",
"value": [
"val1",
"val2"
]
}
}

View file

@ -0,0 +1,10 @@
{
"rougail.my_variable": [
"val1",
"val2"
],
"rougail.my_calculated_variable": [
"val1",
"val2"
]
}

View file

@ -0,0 +1,16 @@
{
"rougail.my_variable": {
"owner": "default",
"value": [
"val1",
"val2"
]
},
"rougail.my_calculated_variable": {
"owner": "default",
"value": [
"val1",
"val2"
]
}
}

View file

@ -0,0 +1,11 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_2 = StrOption(name="my_variable", doc="my_variable", multi=True, default=["val1", "val2"], default_multi="val1", properties=frozenset({"mandatory", "notempty", "standard"}), informations={'type': 'string'})
option_3 = StrOption(name="my_calculated_variable", doc="my_calculated_variable", multi=True, default=Calculation(func['calc_value'], Params((ParamOption(option_2)))), properties=frozenset({"mandatory", "notempty", "standard"}), informations={'type': 'string'})
optiondescription_1 = OptionDescription(name="rougail", doc="Rougail", children=[option_2, option_3], properties=frozenset({"standard"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1])

View file

@ -0,0 +1,16 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_3 = StrOption(name="my_variable", doc="my_variable", multi=True, default=["val1", "val2"], default_multi="val1", properties=frozenset({"mandatory", "notempty", "standard"}), informations={'type': 'string'})
option_4 = StrOption(name="my_calculated_variable", doc="my_calculated_variable", multi=True, default=Calculation(func['calc_value'], Params((ParamOption(option_3)))), properties=frozenset({"mandatory", "notempty", "standard"}), informations={'type': 'string'})
optiondescription_2 = OptionDescription(name="rougail", doc="Rougail", children=[option_3, option_4], properties=frozenset({"standard"}))
optiondescription_1 = OptionDescription(name="1", doc="1", children=[optiondescription_2], properties=frozenset({"standard"}))
option_7 = StrOption(name="my_variable", doc="my_variable", multi=True, default=["val1", "val2"], default_multi="val1", properties=frozenset({"mandatory", "notempty", "standard"}), informations={'type': 'string'})
option_8 = StrOption(name="my_calculated_variable", doc="my_calculated_variable", multi=True, default=Calculation(func['calc_value'], Params((ParamOption(option_7)))), properties=frozenset({"mandatory", "notempty", "standard"}), informations={'type': 'string'})
optiondescription_6 = OptionDescription(name="rougail", doc="Rougail", children=[option_7, option_8], properties=frozenset({"standard"}))
optiondescription_5 = OptionDescription(name="2", doc="2", children=[optiondescription_6], properties=frozenset({"standard"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1, optiondescription_5])

View file

@ -0,0 +1,10 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_1 = StrOption(name="my_variable", doc="my_variable", multi=True, default=["val1", "val2"], default_multi="val1", properties=frozenset({"mandatory", "notempty", "standard"}), informations={'type': 'string'})
option_2 = StrOption(name="my_calculated_variable", doc="my_calculated_variable", multi=True, default=Calculation(func['calc_value'], Params((ParamOption(option_1)))), properties=frozenset({"mandatory", "notempty", "standard"}), informations={'type': 'string'})
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[option_1, option_2])

View file

@ -0,0 +1,17 @@
{
"rougail.var": {
"owner": "default",
"value": [
"val1",
"val2"
]
},
"rougail.dynval1.var": {
"owner": "default",
"value": "a value"
},
"rougail.dynval2.var": {
"owner": "default",
"value": "a value"
}
}

View file

@ -0,0 +1,8 @@
{
"rougail.var": [
"val1",
"val2"
],
"rougail.dynval1.var": "a value",
"rougail.dynval2.var": "a value"
}

View file

@ -0,0 +1,17 @@
{
"rougail.var": {
"owner": "default",
"value": [
"val1",
"val2"
]
},
"rougail.dynval1.var": {
"owner": "default",
"value": "a value"
},
"rougail.dynval2.var": {
"owner": "default",
"value": "a value"
}
}

View file

@ -0,0 +1,11 @@
---
version: '1.1'
var1:
- a
- b
- c
var2:
choices:
type: variable
variable: _.var1
optional: true

View file

@ -0,0 +1,13 @@
---
version: '1.1'
varname:
default:
- val1
dyn{{ suffix }}:
type: dynamic
dynamic:
type: variable
variable: _.varname
optional: true
vardyn:
type: string

View file

@ -1,27 +1,16 @@
general: ---
mode_conteneur_actif: version: '1.1'
type: choice var:
description: No change - a
default: a - b
- c
var2:
- a
- b
- c
var3:
choices: choices:
- type: variable - type: variable
variable: rougail.general.var variable: _.var
- type: variable - type: variable
variable: rougail.general.var2 variable: _.var2
var:
type: string
description: New variable
multi: true
default:
- a
- b
- c
var2:
type: string
description: New variable
multi: true
default:
- a
- b
- c
version: '1.0'