fix: dynoption could be optional if identifier is unknown

This commit is contained in:
egarette@silique.fr 2024-11-25 09:00:00 +01:00
parent 1a31ada869
commit baf1245c7a
7 changed files with 145 additions and 69 deletions

View file

@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Tiramisu\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-11-05 08:49+0100\n"
"POT-Creation-Date: 2024-11-25 08:23+0100\n"
"PO-Revision-Date: \n"
"Last-Translator: Emmanuel Garette <egarette@cadoles.com>\n"
"Language-Team: Tiramisu's team <egarette@cadoles.com>\n"
@ -114,7 +114,7 @@ msgstr "une propriété doit être de type frozenset"
msgid "unknown when {} (must be in append or remove)"
msgstr "value {} inconsistent (doit être append ou remove)"
#: tiramisu/api.py:1424 tiramisu/api.py:1448 tiramisu/config.py:1680
#: tiramisu/api.py:1424 tiramisu/api.py:1448 tiramisu/config.py:1681
msgid "unknown type {}"
msgstr "type inconnu {}"
@ -147,6 +147,26 @@ msgstr "param doit avoir un booléan pas un {} pour notraisepropertyerror"
msgid "param must have a boolean not a {} for raisepropertyerror"
msgstr "param doit avoir un booléan pas un {} pour raisepropertyerror"
#: tiramisu/autolib.py:151
msgid "identifiers in ParamDynOption must be a list, not {0}"
msgstr ""
"les identifiants d'un ParamDynOption doivent être une liste, donc pas {0}"
#: tiramisu/autolib.py:155
msgid "optional in ParamDynOption must be a boolean, not {0}"
msgstr ""
"le paramètre optional dans ParamDynOption doit être un booléen, pas {0}"
#: tiramisu/autolib.py:206
msgid "cannot add option in information after creating config"
msgstr ""
"ne peut ajouter une option dans une information après la création de la "
"configuration"
#: tiramisu/autolib.py:208
msgid "cannot redefine option in information"
msgstr "on ne peu pas redéfinir une option dans une information"
#: tiramisu/autolib.py:212
msgid "option in ParamInformation cannot be a symlinkoption"
msgstr "l'option dans ParamInformation ne peut pas être un symlinkoption"
@ -185,7 +205,14 @@ msgstr ""
"l'option {0} n'est pas une dynoptiondescription ou n'est pas dans une "
"dynoptiondescription"
#: tiramisu/autolib.py:848
#: tiramisu/autolib.py:682
msgid ""
"cannot calculate arguments for \"{0}\", cannot find dynamic variable \"{1}\""
msgstr ""
"impossible de calculer les arguments de \"{0}\", la variable dynamic \"{1}\" "
"ne peut être trouvée"
#: tiramisu/autolib.py:861
msgid ""
"the \"{}\" function with positional arguments \"{}\" and keyword arguments "
"\"{}\" must not return a list (\"{}\") for the follower option {}"
@ -194,7 +221,7 @@ msgstr ""
"nommés \"{}\" ne doit pas retourner une liste (\"{}\") pour l'option "
"suiveuse {}"
#: tiramisu/autolib.py:863
#: tiramisu/autolib.py:876
msgid ""
"the \"{}\" function must not return a list (\"{}\") for the follower option "
"{}"
@ -202,7 +229,7 @@ msgstr ""
"la fonction \"{}\" ne doit pas retourner une liste (\"{}\") pour l'option "
"suiveuse {}"
#: tiramisu/autolib.py:904
#: tiramisu/autolib.py:917
msgid ""
"unexpected error \"{0}\" in function \"{1}\" with arguments \"{3}\" and "
"\"{4}\" for option {2}"
@ -210,64 +237,64 @@ msgstr ""
"erreur inattendue \"{0}\" dans la fonction \"{1}\" avec les arguments "
"\"{3}\" et \"{4}\" pour l'option {2}"
#: tiramisu/autolib.py:915
#: tiramisu/autolib.py:928
msgid "unexpected error \"{0}\" in function \"{1}\" for option {2}"
msgstr "erreur inattendue \"{0}\" dans la fonction \"{1}\" pour l'option {2}"
#: tiramisu/config.py:419
#: tiramisu/config.py:420
msgid ""
"index \"{0}\" is greater than the leadership length \"{1}\" for option {2}"
msgstr ""
"l'index \"{0}\" est supérieur à la longueur de la leadership \"{1}\" pour "
"l'option {2}"
#: tiramisu/config.py:579
#: tiramisu/config.py:580
msgid "there is no option description for this config (may be GroupConfig)"
msgstr ""
"il n'y a pas d'option description trouvé pour cette config (peut être un "
"GroupConfig)"
#: tiramisu/config.py:668
#: tiramisu/config.py:669
msgid "no option found in config with these criteria"
msgstr "aucune option trouvée dans la config avec ces critères"
#: tiramisu/config.py:871
#: tiramisu/config.py:872
msgid ""
"the follower option {0} has greater length ({1}) than the leader length ({2})"
msgstr ""
"l'option suiveuse {0} a une longueur supérieur ({1}) à la longueur de "
"l'option leader ({2})"
#: tiramisu/config.py:982 tiramisu/option/optiondescription.py:74
#: tiramisu/config.py:983 tiramisu/option/optiondescription.py:74
msgid "option description seems to be part of an other config"
msgstr "l'option description semble faire parti d'une autre config"
#: tiramisu/config.py:1144
#: tiramisu/config.py:1145
msgid "parent of {0} not already exists"
msgstr "le parent de {0} n'existe plus"
#: tiramisu/config.py:1191
#: tiramisu/config.py:1192
msgid "cannot set leadership object has root optiondescription"
msgstr "ne peut assigner un objet leadership comme optiondescription racine"
#: tiramisu/config.py:1194
#: tiramisu/config.py:1195
msgid "cannot set dynoptiondescription object has root optiondescription"
msgstr ""
"ne peut assigner un objet dynoptiondescription comme optiondescription racine"
#: tiramisu/config.py:1246
#: tiramisu/config.py:1247
msgid "config name must be uniq in groupconfig for \"{0}\""
msgstr "le nom d'un config doit être unique dans un groupconfig pour \"{0}\""
#: tiramisu/config.py:1457
#: tiramisu/config.py:1458
msgid "unknown config \"{}\""
msgstr "config \"{}\" inconnue"
#: tiramisu/config.py:1482
#: tiramisu/config.py:1483
msgid "child must be a Config, MixConfig or MetaConfig"
msgstr "l'enfant doit être une Config, MixConfig ou MetaConfig"
#: tiramisu/config.py:1517
#: tiramisu/config.py:1518
msgid ""
"force_default, force_default_if_same or force_dont_change_value cannot be "
"set with only_config"
@ -275,43 +302,43 @@ msgstr ""
"force_default, force_default_if_same ou force_dont_change_value ne peuvent "
"pas être spécifié avec only_config"
#: tiramisu/config.py:1527
#: tiramisu/config.py:1528
msgid "force_default and force_dont_change_value cannot be set together"
msgstr ""
"force_default et force_dont_change_value ne peuvent pas être mis ensemble"
#: tiramisu/config.py:1676
#: tiramisu/config.py:1677
msgid "config name must be uniq in groupconfig for {0}"
msgstr "le nom de la config doit être unique dans un groupconfig pour {0}"
#: tiramisu/config.py:1721
#: tiramisu/config.py:1722
msgid "config added has no name, the name is mandatory"
msgstr "la config ajoutée n'a pas de nom, le nom est obligatoire"
#: tiramisu/config.py:1726
#: tiramisu/config.py:1727
msgid "config name \"{0}\" is not uniq in groupconfig \"{1}\""
msgstr ""
"le nom d'un config \"{0}\" n'est pas unique dans le groupconfig \"{1}\""
#: tiramisu/config.py:1744 tiramisu/config.py:1750
#: tiramisu/config.py:1745 tiramisu/config.py:1751
msgid "cannot find the config {0}"
msgstr "ne peut pas trouver la config {0}"
#: tiramisu/config.py:1776
#: tiramisu/config.py:1777
msgid "MetaConfig with optiondescription must have string has child, not {}"
msgstr ""
"MetaConfig avec une optiondescription doit avoir un nom comme enfant, pas {}"
#: tiramisu/config.py:1788
#: tiramisu/config.py:1789
msgid "child must be a Config or MetaConfig"
msgstr "enfant doit être une une Config ou une MetaConfig"
#: tiramisu/config.py:1793
#: tiramisu/config.py:1794
msgid "all config in metaconfig must have the same optiondescription"
msgstr ""
"toutes les configs d'une metaconfig doivent avoir la même optiondescription"
#: tiramisu/config.py:1810
#: tiramisu/config.py:1811
msgid "metaconfig must have the same optiondescription"
msgstr "metaconfig doivent avoir la même optiondescription"
@ -1107,9 +1134,6 @@ msgstr "l'information de l'objet ne sont pas trouvé \"{}\""
#~ msgstr ""
#~ "seuls les caractères en minuscule, les nombres et \"-\" sont recommandés"
#~ msgid "cannot set symlinkoption in a dynoptiondescription"
#~ msgstr "ne peut mettre une symlinkoption dans une dynoptiondescription"
#~ msgid "callback is mandatory for the dynoptiondescription \"{}\""
#~ msgstr "un callback est obligatoire pour le dynoptiondescription \"{}\""
@ -1191,9 +1215,6 @@ msgstr "l'information de l'objet ne sont pas trouvé \"{}\""
#~ msgid "IP \"{0}\" (\"{1}\") is the broadcast"
#~ msgstr "IP \"{0}\" (\"{1}\") est l'adresse de broadcast"
#~ msgid "unique must be a boolean, not \"{}\""
#~ msgstr "unique doit être un booléan, pas \"{}\""
#~ msgid "unique must be set only with multi value"
#~ msgstr "unique doit être activé uniquement avec une valeur multiple"

View file

@ -5,7 +5,7 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2024-11-05 08:52+0100\n"
"POT-Creation-Date: 2024-11-25 08:29+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -103,7 +103,7 @@ msgstr ""
msgid "unknown when {} (must be in append or remove)"
msgstr ""
#: tiramisu/api.py:1424 tiramisu/api.py:1448 tiramisu/config.py:1680
#: tiramisu/api.py:1424 tiramisu/api.py:1448 tiramisu/config.py:1681
msgid "unknown type {}"
msgstr ""
@ -135,6 +135,22 @@ msgstr ""
msgid "param must have a boolean not a {} for raisepropertyerror"
msgstr ""
#: tiramisu/autolib.py:151
msgid "identifiers in ParamDynOption must be a list, not {0}"
msgstr ""
#: tiramisu/autolib.py:155
msgid "optional in ParamDynOption must be a boolean, not {0}"
msgstr ""
#: tiramisu/autolib.py:206
msgid "cannot add option in information after creating config"
msgstr ""
#: tiramisu/autolib.py:208
msgid "cannot redefine option in information"
msgstr ""
#: tiramisu/autolib.py:212
msgid "option in ParamInformation cannot be a symlinkoption"
msgstr ""
@ -171,103 +187,107 @@ msgstr ""
msgid "option {0} is not a dynoptiondescription or in a dynoptiondescription"
msgstr ""
#: tiramisu/autolib.py:848
#: tiramisu/autolib.py:682
msgid "cannot calculate arguments for \"{0}\", cannot find dynamic variable \"{1}\""
msgstr ""
#: tiramisu/autolib.py:861
msgid "the \"{}\" function with positional arguments \"{}\" and keyword arguments \"{}\" must not return a list (\"{}\") for the follower option {}"
msgstr ""
#: tiramisu/autolib.py:863
#: tiramisu/autolib.py:876
msgid "the \"{}\" function must not return a list (\"{}\") for the follower option {}"
msgstr ""
#: tiramisu/autolib.py:904
#: tiramisu/autolib.py:917
msgid "unexpected error \"{0}\" in function \"{1}\" with arguments \"{3}\" and \"{4}\" for option {2}"
msgstr ""
#: tiramisu/autolib.py:915
#: tiramisu/autolib.py:928
msgid "unexpected error \"{0}\" in function \"{1}\" for option {2}"
msgstr ""
#: tiramisu/config.py:419
#: tiramisu/config.py:420
msgid "index \"{0}\" is greater than the leadership length \"{1}\" for option {2}"
msgstr ""
#: tiramisu/config.py:579
#: tiramisu/config.py:580
msgid "there is no option description for this config (may be GroupConfig)"
msgstr ""
#: tiramisu/config.py:668
#: tiramisu/config.py:669
msgid "no option found in config with these criteria"
msgstr ""
#: tiramisu/config.py:871
#: tiramisu/config.py:872
msgid "the follower option {0} has greater length ({1}) than the leader length ({2})"
msgstr ""
#: tiramisu/config.py:982 tiramisu/option/optiondescription.py:74
#: tiramisu/config.py:983 tiramisu/option/optiondescription.py:74
msgid "option description seems to be part of an other config"
msgstr ""
#: tiramisu/config.py:1144
#: tiramisu/config.py:1145
msgid "parent of {0} not already exists"
msgstr ""
#: tiramisu/config.py:1191
#: tiramisu/config.py:1192
msgid "cannot set leadership object has root optiondescription"
msgstr ""
#: tiramisu/config.py:1194
#: tiramisu/config.py:1195
msgid "cannot set dynoptiondescription object has root optiondescription"
msgstr ""
#: tiramisu/config.py:1246
#: tiramisu/config.py:1247
msgid "config name must be uniq in groupconfig for \"{0}\""
msgstr ""
#: tiramisu/config.py:1457
#: tiramisu/config.py:1458
msgid "unknown config \"{}\""
msgstr ""
#: tiramisu/config.py:1482
#: tiramisu/config.py:1483
msgid "child must be a Config, MixConfig or MetaConfig"
msgstr ""
#: tiramisu/config.py:1517
#: tiramisu/config.py:1518
msgid "force_default, force_default_if_same or force_dont_change_value cannot be set with only_config"
msgstr ""
#: tiramisu/config.py:1527
#: tiramisu/config.py:1528
msgid "force_default and force_dont_change_value cannot be set together"
msgstr ""
#: tiramisu/config.py:1676
#: tiramisu/config.py:1677
msgid "config name must be uniq in groupconfig for {0}"
msgstr ""
#: tiramisu/config.py:1721
#: tiramisu/config.py:1722
msgid "config added has no name, the name is mandatory"
msgstr ""
#: tiramisu/config.py:1726
#: tiramisu/config.py:1727
msgid "config name \"{0}\" is not uniq in groupconfig \"{1}\""
msgstr ""
#: tiramisu/config.py:1744 tiramisu/config.py:1750
#: tiramisu/config.py:1745 tiramisu/config.py:1751
msgid "cannot find the config {0}"
msgstr ""
#: tiramisu/config.py:1776
#: tiramisu/config.py:1777
msgid "MetaConfig with optiondescription must have string has child, not {}"
msgstr ""
#: tiramisu/config.py:1788
#: tiramisu/config.py:1789
msgid "child must be a Config or MetaConfig"
msgstr ""
#: tiramisu/config.py:1793
#: tiramisu/config.py:1794
msgid "all config in metaconfig must have the same optiondescription"
msgstr ""
#: tiramisu/config.py:1810
#: tiramisu/config.py:1811
msgid "metaconfig must have the same optiondescription"
msgstr ""

View file

@ -432,6 +432,20 @@ def test_callback_dyndescription_outside3():
assert parse_od_get(cfg.value.get()) == {'od.out': 'val1', 'lst': ['val1', 'val2']}
def test_callback_dyndescription_outside_optional():
lst = StrOption('lst', '', ['val'], multi=True)
st = StrOption('st', '', 'val')
dod = DynOptionDescription('dod', '', [st], identifiers=Calculation(return_list, Params(ParamOption(lst))))
out = StrOption('out', '', Calculation(calc_value, Params(ParamDynOption(st, ['unknown_val'], optional=True))))
od = OptionDescription('od', '', [dod, out])
od2 = OptionDescription('od', '', [od, lst])
cfg = Config(od2)
assert parse_od_get(cfg.value.get()) == {'od.dodval.st': 'val', 'od.out': None, 'lst': ['val']}
cfg.option('lst').value.set(['val', 'unknown_val'])
assert parse_od_get(cfg.value.get()) == {'od.dodval.st': 'val', 'od.dodunknown_val.st': 'val', 'od.out': 'val', 'lst': ['val', 'unknown_val']}
# assert not list_sessions()
def test_callback_dyndescription_subdyn():
lst = StrOption('lst', '', ['val1', 'val2'], multi=True)
st = StrOption('st', '', 'val1')

View file

@ -22,7 +22,7 @@ from typing import Any, Optional, Union, Callable, Dict, List
from itertools import chain
import weakref
from .error import PropertiesOptionError, ConfigError, LeadershipError, ValueWarning
from .error import PropertiesOptionError, ConfigError, LeadershipError, ValueWarning, CancelParam
from .i18n import _
from .setting import undefined, ConfigBag
from .function import FUNCTION_WAITING_FOR_DICT, FUNCTION_WAITING_FOR_ERROR
@ -148,11 +148,11 @@ class ParamDynOption(ParamOption):
)
if not isinstance(identifiers, list):
raise Exception(
f"identifiers in ParamDynOption must be a list, not {identifiers}"
_("identifiers in ParamDynOption must be a list, not {0}").format(identifiers)
)
if not isinstance(optional, bool):
raise Exception(
f"optional in ParamDynOption must be a boolean, not {optional}"
_("optional in ParamDynOption must be a boolean, not {0}").format(optional)
)
self.identifiers = identifiers
self.optional = optional
@ -203,9 +203,9 @@ class ParamInformation(Param):
def set_option(self, option: "Option" = None) -> None:
if not hasattr(self, "self_option"):
raise ConfigError("cannot add option in information after creating config")
raise ConfigError(_("cannot add option in information after creating config"))
if self.option:
raise ConfigError("cannot redefine option in information")
raise ConfigError(_("cannot redefine option in information"))
if not option.impl_is_optiondescription():
if option.impl_is_symlinkoption():
raise ValueError(
@ -464,7 +464,7 @@ def manager_callback(
) from err
except AttributeError as err:
if isinstance(param, ParamDynOption) and param.optional:
# cannot acces, simulate a propertyerror
# cannot access, simulate a propertyerror
raise PropertiesOptionError(
subconfig,
["configerror"],
@ -524,7 +524,7 @@ def manager_callback(
) from err
except AttributeError as err:
if isinstance(param, ParamDynOption) and param.optional:
# cannot acces, simulate a propertyerror
# cannot access, simulate a propertyerror
raise PropertiesOptionError(
param,
["configerror"],
@ -673,7 +673,14 @@ def manager_callback(
parent,
)
except AttributeError as err:
raise ConfigError(err) from err
if parent.path:
child_path = parent.path + '.' + name
else:
child_path = name
if param.optional:
raise CancelParam(callbk_option.impl_getpath(), child_path)
msg = _('cannot calculate arguments for "{0}", cannot find dynamic variable "{1}"').format(subconfig.path, child_path)
raise ConfigError(msg) from err
new_parents.append(
parent.get_child(
doption,
@ -828,6 +835,12 @@ def carry_out_calculation(
args.append(err)
else:
kwargs[key] = err
except CancelParam as err:
if callback.__name__ in FUNCTION_WAITING_FOR_ERROR:
if key is None:
args.append(err)
else:
kwargs[key] = err
ret = calculate(
subconfig,
callback,

View file

@ -227,7 +227,8 @@ class SubConfig:
identifiers: Optional[list[str]],
*,
true_path: Optional[str] = None,
properties: Union[list[str], undefined] = undefined,
# for python 3.9 properties: Union[list[str], undefined] = undefined,
properties = undefined,
validate_properties: bool = True,
) -> None:
self.index = index

View file

@ -227,3 +227,10 @@ class ValueErrorWarning(ValueWarning):
if ValueErrorWarning.tmpl is None:
ValueErrorWarning.tmpl = _('"{0}" is an invalid {1} for "{2}"')
super().__init__(*args, **kwargs)
class CancelParam(Exception):
def __init__(self, origin_path, current_path):
super().__init__()
self.origin_path = origin_path
self.current_path = current_path