From 62097b552aa4c5a81d341017a9fbf52bb693e3f4 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Thu, 3 Apr 2025 20:47:12 +0200 Subject: [PATCH] feat: reoganise param conversion + better variable validation --- locale/fr/LC_MESSAGES/rougail.po | 296 +++++++++++++++--- locale/rougail.pot | 212 ++++++++++--- src/rougail/annotator/value.py | 4 +- src/rougail/locale/fr/LC_MESSAGES/rougail.mo | Bin 7517 -> 13318 bytes src/rougail/object_model.py | 160 +++++----- src/rougail/tiramisureflector.py | 94 +++--- .../tiramisu/base.py | 2 +- .../makedict/after.json | 10 + .../makedict/base.json | 4 + .../makedict/before.json | 10 + .../makedict/mandatory.json | 1 + .../tiramisu/base.py | 18 ++ .../tiramisu/no_namespace.py | 13 + .../errno_67 | 0 .../rougail/00-rougail.yml | 10 + tests/test_1_flattener.py | 2 +- 16 files changed, 628 insertions(+), 208 deletions(-) create mode 100644 tests/dictionaries/60_5family_dynamic_calc_suffix_disabled2/makedict/after.json create mode 100644 tests/dictionaries/60_5family_dynamic_calc_suffix_disabled2/makedict/base.json create mode 100644 tests/dictionaries/60_5family_dynamic_calc_suffix_disabled2/makedict/before.json create mode 100644 tests/dictionaries/60_5family_dynamic_calc_suffix_disabled2/makedict/mandatory.json create mode 100644 tests/dictionaries/60_5family_dynamic_calc_suffix_disabled2/tiramisu/base.py create mode 100644 tests/dictionaries/60_5family_dynamic_calc_suffix_disabled2/tiramisu/no_namespace.py create mode 100644 tests/errors/20_test_default_variable_incompatible/errno_67 create mode 100644 tests/errors/20_test_default_variable_incompatible/rougail/00-rougail.yml diff --git a/locale/fr/LC_MESSAGES/rougail.po b/locale/fr/LC_MESSAGES/rougail.po index 31534c830..65ef8b76c 100644 --- a/locale/fr/LC_MESSAGES/rougail.po +++ b/locale/fr/LC_MESSAGES/rougail.po @@ -5,8 +5,8 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"POT-Creation-Date: 2025-02-17 09:16+0100\n" -"PO-Revision-Date: 2025-02-17 09:17+0100\n" +"POT-Creation-Date: 2025-04-03 20:44+0200\n" +"PO-Revision-Date: 2025-04-03 20:46+0200\n" "Last-Translator: \n" "Language-Team: \n" "Language: fr\n" @@ -16,31 +16,31 @@ msgstr "" "Generated-By: pygettext.py 1.5\n" "X-Generator: Poedit 3.5\n" -#: src/rougail/annotator/family.py:147 +#: src/rougail/annotator/family.py:149 msgid "default variable mode \"{0}\" is not a valid mode, valid modes are {1}" msgstr "" "le mode d'une variable par défaut \"{0}\" n'est pas un mode valide, les " "modes valides sont {1}" -#: src/rougail/annotator/family.py:153 +#: src/rougail/annotator/family.py:155 msgid "default family mode \"{0}\" is not a valid mode, valid modes are {1}" msgstr "" "le mode d'une famille par défaut \"{0}\" n'est pas un mode valide, les modes " "valides sont {1}" -#: src/rougail/annotator/family.py:185 +#: src/rougail/annotator/family.py:187 msgid "mode \"{0}\" for \"{1}\" is not a valid mode, valid modes are {2}" msgstr "" "le mode \"{0}\" pour \"{1}\" n'est pas un mode valide, les modes valides " "sont {2}" -#: src/rougail/annotator/family.py:189 +#: src/rougail/annotator/family.py:191 msgid "mode \"{0}\" for \"{1}\" is not a valid mode, no modes are available" msgstr "" "le mode \"{0}\" pour \"{1}\" n'est pas un mode valide, aucun mode ne sont " "définis" -#: src/rougail/annotator/family.py:253 +#: src/rougail/annotator/family.py:255 msgid "" "the variable \"{0}\" is mandatory so in \"{1}\" mode but family has the " "higher family mode \"{2}\"" @@ -48,7 +48,7 @@ msgstr "" "la variable \"{0}\" est obligatoire, donc en mode \"{1}\", mais la famille a " "un mode supérieur \"{2}\"" -#: src/rougail/annotator/family.py:291 +#: src/rougail/annotator/family.py:293 msgid "" "the follower \"{0}\" is in \"{1}\" mode but leader have the higher mode " "\"{2}\"" @@ -56,7 +56,7 @@ msgstr "" "la variable suiveuse \"{0}\" a le mode \"{1}\" mais la variable leader a un " "mode supérieur \"{2}\"" -#: src/rougail/annotator/family.py:324 +#: src/rougail/annotator/family.py:326 msgid "" "the family \"{0}\" is in \"{1}\" mode but variables and families inside have " "the higher modes \"{2}\"" @@ -64,7 +64,7 @@ msgstr "" "la famille \"{0}\" a le mode \"{1}\" mais les variables et les familles à " "l'intérieur ont des modes supérieurs \"{2}\"" -#: src/rougail/annotator/family.py:342 +#: src/rougail/annotator/family.py:344 msgid "" "the variable \"{0}\" is in \"{1}\" mode but family has the higher family " "mode \"{2}\"" @@ -72,123 +72,167 @@ msgstr "" "la variable \"{0}\" est dans le mode \"{1}\" mais la famille a le mode " "supérieur \"{2}\"" -#: src/rougail/annotator/value.py:77 +#: src/rougail/annotator/value.py:78 msgid "the follower \"{0}\" without multi attribute can only have one value" msgstr "" "la variable suiveuse \"{0}\" sans l'attribut multi peut avoir seulement une " "valeur" -#: src/rougail/annotator/value.py:93 +#: src/rougail/annotator/value.py:94 msgid "the variable \"{0}\" is multi but has a non list default value" msgstr "" "la variable \"{0}\" est multiple mais a une valeur par défaut sans être une " "liste" -#: src/rougail/annotator/variable.py:175 +#: src/rougail/annotator/value.py:118 +msgid "the variable \"{0}\" is a \"choice\" variable but don't have any choice" +msgstr "la variable \"{0}\" a une variable à \"choix\" mais n'a aucun choix" + +#: src/rougail/annotator/value.py:135 +msgid "the variable \"{0}\" is a \"regexp\" variable but don't have any regexp" +msgstr "" +"la variable \"{0}\" a une variable \"regexp\" mais n'a pas de \"regexp\"" + +#: src/rougail/annotator/variable.py:85 +msgid "" +"only \"unix_user\" or \"secret\" variable type can have \"secret_manager\" " +"attribute, but \"{0}\" has type \"{1}\"" +msgstr "" +"seul une variable de type \"unix_user\" ou \"secret\" peut avoir l'attribut " +"\"secret_manager\", mais \"{0}\" a le type \"{1}\"" + +#: src/rougail/annotator/variable.py:88 +msgid "" +"the variable \"{0}\" has attribute \"secret_manager\" but is a multi variable" +msgstr "" +"la variable \"{0}\" a l'attribut \"secret_manager\" mais est une variable " +"multiple" + +#: src/rougail/annotator/variable.py:91 +msgid "" +"the variable \"{0}\" has attribute \"secret_manager\" so must not have " +"default value" +msgstr "" +"la variable \"{0}\" a l'attribut \"secret_manager\" donc ne devrait pas " +"avoir de valeur par défaut" + +#: src/rougail/annotator/variable.py:197 msgid "" "the variable \"{0}\" has regexp attribut but has not the \"regexp\" type" msgstr "" "la variable \"{0}\" a un attribut regexp mais n'a pas le type \"regexp\"" -#: src/rougail/annotator/variable.py:218 +#: src/rougail/annotator/variable.py:240 msgid "" "the variable \"{0}\" has choices attribut but has not the \"choice\" type" msgstr "" "la variable \"{0}\" a un attribut choices mais n'a pas le type \"choice\"" -#: src/rougail/annotator/variable.py:246 +#: src/rougail/annotator/variable.py:268 msgid "" "the variable \"{0}\" has an unvalid default value \"{1}\" should be in {2}" msgstr "" "la variable \"{0}\" a la valeur par défaut invalide \"{1}\" devrait être {2}" -#: src/rougail/config.py:231 +#: src/rougail/config.py:234 msgid "File with functions" msgstr "Fichier avec les fonctions" -#: src/rougail/config.py:243 +#: src/rougail/config.py:246 msgid "All modes level available" msgstr "Tous les niveaux de modes valides" -#: src/rougail/config.py:255 +#: src/rougail/config.py:258 msgid "Default mode for a family" msgstr "Mode par défaut pour une famille" -#: src/rougail/config.py:275 +#: src/rougail/config.py:278 msgid "Default mode for a variable" msgstr "Mode par défaut pour une variable" -#: src/rougail/config.py:299 +#: src/rougail/config.py:302 msgid "Option name for the base option" msgstr "Nom de l'option pour l'option de base" -#: src/rougail/config.py:304 +#: src/rougail/config.py:307 msgid "In cache file, do not importation of Tiramisu and other dependencies" msgstr "" "Dans le fichier de cache, ne pas importer Tiramisu et autres dépendances" -#: src/rougail/config.py:305 +#: src/rougail/config.py:308 msgid "In cache file, do importation of Tiramisu and other dependencies" msgstr "Dans le fichier de cache, importer Tiramisu et autres dépendances" -#: src/rougail/config.py:310 +#: src/rougail/config.py:313 msgid "Tiramisu cache filename" msgstr "Nom du fichier du cache Tiramisu" -#: src/rougail/config.py:318 +#: src/rougail/config.py:321 msgid "Name of internal functions that we can use as a function" msgstr "" "Nom des fonctions internes qu'il est possible d'utiliser comme fonction" -#: src/rougail/config.py:324 +#: src/rougail/config.py:327 msgid "Name of extra annotators" msgstr "Nom des annotators supplémentaires" -#: src/rougail/config.py:330 +#: src/rougail/config.py:333 msgid "Suffix add to generated options name" msgstr "Suffix ajouté pour généré le nom des options" -#: src/rougail/config.py:336 +#: src/rougail/config.py:339 msgid "Every variables in calculation are optionals" msgstr "Toutes les variables dans un calcul sont optionnelles" -#: src/rougail/config.py:337 +#: src/rougail/config.py:340 msgid "Variables in calculation are not optional by default" msgstr "Les variables dans un calcul sont optionnelles par défaut" -#: src/rougail/config.py:341 src/rougail/config.py:342 +#: src/rougail/config.py:344 src/rougail/config.py:345 msgid "Loads redefine variables even if there don't already exists" msgstr "Charger les variables redéfinis même si elles n'existe pas" -#: src/rougail/config.py:443 +#: src/rougail/config.py:352 +msgid "The secret pattern to build item name in Bitwarden" +msgstr "Le patron de secret pour construire le nom de l'élément dans Bitwarden" + +#: src/rougail/config.py:353 +msgid "The pattern is in Jinja format" +msgstr "Le patron est au format Jinja" + +#: src/rougail/config.py:461 msgid "Default parameters for option type" msgstr "Paramètre par défaut pour le type d'option" -#: src/rougail/convert.py:270 +#: src/rougail/convert.py:281 msgid "unknown type {0} for {1}" msgstr "type {0} inconnu pour {1}" -#: src/rougail/convert.py:402 +#: src/rougail/convert.py:413 msgid "family \"{0}\" define multiple time" msgstr "la famille \"{0}\" est définit plusieurs fois" -#: src/rougail/convert.py:658 +#: src/rougail/convert.py:681 msgid "variable \"{0}\" define multiple time" msgstr "la variable \"{0}\" est définit plusieurs fois" -#: src/rougail/convert.py:761 +#: src/rougail/convert.py:787 msgid "params must be a dict for {0}" msgstr "params doit être une dict pour {0}" -#: src/rougail/convert.py:782 +#: src/rougail/convert.py:809 msgid "\"{0}\" has an invalid \"params\" for {1}: {2}" msgstr "\"{0}\" a un attribut \"params\" invalide pour {1}: {2}" -#: src/rougail/convert.py:1096 +#: src/rougail/convert.py:823 +msgid "secret_manager must be a dict for {0}" +msgstr "secret_manager doit être une dict pour {0}" + +#: src/rougail/convert.py:1154 msgid "Cannot execute annotate multiple time" msgstr "Ne peut exécuter l'annotation plusieurs fois" -#: src/rougail/convert.py:1103 +#: src/rougail/convert.py:1161 msgid "" "invalid \"structural\" definition ({0}), we cannot load any structural file!" msgstr "" @@ -199,7 +243,169 @@ msgstr "" msgid "{0} in {1}" msgstr "{0} dans {1}" -#: src/rougail/path.py:209 +#: src/rougail/object_model.py:50 +msgid "unknown boolean value \"{0}\"" +msgstr "valeur du booléen inconnue \"{0}\"" + +#: src/rougail/object_model.py:182 +msgid "cannot find variable \"{0}\" defined in attribute \"{1}\" for \"{2}\"" +msgstr "" +"ne peut trouver la variable \"{0}\" défini dans l'attribut \"{1}\" pour " +"\"{2}\"" + +#: src/rougail/object_model.py:186 +msgid "" +"the variable \"{0}\" is in fact a family in attribute \"{1}\" for \"{2}\"" +msgstr "" +"la variable \"{0}\" est en faite une famille dans l'attribut \"{1}\" pour " +"\"{2}\"" + +#: src/rougail/object_model.py:189 src/rougail/object_model.py:473 +msgid "unknown object \"{0}\" in attribute \"{1}\" for \"{2}\"" +msgstr "objet inconnu \"{0}\" dans l'attribut \"{1}\" pour \"{2}\"" + +#: src/rougail/object_model.py:206 +msgid "" +"identifier parameter for \"{0}\" in \"{1}\" cannot be set none dynamic family" +msgstr "" +"le paramètre identifier pour \"{0}\" dans \"{1}\" ne peut être placé pour " +"une famille non dynamique" + +#: src/rougail/object_model.py:229 +msgid "cannot find variable \"{0}\" defined in \"{1}\" for \"{2}\"" +msgstr "ne peut trouve la variable \"{0}\" défini dans \"{1}\" pour \"{2}\"" + +#: src/rougail/object_model.py:232 +msgid "variable \"{0}\" defined in \"{1}\" for \"{2}\" is a dynamic variable" +msgstr "" +"la variable \"{0}\" défini dans \"{1}\" pour \"{2}\" est une variable " +"dynamique" + +#: src/rougail/object_model.py:246 +msgid "" +"the variable \"{0}\" is not a follower, so cannot have index type for param " +"in \"{1}\"" +msgstr "" +"la variable \"{0}\" n'est pas suiveuse, donc ne peut avoir de type index " +"comme paramètre dans \"{1}\"" + +#: src/rougail/object_model.py:470 +msgid "" +"a variable \"{0}\" is needs in attribute \"{1}\" for \"{2}\" but it's a " +"family" +msgstr "" +"une variable \"{0}\" est nécessaire pour l'attribut \"{1}\" pour \"{2}\" " +"mais c'est une famille" + +#: src/rougail/object_model.py:491 +msgid "Variable not found \"{0}\" for attribut \"{1}\" in variable \"{2}\"" +msgstr "" +"La variable \"{0}\" n'est pas trouvé pour l'attribut \"{1}\" dans la " +"variable \"{2}\"" + +#: src/rougail/object_model.py:533 +msgid "" +"the variable \"{0}\" has an invalid attribute \"{1}\", the variable \"{2}\" " +"is multi but is inside a list" +msgstr "" +"la variable \"{0}\" a un attribut invalide \"{1}\", la variable \"{2}\" est " +"multiple mais est dans une liste" + +#: src/rougail/object_model.py:536 +msgid "" +"the variable \"{0}\" has an invalid attribute \"{1}\", the variable \"{2}\" " +"is not multi but is not inside a list" +msgstr "" +"la variable \"{0}\" a un attribut invalide \"{1}\", la variable \"{2}\" " +"n'est pas multiple mais n'est pas dans une liste" + +#: src/rougail/object_model.py:539 +msgid "the variable \"{0}\" has an invalid attribute \"{1}\", it's a list" +msgstr "la variable \"{0}\" a un attribut invalide \"{1}\", c'est une liste" + +#: src/rougail/object_model.py:548 +msgid "" +"the variable \"{0}\" has an invalid attribute \"{1}\", the variable \"{2}\" " +"is a multi" +msgstr "" +"la variable \"{0}\" a un attribut invalide \"{1}\", la variable \"{2}\" est " +"multiple" + +#: src/rougail/object_model.py:570 +msgid "" +"\"{0}\" attribut shall not have an \"optional\" attribute for variable " +"\"{1}\"" +msgstr "" +"l'attribut \"{0}\" ne devrait pas avoir d'attribut \"optional\" pour la " +"variable \"{1}\"" + +#: src/rougail/object_model.py:582 +msgid "" +"variable \"{0}\" has a default variable calculated with \"{1}\" which has " +"incompatible type" +msgstr "" +"la variable \"{0}\" a une valeur par défaut calculé a partir de \"{1}\" " +"laquelle a un type incompatible" + +#: src/rougail/object_model.py:618 +msgid "" +"\"when\" is not allowed in format version 1.0 for attribute \"{0}\" for " +"variable \"{1}\"" +msgstr "" +"\"when\" n'est pas autorisé avec le format en version 1.0 pour l'attribut " +"\"{0}\" pour la variable \"{1}\"" + +#: src/rougail/object_model.py:621 +msgid "" +"the variable \"{0}\" has an invalid attribute \"{1}\", \"when\" and " +"\"when_not\" cannot set together" +msgstr "" +"la variable \"{0}\" a un attribut invalide \"{1}\", \"when\" et \"when_not\" " +"ne peuvent pas être défini ensemble" + +#: src/rougail/object_model.py:627 +msgid "" +"\"when_not\" is not allowed in format version 1.0 for attribute \"{0}\" for " +"variable \"{1}\"" +msgstr "" +"\"when_not\" n'est pas autorisé au format 1.0 pour l'attribut \"{0}\" pour " +"la variable variable \"{1}\"" + +#: src/rougail/object_model.py:680 +msgid "" +"cannot find variable \"{0}\" for the information \"{1}\" when calculating " +"\"{2}\"" +msgstr "" +"ne peut trouver la variable \"{0}\" pour l'information \"{1}\" lors du " +"calcul de \"{2}\"" + +#: src/rougail/object_model.py:683 +msgid "" +"identifier not allowed for the information \"{0}\" when calculating \"{1}\"" +msgstr "" +"identifier n'est pas autorisé pour l'information \"{0}\" lors du calcul de " +"\"{1}\"" + +#: src/rougail/object_model.py:732 +msgid "\"when\" is not allowed in format version 1.0 for attribute \"{0}\"" +msgstr "\"when\" n'est pas autorisé au format 1.0 pour l'attribut \"{0}\"" + +#: src/rougail/object_model.py:736 src/rougail/object_model.py:744 +msgid "" +"the identifier has an invalid attribute \"{0}\", \"when\" and \"when_not\" " +"cannot set together" +msgstr "" +"l'identifiant a un attribut invalide \"{0}\", \"when\" et \"when_not\" ne " +"peuvent pas être défini ensemble" + +#: src/rougail/object_model.py:766 +msgid "" +"the variable \"{0}\" is not a follower, so cannot have index type for \"{1}\"" +msgstr "" +"la variable \"{0}\" n'est pas suiveuse, donc ne peut avoir de type index " +"pour \"{1}\"" + +#: src/rougail/path.py:206 msgid "" "A variable or a family located in the \"{0}\" namespace shall not be used in " "the \"{1}\" namespace" @@ -260,17 +466,25 @@ msgstr "" "Répertoires où sont placés les fichiers de structure de l'espace de nom " "supplémentaire" -#: src/rougail/tiramisureflector.py:376 +#: src/rougail/tiramisu.py:167 +msgid "" +"cannot calculating \"{0}\" attribute for variable \"{1}\" in {2} with " +"parameters \"{3}\": {4}" +msgstr "" +"ne peut calculer l'attribut \"{0}\" pour la variable \"{1}\" dans {2} avec " +"les paramètres \"{3}\" : {4}" + +#: src/rougail/tiramisureflector.py:369 msgid "internal error, {0} is not a dynamic variable" msgstr "erreur interne, \"{0}\" n'est pas une variable dynamique" -#: src/rougail/user_datas.py:155 +#: src/rougail/user_datas.py:164 msgid "the variable \"{0}\" contains secrets and should not be defined in {1}" msgstr "" "la variable \"{0}\" contient des secrets et ne devrait pas être défini dans " "{1}" -#: src/rougail/user_datas.py:215 +#: src/rougail/user_datas.py:227 msgid "the option \"{0}\" is an option description" msgstr "l'option \"{0}\" est une option description" diff --git a/locale/rougail.pot b/locale/rougail.pot index 6285637b4..c5fc06b80 100644 --- a/locale/rougail.pot +++ b/locale/rougail.pot @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" -"POT-Creation-Date: 2025-02-17 09:18+0100\n" +"POT-Creation-Date: 2025-04-03 20:46+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -15,143 +15,175 @@ msgstr "" "Generated-By: pygettext.py 1.5\n" -#: src/rougail/annotator/family.py:147 +#: src/rougail/annotator/family.py:149 msgid "default variable mode \"{0}\" is not a valid mode, valid modes are {1}" msgstr "" -#: src/rougail/annotator/family.py:153 +#: src/rougail/annotator/family.py:155 msgid "default family mode \"{0}\" is not a valid mode, valid modes are {1}" msgstr "" -#: src/rougail/annotator/family.py:185 +#: src/rougail/annotator/family.py:187 msgid "mode \"{0}\" for \"{1}\" is not a valid mode, valid modes are {2}" msgstr "" -#: src/rougail/annotator/family.py:189 +#: src/rougail/annotator/family.py:191 msgid "mode \"{0}\" for \"{1}\" is not a valid mode, no modes are available" msgstr "" -#: src/rougail/annotator/family.py:253 +#: src/rougail/annotator/family.py:255 msgid "the variable \"{0}\" is mandatory so in \"{1}\" mode but family has the higher family mode \"{2}\"" msgstr "" -#: src/rougail/annotator/family.py:291 +#: src/rougail/annotator/family.py:293 msgid "the follower \"{0}\" is in \"{1}\" mode but leader have the higher mode \"{2}\"" msgstr "" -#: src/rougail/annotator/family.py:324 +#: src/rougail/annotator/family.py:326 msgid "the family \"{0}\" is in \"{1}\" mode but variables and families inside have the higher modes \"{2}\"" msgstr "" -#: src/rougail/annotator/family.py:342 +#: src/rougail/annotator/family.py:344 msgid "the variable \"{0}\" is in \"{1}\" mode but family has the higher family mode \"{2}\"" msgstr "" -#: src/rougail/annotator/value.py:77 +#: src/rougail/annotator/value.py:78 msgid "the follower \"{0}\" without multi attribute can only have one value" msgstr "" -#: src/rougail/annotator/value.py:93 +#: src/rougail/annotator/value.py:94 msgid "the variable \"{0}\" is multi but has a non list default value" msgstr "" -#: src/rougail/annotator/variable.py:175 +#: src/rougail/annotator/value.py:118 +msgid "the variable \"{0}\" is a \"choice\" variable but don't have any choice" +msgstr "" + +#: src/rougail/annotator/value.py:135 +msgid "the variable \"{0}\" is a \"regexp\" variable but don't have any regexp" +msgstr "" + +#: src/rougail/annotator/variable.py:85 +msgid "only \"unix_user\" or \"secret\" variable type can have \"secret_manager\" attribute, but \"{0}\" has type \"{1}\"" +msgstr "" + +#: src/rougail/annotator/variable.py:88 +msgid "the variable \"{0}\" has attribute \"secret_manager\" but is a multi variable" +msgstr "" + +#: src/rougail/annotator/variable.py:91 +msgid "the variable \"{0}\" has attribute \"secret_manager\" so must not have default value" +msgstr "" + +#: src/rougail/annotator/variable.py:197 msgid "the variable \"{0}\" has regexp attribut but has not the \"regexp\" type" msgstr "" -#: src/rougail/annotator/variable.py:218 +#: src/rougail/annotator/variable.py:240 msgid "the variable \"{0}\" has choices attribut but has not the \"choice\" type" msgstr "" -#: src/rougail/annotator/variable.py:246 +#: src/rougail/annotator/variable.py:268 msgid "the variable \"{0}\" has an unvalid default value \"{1}\" should be in {2}" msgstr "" -#: src/rougail/config.py:231 +#: src/rougail/config.py:234 msgid "File with functions" msgstr "" -#: src/rougail/config.py:243 +#: src/rougail/config.py:246 msgid "All modes level available" msgstr "" -#: src/rougail/config.py:255 +#: src/rougail/config.py:258 msgid "Default mode for a family" msgstr "" -#: src/rougail/config.py:275 +#: src/rougail/config.py:278 msgid "Default mode for a variable" msgstr "" -#: src/rougail/config.py:299 +#: src/rougail/config.py:302 msgid "Option name for the base option" msgstr "" -#: src/rougail/config.py:304 +#: src/rougail/config.py:307 msgid "In cache file, do not importation of Tiramisu and other dependencies" msgstr "" -#: src/rougail/config.py:305 +#: src/rougail/config.py:308 msgid "In cache file, do importation of Tiramisu and other dependencies" msgstr "" -#: src/rougail/config.py:310 +#: src/rougail/config.py:313 msgid "Tiramisu cache filename" msgstr "" -#: src/rougail/config.py:318 +#: src/rougail/config.py:321 msgid "Name of internal functions that we can use as a function" msgstr "" -#: src/rougail/config.py:324 +#: src/rougail/config.py:327 msgid "Name of extra annotators" msgstr "" -#: src/rougail/config.py:330 +#: src/rougail/config.py:333 msgid "Suffix add to generated options name" msgstr "" -#: src/rougail/config.py:336 +#: src/rougail/config.py:339 msgid "Every variables in calculation are optionals" msgstr "" -#: src/rougail/config.py:337 +#: src/rougail/config.py:340 msgid "Variables in calculation are not optional by default" msgstr "" -#: src/rougail/config.py:341 src/rougail/config.py:342 +#: src/rougail/config.py:344 src/rougail/config.py:345 msgid "Loads redefine variables even if there don't already exists" msgstr "" -#: src/rougail/config.py:443 +#: src/rougail/config.py:352 +msgid "The secret pattern to build item name in Bitwarden" +msgstr "" + +#: src/rougail/config.py:353 +msgid "The pattern is in Jinja format" +msgstr "" + +#: src/rougail/config.py:461 msgid "Default parameters for option type" msgstr "" -#: src/rougail/convert.py:270 +#: src/rougail/convert.py:281 msgid "unknown type {0} for {1}" msgstr "" -#: src/rougail/convert.py:402 +#: src/rougail/convert.py:413 msgid "family \"{0}\" define multiple time" msgstr "" -#: src/rougail/convert.py:658 +#: src/rougail/convert.py:681 msgid "variable \"{0}\" define multiple time" msgstr "" -#: src/rougail/convert.py:761 +#: src/rougail/convert.py:787 msgid "params must be a dict for {0}" msgstr "" -#: src/rougail/convert.py:782 +#: src/rougail/convert.py:809 msgid "\"{0}\" has an invalid \"params\" for {1}: {2}" msgstr "" -#: src/rougail/convert.py:1096 +#: src/rougail/convert.py:823 +msgid "secret_manager must be a dict for {0}" +msgstr "" + +#: src/rougail/convert.py:1154 msgid "Cannot execute annotate multiple time" msgstr "" -#: src/rougail/convert.py:1103 +#: src/rougail/convert.py:1161 msgid "invalid \"structural\" definition ({0}), we cannot load any structural file!" msgstr "" @@ -159,7 +191,103 @@ msgstr "" msgid "{0} in {1}" msgstr "" -#: src/rougail/path.py:209 +#: src/rougail/object_model.py:50 +msgid "unknown boolean value \"{0}\"" +msgstr "" + +#: src/rougail/object_model.py:182 +msgid "cannot find variable \"{0}\" defined in attribute \"{1}\" for \"{2}\"" +msgstr "" + +#: src/rougail/object_model.py:186 +msgid "the variable \"{0}\" is in fact a family in attribute \"{1}\" for \"{2}\"" +msgstr "" + +#: src/rougail/object_model.py:189 src/rougail/object_model.py:473 +msgid "unknown object \"{0}\" in attribute \"{1}\" for \"{2}\"" +msgstr "" + +#: src/rougail/object_model.py:206 +msgid "identifier parameter for \"{0}\" in \"{1}\" cannot be set none dynamic family" +msgstr "" + +#: src/rougail/object_model.py:229 +msgid "cannot find variable \"{0}\" defined in \"{1}\" for \"{2}\"" +msgstr "" + +#: src/rougail/object_model.py:232 +msgid "variable \"{0}\" defined in \"{1}\" for \"{2}\" is a dynamic variable" +msgstr "" + +#: src/rougail/object_model.py:246 +msgid "the variable \"{0}\" is not a follower, so cannot have index type for param in \"{1}\"" +msgstr "" + +#: src/rougail/object_model.py:470 +msgid "a variable \"{0}\" is needs in attribute \"{1}\" for \"{2}\" but it's a family" +msgstr "" + +#: src/rougail/object_model.py:491 +msgid "Variable not found \"{0}\" for attribut \"{1}\" in variable \"{2}\"" +msgstr "" + +#: src/rougail/object_model.py:533 +msgid "the variable \"{0}\" has an invalid attribute \"{1}\", the variable \"{2}\" is multi but is inside a list" +msgstr "" + +#: src/rougail/object_model.py:536 +msgid "the variable \"{0}\" has an invalid attribute \"{1}\", the variable \"{2}\" is not multi but is not inside a list" +msgstr "" + +#: src/rougail/object_model.py:539 +msgid "the variable \"{0}\" has an invalid attribute \"{1}\", it's a list" +msgstr "" + +#: src/rougail/object_model.py:548 +msgid "the variable \"{0}\" has an invalid attribute \"{1}\", the variable \"{2}\" is a multi" +msgstr "" + +#: src/rougail/object_model.py:570 +msgid "\"{0}\" attribut shall not have an \"optional\" attribute for variable \"{1}\"" +msgstr "" + +#: src/rougail/object_model.py:582 +msgid "variable \"{0}\" has a default value calculated with \"{1}\" which has incompatible type" +msgstr "" + +#: src/rougail/object_model.py:618 +msgid "\"when\" is not allowed in format version 1.0 for attribute \"{0}\" for variable \"{1}\"" +msgstr "" + +#: src/rougail/object_model.py:621 +msgid "the variable \"{0}\" has an invalid attribute \"{1}\", \"when\" and \"when_not\" cannot set together" +msgstr "" + +#: src/rougail/object_model.py:627 +msgid "\"when_not\" is not allowed in format version 1.0 for attribute \"{0}\" for variable \"{1}\"" +msgstr "" + +#: src/rougail/object_model.py:680 +msgid "cannot find variable \"{0}\" for the information \"{1}\" when calculating \"{2}\"" +msgstr "" + +#: src/rougail/object_model.py:683 +msgid "identifier not allowed for the information \"{0}\" when calculating \"{1}\"" +msgstr "" + +#: src/rougail/object_model.py:732 +msgid "\"when\" is not allowed in format version 1.0 for attribute \"{0}\"" +msgstr "" + +#: src/rougail/object_model.py:736 src/rougail/object_model.py:744 +msgid "the identifier has an invalid attribute \"{0}\", \"when\" and \"when_not\" cannot set together" +msgstr "" + +#: src/rougail/object_model.py:766 +msgid "the variable \"{0}\" is not a follower, so cannot have index type for \"{1}\"" +msgstr "" + +#: src/rougail/path.py:206 msgid "A variable or a family located in the \"{0}\" namespace shall not be used in the \"{1}\" namespace" msgstr "" @@ -207,15 +335,19 @@ msgstr "" msgid "Directories where extra dictionary files are placed" msgstr "" -#: src/rougail/tiramisureflector.py:376 +#: src/rougail/tiramisu.py:167 +msgid "cannot calculating \"{0}\" attribute for variable \"{1}\" in {2} with parameters \"{3}\": {4}" +msgstr "" + +#: src/rougail/tiramisureflector.py:369 msgid "internal error, {0} is not a dynamic variable" msgstr "" -#: src/rougail/user_datas.py:155 +#: src/rougail/user_datas.py:164 msgid "the variable \"{0}\" contains secrets and should not be defined in {1}" msgstr "" -#: src/rougail/user_datas.py:215 +#: src/rougail/user_datas.py:227 msgid "the option \"{0}\" is an option description" msgstr "" diff --git a/src/rougail/annotator/value.py b/src/rougail/annotator/value.py index 5a419f87a..25284a128 100644 --- a/src/rougail/annotator/value.py +++ b/src/rougail/annotator/value.py @@ -115,7 +115,7 @@ class Annotator(Walk): # pylint: disable=R0903 if isinstance(variable.choices, Calculation): continue if variable.choices is None: - msg = _(f'the variable "{variable.path}" is a "choice" variable but don\'t have any choice') + msg = _('the variable "{0}" is a "choice" variable but don\'t have any choice').format(variable.path) raise DictConsistencyError(msg, 19, variable.xmlfiles) if not variable.mandatory and not variable.multi: self.add_choice_nil(variable) @@ -132,5 +132,5 @@ class Annotator(Walk): # pylint: disable=R0903 if variable.type != "regexp": continue if variable.regexp is None: - msg = _(f'the variable "{variable.path}" is a "regexp" variable but don\'t have any regexp') + msg = _('the variable "{0}" is a "regexp" variable but don\'t have any regexp').format(variable.path) raise DictConsistencyError(msg, 66, variable.xmlfiles) diff --git a/src/rougail/locale/fr/LC_MESSAGES/rougail.mo b/src/rougail/locale/fr/LC_MESSAGES/rougail.mo index d4b0be014069440eeaa62109db103145cce6ad42..7ba40306f623743ddd76618e7e515a5e2d11afa0 100644 GIT binary patch literal 13318 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 bool: return False elif value in ["", None]: return None - raise Exception(f'unknown boolean value "{value}"') + raise Exception(_('unknown boolean value "{0}"').format(value)) CONVERT_OPTION = { @@ -151,6 +152,9 @@ class Param(BaseModel): ) -> None: super().__init__(**kwargs) + def to_param(self, attribute_name, objectspace, path, version, namespace, xmlfiles) -> dict: + return self.model_dump() + class AnyParam(Param): type: str @@ -164,6 +168,31 @@ class VariableParam(Param): whole: bool = False optional: bool = False + def to_param(self, attribute_name, objectspace, path, version, namespace, xmlfiles) -> dict: + param = super().to_param(attribute_name, objectspace, path, version, namespace, xmlfiles) + variable, identifier = objectspace.paths.get_with_dynamic( + param["variable"], + path, + version, + namespace, + xmlfiles, + ) + if not variable: + if not param.get("optional"): + msg = _('cannot find variable "{0}" defined in attribute "{1}" for "{2}"').format(param["variable"], attribute_name, path) + raise DictConsistencyError(msg, 22, xmlfiles) + return None + if isinstance(variable, objectspace.family): + msg = _('the variable "{0}" is in fact a family in attribute "{1}" for "{2}"').format(variable["name"], attribute_name, path) + raise DictConsistencyError(msg, 42, xmlfiles) + if not isinstance(variable, objectspace.variable): + msg = _('unknown object "{0}" in attribute "{1}" for "{2}"').format(variable, attribute_name, path) + raise DictConsistencyError(msg, 44, xmlfiles) + param["variable"] = variable + if identifier: + param["identifier"] = identifier + return param + class IdentifierParam(Param): type: str @@ -174,7 +203,7 @@ class IdentifierParam(Param): **kwargs, ) -> None: if not kwargs["family_is_dynamic"]: - msg = f'identifier parameter for "{kwargs["attribute"]}" in "{kwargs["path"]}" cannot be set none dynamic family' + msg = _('identifier parameter for "{0}" in "{1}" cannot be set none dynamic family').format(kwargs["attribute"], kwargs["path"]) raise DictConsistencyError(msg, 10, kwargs["xmlfiles"]) super().__init__(**kwargs) @@ -184,6 +213,27 @@ class InformationParam(Param): information: str variable: Optional[str] = None + def to_param(self, attribute_name, objectspace, path, version, namespace, xmlfiles) -> dict: + param = super().to_param(attribute_name, objectspace, path, version, namespace, xmlfiles) + if not param["variable"]: + del param["variable"] + return param + variable, identifier = objectspace.paths.get_with_dynamic( + param["variable"], + path, + version, + namespace, + xmlfiles, + ) + if not variable: + msg = _('cannot find variable "{0}" defined in "{1}" for "{2}"').format(param["variable"], attribute_name, path) + raise DictConsistencyError(msg, 14, xmlfiles) + if identifier: + msg = _('variable "{0}" defined in "{1}" for "{2}" is a dynamic variable').format(param["variable"], attribute_name, path) + raise DictConsistencyError(msg, 15, xmlfiles) + param["variable"] = variable + return param + class IndexParam(Param): type: str @@ -193,7 +243,7 @@ class IndexParam(Param): **kwargs, ) -> None: 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 = _('the variable "{0}" is not a follower, so cannot have index type for param in "{1}"').format(kwargs["path"], kwargs["attribute"]) raise DictConsistencyError(msg, 25, kwargs["xmlfiles"]) super().__init__(**kwargs) @@ -202,6 +252,14 @@ class NamespaceParam(Param): type: str namespace: str + def to_param(self, attribute_name, objectspace, path, version, namespace, xmlfiles) -> dict: + namespace = self.namespace + if namespace: + namespace = objectspace.paths[namespace].description + return {'type': 'any', + 'value': namespace, + 'key': self.key, + } PARAM_TYPES = { "any": AnyParam, @@ -227,58 +285,15 @@ class Calculation(BaseModel): def get_params(self, objectspace): if not self.params: return {} + if self.ori_path is None: + path = self.path + else: + path = self.ori_path params = {} for param_obj in self.params: - param = param_obj.model_dump() - if param.get("type") == "variable": - if self.ori_path is None: - path = self.path - else: - path = self.ori_path - variable, identifier = objectspace.paths.get_with_dynamic( - param["variable"], - path, - self.version, - self.namespace, - self.xmlfiles, - ) - if not variable: - if not param.get("optional"): - msg = f'cannot find variable "{param["variable"]}" defined in attribute "{self.attribute_name}" for "{self.path}"' - raise DictConsistencyError(msg, 22, self.xmlfiles) - continue - if not isinstance(variable, objectspace.variable): - if isinstance(variable, objectspace.family): - msg = f'the variable "{variable["name"]}" is in fact a family in attribute "{self.attribute_name}" for "{self.path}"' - raise DictConsistencyError(msg, 42, self.xmlfiles) - else: - msg = f'unknown object "{variable}" in attribute "{self.attribute_name}" for "{self.path}"' - raise DictConsistencyError(msg, 44, self.xmlfiles) - param["variable"] = variable - if identifier: - param["identifier"] = identifier - if param.get("type") == "information": - if param["variable"]: - if self.ori_path is None: - path = self.path - else: - path = self.ori_path - variable, identifier = objectspace.paths.get_with_dynamic( - param["variable"], - path, - self.version, - self.namespace, - self.xmlfiles, - ) - if not variable: - msg = f'cannot find variable "{param["variable"]}" defined in "{self.attribute_name}" for "{self.path}"' - raise DictConsistencyError(msg, 14, self.xmlfiles) - param["variable"] = variable - if identifier: - msg = f'variable "{param["variable"]}" defined in "{self.attribute_name}" for "{self.path}" is a dynamic variable' - raise DictConsistencyError(msg, 15, self.xmlfiles) - else: - del param["variable"] + param = param_obj.to_param(self.attribute_name, objectspace, path, self.version, self.namespace, self.xmlfiles) + if param is None: + continue params[param.pop("key")] = param return params @@ -452,10 +467,10 @@ class _VariableCalculation(Calculation): ) if variable and not isinstance(variable, objectspace.variable): if isinstance(variable, objectspace.family): - msg = f'a variable "{variable.path}" is needs in attribute "{self.attribute_name}" for "{self.path}" but it\'s a family' + msg = _('a variable "{0}" is needs in attribute "{1}" for "{2}" but it\'s a family').format(variable.path, self.attribute_name, self.path) raise DictConsistencyError(msg, 47, self.xmlfiles) else: - msg = f'unknown object "{variable}" in attribute "{self.attribute_name}" for "{self.path}"' + msg = _('unknown object "{0}" in attribute "{1}" for "{2}"').format(variable, self.attribute_name, self.path) raise DictConsistencyError(msg, 48, self.xmlfiles) return variable, identifier @@ -473,7 +488,7 @@ class _VariableCalculation(Calculation): path = self.path else: path = self.ori_path - msg = f'Variable not found "{self.variable}" for attribut "{self.attribute_name}" in variable "{path}"' + msg = _('Variable not found "{0}" for attribut "{1}" in variable "{2}"').format(self.variable, self.attribute_name, path) raise DictConsistencyError(msg, 88, self.xmlfiles) return {None: [["example"]]} param = { @@ -515,13 +530,13 @@ class _VariableCalculation(Calculation): if needs_multi: if calc_variable_is_multi: if self.inside_list: - msg = f'the variable "{self.path}" has an invalid attribute "{self.attribute_name}", the variable "{variable.path}" is multi but is inside a list' + msg = _('the variable "{0}" has an invalid attribute "{1}", the variable "{2}" is multi but is inside a list').format(self.path, self.attribute_name, variable.path) raise DictConsistencyError(msg, 18, self.xmlfiles) elif not self.inside_list: - msg = f'the variable "{self.path}" has an invalid attribute "{self.attribute_name}", the variable "{variable.path}" is not multi but is not inside a list' + msg = _('the variable "{0}" has an invalid attribute "{1}", the variable "{2}" is not multi but is not inside a list').format(self.path, self.attribute_name, variable.path) raise DictConsistencyError(msg, 20, self.xmlfiles) elif self.inside_list: - msg = f'the variable "{self.path}" has an invalid attribute "{self.attribute_name}", it\'s a list' + msg = _('the variable "{0}" has an invalid attribute "{1}", it\'s a list').format(self.path, self.attribute_name) raise DictConsistencyError(msg, 23, self.xmlfiles) elif calc_variable_is_multi: if ( @@ -530,7 +545,7 @@ class _VariableCalculation(Calculation): ): if is_variable_calculation: # it's not a follower or not in same leadership - msg = f'the variable "{self.path}" has an invalid attribute "{self.attribute_name}", the variable "{variable.path}" is a multi' + msg = _('the variable "{0}" has an invalid attribute "{1}", the variable "{2}" is a multi').format(self.path, self.attribute_name, variable.path) raise DictConsistencyError(msg, 21, self.xmlfiles) else: params[None][0]["index"] = {"index": {"type": "index"}} @@ -552,7 +567,7 @@ class VariableCalculation(_VariableCalculation): objectspace, ) -> dict: if self.attribute_name != "default" and self.optional: - msg = f'"{self.attribute_name}" variable shall not have an "optional" attribute for variable "{self.variable}"' + msg = _('"{0}" attribut shall not have an "optional" attribute for variable "{1}"').format(self.attribute_name, self.variable) raise DictConsistencyError(msg, 33, self.xmlfiles) variable, identifier = self.get_variable(objectspace) if ( @@ -561,6 +576,11 @@ class VariableCalculation(_VariableCalculation): or (objectspace.force_optional and self.attribute_name == "default") ): raise VariableCalculationDependencyError() + if self.attribute_name == "default": + local_variable = objectspace.paths[self.path] + if CONVERT_OPTION.get(local_variable.type, {}).get("func", str) != CONVERT_OPTION.get(variable.type, {}).get("func", str): + msg = _('variable "{0}" has a default value calculated with "{1}" which has incompatible type').format(self.path, variable.path) + raise DictConsistencyError(msg, 67, self.xmlfiles) params = self.get_params( objectspace, variable, @@ -595,16 +615,16 @@ class VariablePropertyCalculation(_VariableCalculation): variable = params[None][0]["variable"] if self.when is not undefined: 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 = _('"when" is not allowed in format version 1.0 for attribute "{0}" for variable "{1}"').format(self.attribute_name, self.path) raise DictConsistencyError(msg, 103, variable.xmlfiles) if self.when_not is not undefined: - msg = f'the variable "{self.path}" has an invalid attribute "{self.attribute_name}", when and when_not cannot set together' + msg = _('the variable "{0}" has an invalid attribute "{1}", "when" and "when_not" cannot set together').format(self.path, self.attribute_name) raise DictConsistencyError(msg, 31, variable.xmlfiles) when = self.when inverse = False elif self.when_not is not undefined: 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 = _('"when_not" is not allowed in format version 1.0 for attribute "{0}" for variable "{1}"').format(self.attribute_name, self.path) raise DictConsistencyError(msg, 104, variable.xmlfiles) when = self.when_not inverse = True @@ -657,10 +677,10 @@ class InformationCalculation(Calculation): ) if variable is None: if not objectspace.force_optional: - msg = f'cannot find variable "{self.variable}" for the information "{self.information}" when calculating "{self.attribute_name}"' + msg = _('cannot find variable "{0}" for the information "{1}" when calculating "{2}"').format(self.variable, self.information, self.attribute_name) raise DictConsistencyError(msg, 40, variable.xmlfiles) if identifier is not None: - msg = f'identifier not allowed for the information "{self.information}" when calculating "{self.attribute_name}"' + msg = _('identifier not allowed for the information "{0}" when calculating "{1}"').format(self.information, self.attribute_name) raise DictConsistencyError(msg, 41, variable.xmlfiles) if variable: params[None][0]["variable"] = variable @@ -709,11 +729,11 @@ class IdentifierPropertyCalculation(_IdentifierCalculation): objectspace, ) -> dict: if self.version == "1.0": - msg = f'when is not allowed in format version 1.0 for attribute "{self.attribute_name}"' + msg = _('"when" is not allowed in format version 1.0 for attribute "{0}"').format(self.attribute_name) raise DictConsistencyError(msg, 105, variable.xmlfiles) if self.when is not undefined: if self.when_not is not undefined: - msg = f'the identifier has an invalid attribute "{self.attribute_name}", when and when_not cannot set together' + msg = _('the identifier has an invalid attribute "{0}", "when" and "when_not" cannot set together').format(self.attribute_name) raise DictConsistencyError(msg, 35, variable.xmlfiles) when = self.when inverse = False @@ -721,7 +741,7 @@ class IdentifierPropertyCalculation(_IdentifierCalculation): when = self.when_not inverse = True else: - msg = f'the identifier has an invalid attribute "{self.attribute_name}", when and when_not cannot set together' + msg = _('the identifier has an invalid attribute "{0}", "when" and "when_not" cannot set together').format(self.attribute_name) raise DictConsistencyError params = { None: [self.attribute_name, self.get_identifier()], @@ -743,7 +763,7 @@ class IndexCalculation(Calculation): objectspace, ) -> dict: if self.path not in objectspace.followers: - msg = f'the variable "{self.path}" is not a follower, so cannot have index type for "{self.attribute_name}"' + msg = _('the variable "{0}" is not a follower, so cannot have index type for "{1}"').format(self.path, self.attribute_name) raise DictConsistencyError(msg, 60, self.xmlfiles) return { "function": "calc_value", diff --git a/src/rougail/tiramisureflector.py b/src/rougail/tiramisureflector.py index ff9358273..0c6cf65b9 100644 --- a/src/rougail/tiramisureflector.py +++ b/src/rougail/tiramisureflector.py @@ -295,40 +295,13 @@ class Common: ): """Populate variable parameters""" if not isinstance(param, dict): - if isinstance(param, str): - value = self.convert_str(param) - else: - value = param - return f"ParamValue({value})" + param = {"type": "any", + "value": param, + } if param["type"] == "value": return f"ParamValue({param['value']})" if param["type"] == "information": - # default? really? - if self.elt.multi: - default = [] - else: - default = None - if "variable" in param: - if param["variable"].path == self.elt.path: - return f'ParamSelfInformation("{param["information"]}", {default})' - information_variable_path = param["variable"].path - information_variable = self.tiramisu.reflector_objects[ - information_variable_path - ] - if information_variable_path not in self.calls: - option_name = information_variable.get(self.calls, self.elt.path) - return f'ParamInformation("{param["information"]}", {default}, option={option_name})' - else: - information = ( - f'ParamInformation("{param["information"]}", {default})' - ) - information_name = self.tiramisu.get_information_name() - self.tiramisu.text["option"].append( - f"{information_name} = {information}" - ) - information_variable.informations.append(information_name) - return information_name - return f'ParamInformation("{param["information"]}", {default})' + return self.build_information_param(param) if param["type"] == "identifier": if "identifier" in param and param["identifier"] != None: return f"ParamIdentifier(identifier_index={param['identifier']})" @@ -336,37 +309,51 @@ class Common: if param["type"] == "index": return "ParamIndex()" if param["type"] == "variable": - return self.build_option_param( - param["variable"], - param.get("propertyerror", True), - param.get("optional", False), - param.get("identifier"), - param.get("dynamic"), - param.get("whole", False), - ) + return self.build_variable_param(param) if param["type"] == "any": if isinstance(param["value"], str): value = self.convert_str(param["value"]) else: value = str(param["value"]) return "ParamValue(" + value + ")" - if param["type"] == "namespace": - namespace = param["namespace"] - if namespace: - namespace = self.objectspace.paths[param["namespace"]].description - return f"ParamValue('{namespace}')" raise Exception("pfff") - def build_option_param( + def build_information_param(self, param: dict) -> str: + # default? really? + if self.elt.multi: + default = [] + else: + default = None + if "variable" in param: + information_variable_path = param["variable"].path + if information_variable_path == self.elt.path: + return f'ParamSelfInformation("{param["information"]}", {default})' + information_variable = self.tiramisu.reflector_objects[ + information_variable_path + ] + if information_variable_path not in self.calls: + option_name = information_variable.get(self.calls, self.elt.path) + return f'ParamInformation("{param["information"]}", {default}, option={option_name})' + else: + # if we want to get information from the a parent family + information = ( + f'ParamInformation("{param["information"]}", {default})' + ) + information_name = self.tiramisu.get_information_name() + self.tiramisu.text["option"].append( + f"{information_name} = {information}" + ) + information_variable.informations.append(information_name) + return information_name + return f'ParamInformation("{param["information"]}", {default})' + + def build_variable_param( self, - variable, - propertyerror, - optional: bool, - identifier: Optional[str], - dynamic, - whole: bool, + param: dict, ) -> str: """build variable parameters""" + variable = param["variable"] + whole = param.get("whole", False) if variable.path == self.elt.path: return f"ParamSelfOption(whole={whole})" if whole: @@ -376,6 +363,7 @@ class Common: self.calls, self.elt.path ) params = [f"{option_name}"] + identifier = param.get("identifier") if identifier is not None: if not self.objectspace.paths.is_dynamic(variable.path): msg = _("internal error, {0} is not a dynamic variable").format( @@ -389,11 +377,11 @@ class Common: ident = self.convert_str(ident) identifiers.append(str(ident)) params.append("[" + ", ".join(identifiers) + "]") - if optional: + if param.get("optional", False): params.append("optional=True") else: param_type = "ParamOption" - if not propertyerror: + if not param.get("propertyerror", True): params.append("notraisepropertyerror=True") return f'{param_type}({", ".join(params)})' diff --git a/tests/dictionaries/00_8calculation_param_namespace/tiramisu/base.py b/tests/dictionaries/00_8calculation_param_namespace/tiramisu/base.py index 085a2e6b9..451799591 100644 --- a/tests/dictionaries/00_8calculation_param_namespace/tiramisu/base.py +++ b/tests/dictionaries/00_8calculation_param_namespace/tiramisu/base.py @@ -11,6 +11,6 @@ ALLOWED_LEADER_PROPERTIES.add("basic") ALLOWED_LEADER_PROPERTIES.add("standard") ALLOWED_LEADER_PROPERTIES.add("advanced") dict_env['default_rougail.variable'] = "{{ namespace }}" -option_2 = StrOption(name="variable", doc="a variable", default=Calculation(func['jinja_to_function'], Params((), kwargs={'__internal_jinja': ParamValue("default_rougail.variable"), '__internal_type': ParamValue("string"), '__internal_multi': ParamValue(False), '__internal_files': ParamValue(['../rougail-tests/structures/00_8calculation_param_namespace/rougail/00-base.yml']), '__internal_attribute': ParamValue("default"), '__internal_variable': ParamValue("rougail.variable"), 'namespace': ParamValue('Rougail')})), properties=frozenset({"standard"}), informations={'type': 'string'}) +option_2 = StrOption(name="variable", doc="a variable", default=Calculation(func['jinja_to_function'], Params((), kwargs={'__internal_jinja': ParamValue("default_rougail.variable"), '__internal_type': ParamValue("string"), '__internal_multi': ParamValue(False), '__internal_files': ParamValue(['../rougail-tests/structures/00_8calculation_param_namespace/rougail/00-base.yml']), '__internal_attribute': ParamValue("default"), '__internal_variable': ParamValue("rougail.variable"), 'namespace': ParamValue("Rougail")})), properties=frozenset({"standard"}), informations={'type': 'string'}) optiondescription_1 = OptionDescription(name="rougail", doc="Rougail", group_type=groups.namespace, children=[option_2], properties=frozenset({"standard"})) option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1]) diff --git a/tests/dictionaries/60_5family_dynamic_calc_suffix_disabled2/makedict/after.json b/tests/dictionaries/60_5family_dynamic_calc_suffix_disabled2/makedict/after.json new file mode 100644 index 000000000..fec8f4dc2 --- /dev/null +++ b/tests/dictionaries/60_5family_dynamic_calc_suffix_disabled2/makedict/after.json @@ -0,0 +1,10 @@ +{ + "rougail.var1": { + "owner": "default", + "value": [] + }, + "rougail.var2": { + "owner": "default", + "value": null + } +} diff --git a/tests/dictionaries/60_5family_dynamic_calc_suffix_disabled2/makedict/base.json b/tests/dictionaries/60_5family_dynamic_calc_suffix_disabled2/makedict/base.json new file mode 100644 index 000000000..a20d18a3f --- /dev/null +++ b/tests/dictionaries/60_5family_dynamic_calc_suffix_disabled2/makedict/base.json @@ -0,0 +1,4 @@ +{ + "rougail.var1": [], + "rougail.var2": null +} diff --git a/tests/dictionaries/60_5family_dynamic_calc_suffix_disabled2/makedict/before.json b/tests/dictionaries/60_5family_dynamic_calc_suffix_disabled2/makedict/before.json new file mode 100644 index 000000000..fec8f4dc2 --- /dev/null +++ b/tests/dictionaries/60_5family_dynamic_calc_suffix_disabled2/makedict/before.json @@ -0,0 +1,10 @@ +{ + "rougail.var1": { + "owner": "default", + "value": [] + }, + "rougail.var2": { + "owner": "default", + "value": null + } +} diff --git a/tests/dictionaries/60_5family_dynamic_calc_suffix_disabled2/makedict/mandatory.json b/tests/dictionaries/60_5family_dynamic_calc_suffix_disabled2/makedict/mandatory.json new file mode 100644 index 000000000..4fb69ce52 --- /dev/null +++ b/tests/dictionaries/60_5family_dynamic_calc_suffix_disabled2/makedict/mandatory.json @@ -0,0 +1 @@ +["rougail.var2"] \ No newline at end of file diff --git a/tests/dictionaries/60_5family_dynamic_calc_suffix_disabled2/tiramisu/base.py b/tests/dictionaries/60_5family_dynamic_calc_suffix_disabled2/tiramisu/base.py new file mode 100644 index 000000000..cb4123bcb --- /dev/null +++ b/tests/dictionaries/60_5family_dynamic_calc_suffix_disabled2/tiramisu/base.py @@ -0,0 +1,18 @@ +from tiramisu import * +from tiramisu.setting import ALLOWED_LEADER_PROPERTIES +from re import compile as re_compile +from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription +load_functions('../rougail-tests/funcs/test.py') +try: + groups.namespace +except: + groups.addgroup('namespace') +ALLOWED_LEADER_PROPERTIES.add("basic") +ALLOWED_LEADER_PROPERTIES.add("standard") +ALLOWED_LEADER_PROPERTIES.add("advanced") +option_2 = StrOption(name="var1", doc="A suffix variable", multi=True, properties=frozenset({"standard"}), informations={'type': 'string', 'test': ('val1', 'val2')}) +option_4 = StrOption(name="var", doc="A dynamic variable", properties=frozenset({"basic", "disabled", "mandatory"}), informations={'type': 'string'}) +optiondescription_3 = ConvertDynOptionDescription(name="dyn{{ identifier }}", doc="dyn{{ identifier }}", identifiers=Calculation(func['calc_value'], Params((ParamOption(option_2)))), children=[option_4], properties=frozenset({"basic"}), informations={'dynamic_variable': 'rougail.var1'}) +option_5 = StrOption(name="var2", doc="A variable calculated", default=Calculation(func['calc_value'], Params((ParamDynOption(option_4, ["val1"], optional=True)))), properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'}) +optiondescription_1 = OptionDescription(name="rougail", doc="Rougail", group_type=groups.namespace, children=[option_2, optiondescription_3, option_5], properties=frozenset({"basic"})) +option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1]) diff --git a/tests/dictionaries/60_5family_dynamic_calc_suffix_disabled2/tiramisu/no_namespace.py b/tests/dictionaries/60_5family_dynamic_calc_suffix_disabled2/tiramisu/no_namespace.py new file mode 100644 index 000000000..2688d085f --- /dev/null +++ b/tests/dictionaries/60_5family_dynamic_calc_suffix_disabled2/tiramisu/no_namespace.py @@ -0,0 +1,13 @@ +from tiramisu import * +from tiramisu.setting import ALLOWED_LEADER_PROPERTIES +from re import compile as re_compile +from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription +load_functions('../rougail-tests/funcs/test.py') +ALLOWED_LEADER_PROPERTIES.add("basic") +ALLOWED_LEADER_PROPERTIES.add("standard") +ALLOWED_LEADER_PROPERTIES.add("advanced") +option_1 = StrOption(name="var1", doc="A suffix variable", multi=True, properties=frozenset({"standard"}), informations={'type': 'string', 'test': ('val1', 'val2')}) +option_3 = StrOption(name="var", doc="A dynamic variable", properties=frozenset({"basic", "disabled", "mandatory"}), informations={'type': 'string'}) +optiondescription_2 = ConvertDynOptionDescription(name="dyn{{ identifier }}", doc="dyn{{ identifier }}", identifiers=Calculation(func['calc_value'], Params((ParamOption(option_1)))), children=[option_3], properties=frozenset({"basic"}), informations={'dynamic_variable': 'var1'}) +option_4 = StrOption(name="var2", doc="A variable calculated", properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'}) +option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[option_1, optiondescription_2, option_4]) diff --git a/tests/errors/20_test_default_variable_incompatible/errno_67 b/tests/errors/20_test_default_variable_incompatible/errno_67 new file mode 100644 index 000000000..e69de29bb diff --git a/tests/errors/20_test_default_variable_incompatible/rougail/00-rougail.yml b/tests/errors/20_test_default_variable_incompatible/rougail/00-rougail.yml new file mode 100644 index 000000000..f21a5fad1 --- /dev/null +++ b/tests/errors/20_test_default_variable_incompatible/rougail/00-rougail.yml @@ -0,0 +1,10 @@ +--- +version: 1.1 + +var1: + type: number + +var2: + type: port + default: + variable: _.var1 diff --git a/tests/test_1_flattener.py b/tests/test_1_flattener.py index 0c485b777..8ae3968d1 100644 --- a/tests/test_1_flattener.py +++ b/tests/test_1_flattener.py @@ -121,7 +121,7 @@ def save(test_dir, eolobj, multi=False, namespace=False, error=False): if isdir(tiramisu_tmp_dir): rmtree(tiramisu_tmp_dir) makedirs(tiramisu_tmp_dir) - tiramisu_objects = eolobj.get_config() + tiramisu_objects = eolobj.run() tiramisu_file = get_tiramisu_filename(test_dir, 'tiramisu', multi, namespace) tiramisu_dir = dirname(tiramisu_file) if not error: