Compare commits

..

No commits in common. "5.2.0a9" and "main" have entirely different histories.

37 changed files with 889 additions and 1504 deletions

File diff suppressed because it is too large Load diff

View file

@ -5,7 +5,7 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2025-05-12 09:05+0200\n"
"POT-Creation-Date: 2024-11-05 08:52+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"
@ -35,380 +35,288 @@ msgstr ""
msgid "Commands:"
msgstr ""
#: tiramisu/api.py:111 tiramisu/api.py:1857
#: tiramisu/api.py:111 tiramisu/api.py:1840
msgid "please specify a valid sub function ({0}.{1})"
msgstr ""
#: tiramisu/api.py:196
#: tiramisu/api.py:194
msgid "please do not specify index ({0}.{1})"
msgstr ""
#: tiramisu/api.py:201 tiramisu/api.py:856
#: tiramisu/api.py:199 tiramisu/api.py:844
msgid "please specify index with a follower option ({0}.{1})"
msgstr ""
#: tiramisu/api.py:222
#: tiramisu/api.py:220
msgid "please specify a valid sub function ({0}.{1}): {2}"
msgstr ""
#: tiramisu/api.py:446
#: tiramisu/api.py:431
msgid "the option {0} is not a dynamic option, cannot get identifiers with only_self parameter to True"
msgstr ""
#: tiramisu/api.py:532
#: tiramisu/api.py:517
msgid "cannot get option from a follower symlink without index"
msgstr ""
#: tiramisu/api.py:607
#: tiramisu/api.py:592
msgid "cannot add this property: \"{0}\""
msgstr ""
#: tiramisu/api.py:634
#: tiramisu/api.py:619
msgid "cannot remove option's property \"{0}\", use permissive instead in option \"{1}\""
msgstr ""
#: tiramisu/api.py:638
#: tiramisu/api.py:623
msgid "cannot find \"{0}\" in option \"{1}\""
msgstr ""
#: tiramisu/api.py:643
#: tiramisu/api.py:628
msgid "cannot remove option's property \"{0}\", use permissive instead in option \"{1}\" at index \"{2}\""
msgstr ""
#: tiramisu/api.py:647
#: tiramisu/api.py:632
msgid "cannot find \"{0}\" in option \"{1}\" at index \"{2}\""
msgstr ""
#: tiramisu/api.py:691
#: tiramisu/api.py:676
msgid "cannot find \"{0}\""
msgstr ""
#: tiramisu/api.py:873
#: tiramisu/api.py:808
msgid "cannot reduce length of the leader {}"
msgstr ""
#: tiramisu/api.py:861
msgid "only multi value has defaultmulti"
msgstr ""
#: tiramisu/api.py:1037
#: tiramisu/api.py:1020
msgid "please specify a valid sub function ({0}.{1}) for {2}"
msgstr ""
#: tiramisu/api.py:1424
#: tiramisu/api.py:1407
msgid "properties must be a frozenset"
msgstr ""
#: tiramisu/api.py:1428 tiramisu/api.py:1455
#: tiramisu/api.py:1411 tiramisu/api.py:1438
msgid "unknown when {} (must be in append or remove)"
msgstr ""
#: tiramisu/api.py:1441 tiramisu/api.py:1465 tiramisu/config.py:1676
#: tiramisu/api.py:1424 tiramisu/api.py:1448 tiramisu/config.py:1680
msgid "unknown type {}"
msgstr ""
#: tiramisu/api.py:1829
#: tiramisu/api.py:1812
msgid "do not use unrestraint, nowarnings or forcepermissive together"
msgstr ""
#: tiramisu/autolib.py:89
#: tiramisu/autolib.py:80
msgid "args in params must be a tuple"
msgstr ""
#: tiramisu/autolib.py:92 tiramisu/autolib.py:97
#: tiramisu/autolib.py:83 tiramisu/autolib.py:88
msgid "arg in params must be a Param"
msgstr ""
#: tiramisu/autolib.py:94
#: tiramisu/autolib.py:85
msgid "kwargs in params must be a dict"
msgstr ""
#: tiramisu/autolib.py:122
#: tiramisu/autolib.py:113
msgid "paramoption needs an option not {}"
msgstr ""
#: tiramisu/autolib.py:128
#: tiramisu/autolib.py:119
msgid "param must have a boolean not a {} for notraisepropertyerror"
msgstr ""
#: tiramisu/autolib.py:131
#: tiramisu/autolib.py:122
msgid "param must have a boolean not a {} for raisepropertyerror"
msgstr ""
#: tiramisu/autolib.py:160
msgid "identifiers in ParamDynOption must be a list, not {0}"
msgstr ""
#: tiramisu/autolib.py:166
msgid "optional in ParamDynOption must be a boolean, not {0}"
msgstr ""
#: tiramisu/autolib.py:220
msgid "cannot add option in information after creating config"
msgstr ""
#: tiramisu/autolib.py:223
msgid "cannot redefine option in information"
msgstr ""
#: tiramisu/autolib.py:227
#: tiramisu/autolib.py:212
msgid "option in ParamInformation cannot be a symlinkoption"
msgstr ""
#: tiramisu/autolib.py:230
#: tiramisu/autolib.py:215
msgid "option in ParamInformation cannot be a follower"
msgstr ""
#: tiramisu/autolib.py:233
#: tiramisu/autolib.py:218
msgid "option in ParamInformation cannot be a dynamic option"
msgstr ""
#: tiramisu/autolib.py:294
#: tiramisu/autolib.py:279
msgid "first argument ({0}) must be a function"
msgstr ""
#: tiramisu/autolib.py:298
#: tiramisu/autolib.py:283
msgid "help_function ({0}) must be a function"
msgstr ""
#: tiramisu/autolib.py:469 tiramisu/autolib.py:524
#: tiramisu/autolib.py:452 tiramisu/autolib.py:514
msgid "unable to carry out a calculation for {}, {}"
msgstr ""
#: tiramisu/autolib.py:461 tiramisu/autolib.py:521
msgid "the option {0} is used in a calculation but is invalid ({1})"
msgstr ""
#: tiramisu/autolib.py:482 tiramisu/autolib.py:538 tiramisu/autolib.py:588
#: tiramisu/autolib.py:477 tiramisu/autolib.py:535 tiramisu/autolib.py:584
msgid "unable to get value for calculating {0}, {1}"
msgstr ""
#: tiramisu/autolib.py:517
msgid "unable to carry out a calculation for {0}, {1}"
msgstr ""
#: tiramisu/autolib.py:563
msgid "cannot find information for {0}, {1} is a dynamic option"
msgstr ""
#: tiramisu/autolib.py:603
#: tiramisu/autolib.py:601
msgid "option {0} is not a dynoptiondescription or in a dynoptiondescription"
msgstr ""
#: tiramisu/autolib.py:696
msgid "cannot calculate arguments for {0}, {1} with identifier \"{2}\", there is no identifiers"
#: tiramisu/autolib.py:848
msgid "the \"{}\" function with positional arguments \"{}\" and keyword arguments \"{}\" must not return a list (\"{}\") for the follower option {}"
msgstr ""
#: tiramisu/autolib.py:708
msgid "cannot calculate arguments for {0}, {1} with identifier \"{2}\", list of valid identifiers: {3}"
#: tiramisu/autolib.py:863
msgid "the \"{}\" function must not return a list (\"{}\") for the follower option {}"
msgstr ""
#: tiramisu/autolib.py:819
msgid "the follower {0} must have index in carry_out_calculation!"
#: tiramisu/autolib.py:904
msgid "unexpected error \"{0}\" in function \"{1}\" with arguments \"{3}\" and \"{4}\" for option {2}"
msgstr ""
#: tiramisu/autolib.py:931
msgid "unexpected error \"{1}\" in function \"{2}\" with arguments \"{3}\" and \"{4}\" for option {0}"
#: tiramisu/autolib.py:915
msgid "unexpected error \"{0}\" in function \"{1}\" for option {2}"
msgstr ""
#: tiramisu/autolib.py:941
msgid "unexpected error \"{1}\" in function \"{2}\" for option {0}"
msgstr ""
#: tiramisu/config.py:574
msgid "there is no option description for this config (may be GroupConfig)"
msgstr ""
#: tiramisu/config.py:663
msgid "no option found in config with these criteria"
msgstr ""
#: tiramisu/config.py:978 tiramisu/option/optiondescription.py:74
msgid "option description seems to be part of an other config"
msgstr ""
#: tiramisu/config.py:1140
msgid "parent of {0} not already exists"
msgstr ""
#: tiramisu/config.py:1187
msgid "cannot set leadership object has root optiondescription"
msgstr ""
#: tiramisu/config.py:1190
msgid "cannot set dynoptiondescription object has root optiondescription"
msgstr ""
#: tiramisu/config.py:1242
msgid "config name must be uniq in groupconfig for \"{0}\""
msgstr ""
#: tiramisu/config.py:1453
msgid "unknown config \"{}\""
msgstr ""
#: tiramisu/config.py:1478
msgid "child must be a Config, MixConfig or MetaConfig"
msgstr ""
#: tiramisu/config.py:1513
msgid "force_default, force_default_if_same or force_dont_change_value cannot be set with only_config"
msgstr ""
#: tiramisu/config.py:1523
msgid "force_default and force_dont_change_value cannot be set together"
msgstr ""
#: tiramisu/config.py:1672
msgid "config name must be uniq in groupconfig for {0}"
msgstr ""
#: tiramisu/config.py:1717
msgid "config added has no name, the name is mandatory"
msgstr ""
#: tiramisu/config.py:1722
msgid "config name \"{0}\" is not uniq in groupconfig \"{1}\""
msgstr ""
#: tiramisu/config.py:1740 tiramisu/config.py:1746
msgid "cannot find the config {0}"
msgstr ""
#: tiramisu/config.py:1772
msgid "MetaConfig with optiondescription must have string has child, not {}"
msgstr ""
#: tiramisu/config.py:1784
msgid "child must be a Config or MetaConfig"
msgstr ""
#: tiramisu/config.py:1789
msgid "all config in metaconfig must have the same optiondescription"
msgstr ""
#: tiramisu/config.py:1806
msgid "metaconfig must have the same optiondescription"
msgstr ""
#: tiramisu/error.py:48
msgid "and"
msgstr ""
#: tiramisu/error.py:50
msgid "or"
msgstr ""
#: tiramisu/error.py:72
msgid " {} "
msgstr ""
#: tiramisu/error.py:145
msgid "cannot modify the {0} {1} at index \"{2}\" because {3} is frozen"
msgstr ""
#: tiramisu/error.py:149
msgid "cannot modify the {0} {1} at index \"{2}\" because is frozen"
msgstr ""
#: tiramisu/error.py:154
msgid "cannot modify the {0} {1} because {2} is frozen"
msgstr ""
#: tiramisu/error.py:156
msgid "cannot modify the {0} {1} because is frozen"
msgstr ""
#: tiramisu/error.py:160
msgid "cannot access to {0} {1} at index \"{2}\" because {3} hasn't value"
msgstr ""
#: tiramisu/error.py:164
msgid "{0} {1} at index \"{2}\" is mandatory but hasn't value"
msgstr ""
#: tiramisu/error.py:167
msgid "cannot access to {0} {1} because {2} hasn't value"
msgstr ""
#: tiramisu/error.py:169
msgid "{0} {1} is mandatory but hasn't value"
msgstr ""
#: tiramisu/error.py:173
msgid "cannot access to {0} {1} at index \"{2}\" because {3} has {4} {5}"
msgstr ""
#: tiramisu/error.py:177
msgid "cannot access to {0} {1} at index \"{2}\" because has {3} {4}"
msgstr ""
#: tiramisu/error.py:182
msgid "cannot access to {0} {1} because {2} has {3} {4}"
msgstr ""
#: tiramisu/error.py:184
msgid "cannot access to {0} {1} because has {2} {3}"
msgstr ""
#: tiramisu/error.py:187
msgid "property"
msgstr ""
#: tiramisu/error.py:189
msgid "properties"
msgstr ""
#: tiramisu/error.py:204
msgid "cannot access to \"{0}\" it's a dynamic option"
msgstr ""
#: tiramisu/error.py:205
msgid "\"{0}\" is not an option"
msgstr ""
#: tiramisu/error.py:269
msgid "cannot set \"group_type\" attribute for the Leadership {0}"
msgstr ""
#: tiramisu/error.py:273
msgid "the leader {0} cannot have \"{1}\" property"
msgstr ""
#: tiramisu/error.py:277
msgid "the leader {0} cannot have \"force_default_on_freeze\" or \"force_metaconfig_on_freeze\" property without \"frozen\""
msgstr ""
#: tiramisu/error.py:281
msgid "cannot reduce length of the leader {0}"
msgstr ""
#: tiramisu/error.py:283
#: tiramisu/config.py:419
msgid "index \"{0}\" is greater than the leadership length \"{1}\" for option {2}"
msgstr ""
#: tiramisu/error.py:287
#: tiramisu/config.py:579
msgid "there is no option description for this config (may be GroupConfig)"
msgstr ""
#: tiramisu/config.py:668
msgid "no option found in config with these criteria"
msgstr ""
#: tiramisu/config.py:871
msgid "the follower option {0} has greater length ({1}) than the leader length ({2})"
msgstr ""
#: tiramisu/error.py:292
msgid "the \"{0}\" function with positional arguments \"{1}\" and keyword arguments \"{2}\" must not return a list (\"{3}\") for the follower option {4}"
#: tiramisu/config.py:982 tiramisu/option/optiondescription.py:74
msgid "option description seems to be part of an other config"
msgstr ""
#: tiramisu/error.py:297
msgid "the \"{0}\" function must not return a list (\"{1}\") for the follower option {2}"
#: tiramisu/config.py:1144
msgid "parent of {0} not already exists"
msgstr ""
#: tiramisu/error.py:331
#: tiramisu/config.py:1191
msgid "cannot set leadership object has root optiondescription"
msgstr ""
#: tiramisu/config.py:1194
msgid "cannot set dynoptiondescription object has root optiondescription"
msgstr ""
#: tiramisu/config.py:1246
msgid "config name must be uniq in groupconfig for \"{0}\""
msgstr ""
#: tiramisu/config.py:1457
msgid "unknown config \"{}\""
msgstr ""
#: tiramisu/config.py:1482
msgid "child must be a Config, MixConfig or MetaConfig"
msgstr ""
#: tiramisu/config.py:1517
msgid "force_default, force_default_if_same or force_dont_change_value cannot be set with only_config"
msgstr ""
#: tiramisu/config.py:1527
msgid "force_default and force_dont_change_value cannot be set together"
msgstr ""
#: tiramisu/config.py:1676
msgid "config name must be uniq in groupconfig for {0}"
msgstr ""
#: tiramisu/config.py:1721
msgid "config added has no name, the name is mandatory"
msgstr ""
#: tiramisu/config.py:1726
msgid "config name \"{0}\" is not uniq in groupconfig \"{1}\""
msgstr ""
#: tiramisu/config.py:1744 tiramisu/config.py:1750
msgid "cannot find the config {0}"
msgstr ""
#: tiramisu/config.py:1776
msgid "MetaConfig with optiondescription must have string has child, not {}"
msgstr ""
#: tiramisu/config.py:1788
msgid "child must be a Config or MetaConfig"
msgstr ""
#: tiramisu/config.py:1793
msgid "all config in metaconfig must have the same optiondescription"
msgstr ""
#: tiramisu/config.py:1810
msgid "metaconfig must have the same optiondescription"
msgstr ""
#: tiramisu/error.py:31
msgid "and"
msgstr ""
#: tiramisu/error.py:33
msgid "or"
msgstr ""
#: tiramisu/error.py:55
msgid " {} "
msgstr ""
#: tiramisu/error.py:108
msgid "property"
msgstr ""
#: tiramisu/error.py:110
msgid "properties"
msgstr ""
#: tiramisu/error.py:113
msgid "cannot modify the {0} {1} because \"{2}\" has {3} {4}"
msgstr ""
#: tiramisu/error.py:115
msgid "cannot modify the {0} {1} because has {2} {3}"
msgstr ""
#: tiramisu/error.py:118
msgid "cannot access to {0} {1} because \"{2}\" has {3} {4}"
msgstr ""
#: tiramisu/error.py:120
msgid "cannot access to {0} {1} because has {2} {3}"
msgstr ""
#: tiramisu/error.py:192
msgid "invalid value"
msgstr ""
#: tiramisu/error.py:341
msgid "attention, \"{0}\" could be an invalid {1} for {2}"
#: tiramisu/error.py:201
msgid "attention, \"{0}\" could be an invalid {1} for \"{2}\""
msgstr ""
#: tiramisu/error.py:345
msgid "attention, \"{0}\" could be an invalid {1} for {2} at index \"{3}\""
msgstr ""
#: tiramisu/error.py:366 tiramisu/error.py:377
msgid "\"{0}\" is an invalid {1} for {2}"
msgstr ""
#: tiramisu/error.py:368
msgid "\"{0}\" is an invalid {1} for {2} at index \"{3}\""
#: tiramisu/error.py:219 tiramisu/error.py:228
msgid "\"{0}\" is an invalid {1} for \"{2}\""
msgstr ""
#: tiramisu/function.py:65
@ -475,23 +383,23 @@ msgstr ""
msgid "invalid properties type {0} for {1}, must be a frozenset"
msgstr ""
#: tiramisu/option/baseoption.py:100
#: tiramisu/option/baseoption.py:98
msgid "invalid property type {0} for {1}, must be a string or a Calculation"
msgstr ""
#: tiramisu/option/baseoption.py:251
#: tiramisu/option/baseoption.py:249
msgid "information's item for {0} not found: \"{1}\""
msgstr ""
#: tiramisu/option/baseoption.py:269
#: tiramisu/option/baseoption.py:267
msgid "'{0}' ({1}) object attribute '{2}' is read-only"
msgstr ""
#: tiramisu/option/baseoption.py:310
#: tiramisu/option/baseoption.py:308
msgid "\"{}\" ({}) object attribute \"{}\" is read-only"
msgstr ""
#: tiramisu/option/baseoption.py:322
#: tiramisu/option/baseoption.py:320
msgid "{0} not part of any Config"
msgstr ""
@ -515,80 +423,64 @@ msgstr ""
msgid "only {0} are allowed"
msgstr ""
#: tiramisu/option/domainnameoption.py:67
#: tiramisu/option/domainnameoption.py:60
msgid "unknown type {0} for hostname"
msgstr ""
#: tiramisu/option/domainnameoption.py:70
#: tiramisu/option/domainnameoption.py:63
msgid "allow_ip must be a boolean"
msgstr ""
#: tiramisu/option/domainnameoption.py:72
#: tiramisu/option/domainnameoption.py:65
msgid "allow_cidr_network must be a boolean"
msgstr ""
#: tiramisu/option/domainnameoption.py:74
#: tiramisu/option/domainnameoption.py:67
msgid "allow_without_dot must be a boolean"
msgstr ""
#: tiramisu/option/domainnameoption.py:76
#: tiramisu/option/domainnameoption.py:69
msgid "allow_startswith_dot must be a boolean"
msgstr ""
#: tiramisu/option/domainnameoption.py:87
#: tiramisu/option/domainnameoption.py:81
msgid "must start with lowercase characters followed by lowercase characters, number, \"-\" and \".\" characters are allowed"
msgstr ""
#: tiramisu/option/domainnameoption.py:90
#: tiramisu/option/domainnameoption.py:84
msgid "must start with lowercase characters followed by lowercase characters, number, \"-\" and \".\" characters are recommanded"
msgstr ""
#: tiramisu/option/domainnameoption.py:95
msgid "must start with lowercase characters followed by lowercase characters, number and \"-\" characters are allowed"
msgstr ""
#: tiramisu/option/domainnameoption.py:98
msgid "must start with lowercase characters followed by lowercase characters, number and \"-\" characters are recommanded"
msgstr ""
#: tiramisu/option/domainnameoption.py:102
#: tiramisu/option/domainnameoption.py:103
#: tiramisu/option/domainnameoption.py:88
#: tiramisu/option/domainnameoption.py:89
msgid "could be a IP, otherwise {}"
msgstr ""
#: tiramisu/option/domainnameoption.py:148
#: tiramisu/option/domainnameoption.py:134
msgid "invalid length (min 1)"
msgstr ""
#: tiramisu/option/domainnameoption.py:151
#: tiramisu/option/domainnameoption.py:137
msgid "invalid length (max {0})"
msgstr ""
#: tiramisu/option/domainnameoption.py:157
#: tiramisu/option/domainnameoption.py:143
msgid "must have dot"
msgstr ""
#: tiramisu/option/domainnameoption.py:159
#: tiramisu/option/domainnameoption.py:145
msgid "invalid length (max 255)"
msgstr ""
#: tiramisu/option/domainnameoption.py:179
msgid "DNS resolution failed"
msgstr ""
#: tiramisu/option/domainnameoption.py:182
msgid "error resolving DNS: {1}"
msgstr ""
#: tiramisu/option/domainnameoption.py:189
#: tiramisu/option/domainnameoption.py:163
msgid "must not be an IP"
msgstr ""
#: tiramisu/option/domainnameoption.py:212
#: tiramisu/option/domainnameoption.py:186
msgid "some characters are uppercase"
msgstr ""
#: tiramisu/option/dynoptiondescription.py:130
#: tiramisu/option/dynoptiondescription.py:131
msgid "DynOptionDescription identifiers for option {0}, is not a list ({1})"
msgstr ""
@ -609,19 +501,7 @@ msgid "must starts with \"/\""
msgstr ""
#: tiramisu/option/filenameoption.py:78
msgid "directory"
msgstr ""
#: tiramisu/option/filenameoption.py:78
msgid "file"
msgstr ""
#: tiramisu/option/filenameoption.py:82
msgid "cannot find this {0}"
msgstr ""
#: tiramisu/option/intoption.py:46
msgid "which is not an integer"
msgid "cannot find {0} \"{1}\""
msgstr ""
#: tiramisu/option/intoption.py:52
@ -668,23 +548,31 @@ msgstr ""
msgid "must be private IP"
msgstr ""
#: tiramisu/option/leadership.py:65
#: tiramisu/option/leadership.py:55
msgid "cannot set \"group_type\" attribute for a Leadership"
msgstr ""
#: tiramisu/option/leadership.py:67
msgid "a leader and a follower are mandatories in leadership \"{}\""
msgstr ""
#: tiramisu/option/leadership.py:97
#: tiramisu/option/leadership.py:89
msgid "leader cannot have \"{}\" property"
msgstr ""
#: tiramisu/option/leadership.py:101
msgid "leadership {0} shall not have a symlinkoption"
msgstr ""
#: tiramisu/option/leadership.py:104
#: tiramisu/option/leadership.py:108
msgid "leadership {0} shall not have a subgroup"
msgstr ""
#: tiramisu/option/leadership.py:110
msgid "only multi option are allowed in leadership {0} but option {1} is not a multi"
#: tiramisu/option/leadership.py:114
msgid "only multi option allowed in leadership {0} but option {1} is not a multi"
msgstr ""
#: tiramisu/option/leadership.py:137
#: tiramisu/option/leadership.py:141
msgid "not allowed default value for follower option {0} in leadership {1}"
msgstr ""
@ -716,31 +604,31 @@ msgstr ""
msgid "validators must be a Calculation for \"{0}\""
msgstr ""
#: tiramisu/option/option.py:141
#: tiramisu/option/option.py:146
msgid "invalid default_multi value \"{0}\" for option {1}"
msgstr ""
#: tiramisu/option/option.py:149
#: tiramisu/option/option.py:154
msgid "invalid default_multi value \"{0}\" for option {1}, {2}"
msgstr ""
#: tiramisu/option/option.py:162
#: tiramisu/option/option.py:167
msgid "invalid default_multi value \"{0}\" for option {1}, must be a list for a submulti"
msgstr ""
#: tiramisu/option/option.py:294
#: tiramisu/option/option.py:290
msgid "the value \"{}\" is not unique"
msgstr ""
#: tiramisu/option/option.py:356
#: tiramisu/option/option.py:352
msgid "which must not be a list"
msgstr ""
#: tiramisu/option/option.py:408 tiramisu/option/option.py:434
#: tiramisu/option/option.py:404 tiramisu/option/option.py:430
msgid "which must be a list"
msgstr ""
#: tiramisu/option/option.py:428
#: tiramisu/option/option.py:424
msgid "which \"{}\" must be a list of list"
msgstr ""
@ -748,23 +636,35 @@ msgstr ""
msgid "duplicate option: {0}"
msgstr ""
#: tiramisu/option/optiondescription.py:336
#: tiramisu/option/optiondescription.py:244
msgid "unknown option \"{0}\" in root optiondescription (it's a dynamic option)"
msgstr ""
#: tiramisu/option/optiondescription.py:279
msgid "unknown option \"{0}\" in root optiondescription"
msgstr ""
#: tiramisu/option/optiondescription.py:282
msgid "unknown option \"{0}\" in optiondescription {1}"
msgstr ""
#: tiramisu/option/optiondescription.py:338
msgid "children in optiondescription \"{}\" must be a list"
msgstr ""
#: tiramisu/option/optiondescription.py:364
#: tiramisu/option/optiondescription.py:366
msgid "duplicate option name: \"{0}\""
msgstr ""
#: tiramisu/option/optiondescription.py:370
#: tiramisu/option/optiondescription.py:372
msgid "the option's name \"{0}\" start as the dynoptiondescription's name \"{1}\""
msgstr ""
#: tiramisu/option/optiondescription.py:413
#: tiramisu/option/optiondescription.py:415
msgid "cannot change group_type if already set (old {0}, new {1})"
msgstr ""
#: tiramisu/option/optiondescription.py:418
#: tiramisu/option/optiondescription.py:420
msgid "group_type: {0} not allowed"
msgstr ""
@ -805,79 +705,79 @@ msgstr ""
msgid "too weak"
msgstr ""
#: tiramisu/option/portoption.py:80
#: tiramisu/option/portoption.py:74
msgid "inconsistency in allowed range"
msgstr ""
#: tiramisu/option/portoption.py:85
#: tiramisu/option/portoption.py:79
msgid "max value is empty"
msgstr ""
#: tiramisu/option/portoption.py:98
#: tiramisu/option/portoption.py:92
msgid "range must have two values only"
msgstr ""
#: tiramisu/option/portoption.py:101
#: tiramisu/option/portoption.py:95
msgid "first port in range must be smaller than the second one"
msgstr ""
#: tiramisu/option/portoption.py:127
#: tiramisu/option/portoption.py:121
msgid "should be between {0} and {1}"
msgstr ""
#: tiramisu/option/portoption.py:129
#: tiramisu/option/portoption.py:123
msgid "must be between {0} and {1}"
msgstr ""
#: tiramisu/option/stroption.py:41
msgid "which is not a string"
msgstr ""
#: tiramisu/option/symlinkoption.py:51
msgid "malformed symlink second parameters must be an option for \"{0}\", not {1}"
msgstr ""
#: tiramisu/option/urloption.py:92
#: tiramisu/option/urloption.py:91
msgid "must start with http:// or https://"
msgstr ""
#: tiramisu/option/urloption.py:117
msgid "the port \"{0}\" is invalid: {1}"
msgstr ""
#: tiramisu/option/urloption.py:124
msgid "the domain \"{0}\" is invalid: {1}"
msgstr ""
#: tiramisu/option/urloption.py:128
#: tiramisu/option/urloption.py:119
msgid "must ends with a valid resource name"
msgstr ""
#: tiramisu/setting.py:258
#: tiramisu/setting.py:255
msgid "can't rebind {0}"
msgstr ""
#: tiramisu/setting.py:265
#: tiramisu/setting.py:262
msgid "can't unbind {0}"
msgstr ""
#: tiramisu/setting.py:467
#: tiramisu/setting.py:464
msgid "invalid property type {type(new_prop)} for {subconfig.option.impl_getname()} with {prop.function.__name__} function"
msgstr ""
#: tiramisu/setting.py:606
#: tiramisu/setting.py:476
msgid "leader cannot have \"{new_prop}\" property"
msgstr ""
#: tiramisu/setting.py:564
msgid "leader cannot have \"{0}\" property"
msgstr ""
#: tiramisu/setting.py:573
msgid "a leader ({0}) cannot have \"force_default_on_freeze\" or \"force_metaconfig_on_freeze\" property without \"frozen\""
msgstr ""
#: tiramisu/setting.py:607
msgid "permissive must be a frozenset"
msgstr ""
#: tiramisu/setting.py:616
#: tiramisu/setting.py:617
msgid "cannot add those permissives: {0}"
msgstr ""
#: tiramisu/setting.py:653
#: tiramisu/setting.py:654
msgid "can't reset properties to the symlinkoption \"{}\""
msgstr ""
#: tiramisu/setting.py:666
#: tiramisu/setting.py:667
msgid "can't reset permissives to the symlinkoption \"{}\""
msgstr ""
@ -905,19 +805,19 @@ msgstr ""
msgid "unknown action {}"
msgstr ""
#: tiramisu/value.py:570 tiramisu/value.py:872
#: tiramisu/value.py:564 tiramisu/value.py:861
msgid "set owner \"{0}\" is forbidden"
msgstr ""
#: tiramisu/value.py:577
#: tiramisu/value.py:571
msgid "\"{0}\" is a default value, so we cannot change owner to \"{1}\""
msgstr ""
#: tiramisu/value.py:751
#: tiramisu/value.py:740
msgid "index {index} is greater than the length {length} for option {subconfig.option.impl_get_display_name(with_quote=True)}"
msgstr ""
#: tiramisu/value.py:858
#: tiramisu/value.py:847
msgid "information's item not found \"{}\""
msgstr ""

View file

@ -4,7 +4,7 @@ requires = ["flit_core >=3.8.0,<4"]
[project]
name = "tiramisu"
version = "5.2.0a9"
version = "5.1.0"
authors = [{name = "Emmanuel Garette", email = "gnunux@gnunux.info"}]
readme = "README.md"
description = "an options controller tool"
@ -18,8 +18,6 @@ classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Programming Language :: Python :: 3",
"Operating System :: OS Independent",
"Natural Language :: English",
@ -35,9 +33,5 @@ name = "cz_conventional_commits"
tag_format = "$version"
version_scheme = "pep440"
version_provider = "pep621"
version_files = [
"tiramisu/__version__.py",
"pyproject.toml:version"
]
#update_changelog_on_bump = true
changelog_merge_prerelease = true

View file

@ -69,11 +69,11 @@ def test_cache_importation_property():
cfg = Config(od1)
cfg.option('u2').property.add('prop')
export = cfg.property.exportation()
assert cfg.option('u2').property.get() == {'validator', 'prop'}
assert cfg.option('u2').property.get() == {'prop'}
cfg.option('u2').property.add('prop2')
assert cfg.option('u2').property.get() == {'validator', 'prop', 'prop2'}
assert cfg.option('u2').property.get() == {'prop', 'prop2'}
cfg.property.importation(export)
assert cfg.option('u2').property.get() == {'validator', 'prop'}
assert cfg.option('u2').property.get() == {'prop'}
cfg = Config(od1)
# assert not list_sessions()
@ -366,8 +366,8 @@ def test_cache_leader_and_followers():
cfg.value.get()
global_props = ['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings', 'force_store_value']
val1_props = []
val1_val1_props = ['empty', 'unique', 'validator']
val1_val2_props = ['validator']
val1_val1_props = ['empty', 'unique']
val1_val2_props = []
global_props = frozenset(global_props)
val1_props = frozenset(val1_props)
val1_val1_props = frozenset(val1_val1_props)
@ -384,7 +384,7 @@ def test_cache_leader_and_followers():
#
cfg.option('val1.val1').value.set([None])
val_val2_props = {idx_val2: (val1_val2_props, None), None: (set(), None)}
compare(settings.get_cached(), {'val1.val1': {None: ({'validator', 'empty', 'unique'}, None, True)}})
compare(settings.get_cached(), {'val1.val1': {None: ({'empty', 'unique'}, None, True)}})
compare(values.get_cached(), {'val1.val1': {None: ([None], None, True)}})
cfg.value.get()
#has value
@ -416,8 +416,8 @@ def test_cache_leader_callback():
cfg.value.get()
global_props = ['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings', 'force_store_value']
val1_props = []
val1_val1_props = ['empty', 'unique', 'validator']
val1_val2_props = ['validator']
val1_val1_props = ['empty', 'unique']
val1_val2_props = []
global_props = frozenset(global_props)
val1_props = frozenset(val1_props)
val1_val1_props = frozenset(val1_val1_props)
@ -429,7 +429,7 @@ def test_cache_leader_callback():
})
compare(values.get_cached(), {'val1.val1': {None: ([], None)}})
cfg.option('val1.val1').value.set([None])
compare(settings.get_cached(), {'val1.val1': {None: ({'unique', 'empty', 'validator'}, None, True)}})
compare(settings.get_cached(), {'val1.val1': {None: ({'unique', 'empty'}, None, True)}})
compare(values.get_cached(), {'val1.val1': {None: ([None], None, True)}})
cfg.value.get()
@ -451,24 +451,24 @@ def test_cache_requires():
settings = cfg._config_bag.context.properties_cache
assert values.get_cached() == {}
assert cfg.option('ip_address_service').value.get() == None
compare(settings.get_cached(), {'activate_service': {None: ({'validator'}, None)},
'ip_address_service': {None: ({"validator"}, None)}})
compare(settings.get_cached(), {'activate_service': {None: (set([]), None)},
'ip_address_service': {None: (set([]), None)}})
compare(values.get_cached(), {'ip_address_service': {None: (None, None)},
'activate_service': {None: (True, None)}})
cfg.value.get()
compare(settings.get_cached(), {'activate_service': {None: ({"validator"}, None)},
'ip_address_service': {None: ({"validator"}, None)}})
compare(settings.get_cached(), {'activate_service': {None: (set([]), None)},
'ip_address_service': {None: (set([]), None)}})
compare(values.get_cached(), {'ip_address_service': {None: (None, None)},
'activate_service': {None: (True, None)}})
cfg.option('ip_address_service').value.set('1.1.1.1')
compare(settings.get_cached(), {'activate_service': {None: ({"validator"}, None)}})
compare(settings.get_cached(), {'activate_service': {None: (set([]), None)}})
compare(values.get_cached(), {'activate_service': {None: (True, None)}, 'ip_address_service': {None: ('1.1.1.1', None, True)}})
cfg.value.get()
compare(settings.get_cached(), {'activate_service': {None: ({"validator"}, None)},
'ip_address_service': {None: ({"validator"}, None)}})
compare(settings.get_cached(), {'activate_service': {None: (set([]), None)},
'ip_address_service': {None: (set([]), None)}})
compare(values.get_cached(), {'ip_address_service': {None: ('1.1.1.1', None)},
'activate_service': {None: (True, None)}})
@ -477,8 +477,8 @@ def test_cache_requires():
compare(values.get_cached(), {'activate_service': {None: (False, None)}})
cfg.value.get()
compare(settings.get_cached(), {'activate_service': {None: ({"validator"}, None)},
'ip_address_service': {None: ({'disabled', "validator"}, None)}})
compare(settings.get_cached(), {'activate_service': {None: (set([]), None)},
'ip_address_service': {None: (set(['disabled']), None)}})
compare(values.get_cached(), {'activate_service': {None: (False, None)}})
# assert not list_sessions()
@ -499,19 +499,19 @@ def test_cache_global_properties():
settings = cfg._config_bag.context.properties_cache
assert values.get_cached() == {}
assert cfg.option('ip_address_service').value.get() == None
compare(settings.get_cached(), {'activate_service': {None: ({"validator"}, None)},
'ip_address_service': {None: ({"validator"}, None)}})
compare(settings.get_cached(), {'activate_service': {None: (set([]), None)},
'ip_address_service': {None: (set([]), None)}})
compare(values.get_cached(), {'ip_address_service': {None: (None, None)},
'activate_service': {None: (True, None)}})
cfg.property.remove('disabled')
assert cfg.option('ip_address_service').value.get() == None
compare(settings.get_cached(), {'activate_service': {None: ({"validator"}, None)},
'ip_address_service': {None: ({"validator"}, None)}})
compare(settings.get_cached(), {'activate_service': {None: (set([]), None)},
'ip_address_service': {None: (set([]), None)}})
cfg.property.add('test')
assert cfg.option('ip_address_service').value.get() == None
compare(settings.get_cached(), {'activate_service': {None: ({"validator"}, None)},
'ip_address_service': {None: ({"validator"}, None)}})
compare(settings.get_cached(), {'activate_service': {None: (set([]), None)},
'ip_address_service': {None: (set([]), None)}})
# assert not list_sessions()

View file

@ -380,12 +380,12 @@ def test_prefix_error():
try:
cfg.option('test1').value.set('yes')
except Exception as err:
assert str(err) == _('"{0}" is an invalid {1} for "{2}", which is not an integer').format('yes', _('integer'), 'test1')
assert str(err) == _('"{0}" is an invalid {1} for "{2}"').format('yes', _('integer'), 'test1')
try:
cfg.option('test1').value.set('yes')
except Exception as err:
err.prefix = ''
assert str(err) == _('which is not an integer')
assert str(err) == _('invalid value')
# assert not list_sessions()

View file

@ -423,7 +423,7 @@ def test_config_reset():
cfg.owner.set('test')
assert cfg.owner.get() == 'test'
assert not cfg.option('gc.gc2.bool').value.get()
assert cfg.option('boolop').property.get() == frozenset(["validator"])
assert not cfg.option('boolop').property.get()
assert not cfg.option('boolop').permissive.get()
assert not cfg.option('wantref').information.get('info', None)
#
@ -440,7 +440,7 @@ def test_config_reset():
cfg.config.reset()
assert cfg.owner.get() == 'test'
assert not cfg.option('gc.gc2.bool').value.get()
assert cfg.option('boolop').property.get() == {"validator"}
assert not cfg.option('boolop').property.get()
assert not cfg.option('float').permissive.get()
assert not cfg.option('wantref').information.get('info', None)
# assert not list_sessions()

View file

@ -275,9 +275,3 @@ def test_url(config_type):
with pytest.raises(ValueError):
cfg.option('u').value.set('https://FOO.COM:8443')
# assert not list_sessions()
def test_domainname_existence():
DomainnameOption('d', '', 'google.fr', test_existence=True)
with pytest.raises(ValueError):
DomainnameOption('d', '', 'ljijouuuehyfr.com', test_existence=True)

View file

@ -300,20 +300,20 @@ def test_prop_dyndescription():
od = OptionDescription('od', '', [dod])
od2 = OptionDescription('od', '', [od])
cfg = Config(od2)
assert set(cfg.option('od.dodval1.st').property.get()) == {'test', "validator"}
assert set(cfg.option('od.dodval2.st').property.get()) == {'test', "validator"}
assert set(cfg.option('od.dodval1.st').property.get()) == set(['test'])
assert set(cfg.option('od.dodval2.st').property.get()) == set(['test'])
cfg.option('od.dodval2.st').property.add('test2')
assert set(cfg.option('od.dodval1.st').property.get()) == {'test', "validator"}
assert set(cfg.option('od.dodval2.st').property.get()) == {'test', 'test2', "validator"}
assert set(cfg.option('od.dodval1.st').property.get()) == set(['test'])
assert set(cfg.option('od.dodval2.st').property.get()) == set(['test', 'test2'])
#
assert set(cfg.option('od.dodval1').property.get()) == set()
assert set(cfg.option('od.dodval2').property.get()) == set()
assert set(cfg.option('od.dodval1').property.get()) == set([])
assert set(cfg.option('od.dodval2').property.get()) == set([])
cfg.option('od.dodval1').property.add('test1')
assert set(cfg.option('od.dodval1').property.get()) == {'test1'}
assert set(cfg.option('od.dodval2').property.get()) == set()
assert set(cfg.option('od.dodval1').property.get()) == set(['test1'])
assert set(cfg.option('od.dodval2').property.get()) == set([])
cfg.option('od.dodval1').property.remove('test1')
assert set(cfg.option('od.dodval1').property.get()) == set()
assert set(cfg.option('od.dodval2').property.get()) == set()
assert set(cfg.option('od.dodval1').property.get()) == set([])
assert set(cfg.option('od.dodval2').property.get()) == set([])
# assert not list_sessions()
@ -432,20 +432,6 @@ 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')
@ -616,14 +602,14 @@ def test_prop_dyndescription_context():
od = OptionDescription('od', '', [dod, val1])
od2 = OptionDescription('od', '', [od])
cfg = Config(od2)
assert set(cfg.option('od.dodval1.st').property.get()) == {"validator", 'test'}
assert set(cfg.option('od.dodval2.st').property.get()) == {"validator", 'test'}
assert set(cfg.option('od.dodval1.st').property.get()) == set(['test'])
assert set(cfg.option('od.dodval2.st').property.get()) == set(['test'])
cfg.option('od.dodval2.st').property.add('test2')
assert set(cfg.option('od.dodval1.st').property.get()) == {"validator", 'test'}
assert set(cfg.option('od.dodval2.st').property.get()) == {"validator", 'test', 'test2'}
assert set(cfg.option('od.dodval1.st').property.get()) == set(['test'])
assert set(cfg.option('od.dodval2.st').property.get()) == set(['test', 'test2'])
cfg.option('od.dodval1.st').permissive.add('test')
assert set(cfg.option('od.dodval1.st').property.get()) == {"validator"}
assert set(cfg.option('od.dodval2.st').property.get()) == {"validator", 'test', 'test2'}
assert set(cfg.option('od.dodval1.st').property.get()) == set([])
assert set(cfg.option('od.dodval2.st').property.get()) == set(['test', 'test2'])
# assert not list_sessions()

View file

@ -6,7 +6,7 @@ import pytest
from tiramisu.setting import groups, owners
from tiramisu import ChoiceOption, BoolOption, IntOption, IPOption, NetworkOption, NetmaskOption, \
StrOption, OptionDescription, Leadership, Config, Calculation, ParamValue, ParamOption, calc_value, Params, submulti
StrOption, OptionDescription, Leadership, Config, Calculation, ParamValue, calc_value, Params
from tiramisu.error import LeadershipError, PropertiesOptionError, ConfigError
@ -788,19 +788,6 @@ def test_values_with_leader_and_followers_leader_pop():
# assert not list_sessions()
def test_values_with_leader_and_followers_leader_pop_default_value():
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", default=["192.168.230.145", "192.168.230.146"], multi=True, properties=('notunique',))
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", default_multi="255.255.255.0", multi=True)
interface1 = Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
od1 = OptionDescription('toto', '', [interface1])
cfg = Config(od1)
cfg.property.read_write()
cfg.option('ip_admin_eth0.ip_admin_eth0').value.pop(0)
compare(cfg.value.exportation(), {'ip_admin_eth0.ip_admin_eth0': {None: [['192.168.230.146'], 'user']}})
assert cfg.option('ip_admin_eth0.ip_admin_eth0').value.get() == ["192.168.230.146"]
assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() == '255.255.255.0'
def test_follower_unique():
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True, properties=('unique',))
@ -809,7 +796,7 @@ def test_follower_unique():
cfg = Config(od1)
cfg.option('ip_admin_eth0.ip_admin_eth0').value.set(["192.168.230.145", "192.168.230.146"])
# unique property is removed for a follower
assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 1).property.get() == {"validator"}
assert not cfg.option('ip_admin_eth0.netmask_admin_eth0', 1).property.get()
# assert not list_sessions()
@ -1106,25 +1093,3 @@ def test_leader_forbidden_properties_callback(config_type):
cfg = Config(od1)
with pytest.raises(LeadershipError):
cfg.option('ip_admin_eth0.ip_admin_eth0').value.get()
def test_follower_value_not_list():
ip_admin_eth0 = IPOption('ip_admin_eth0', "ip réseau autorisé", multi=True, default=['1.1.1.1'])
netmask_admin_eth0 = NetmaskOption('netmask_admin_eth0', "masque du sous-réseau", default_multi='255.255.255.0', multi=True, properties=('force_store_value',))
interface0 = Leadership('interface0', '', [ip_admin_eth0, netmask_admin_eth0])
od1 = OptionDescription('od', '', [interface0])
od2 = OptionDescription('root', '', [od1])
cfg = Config(od2)
cfg.property.read_write()
with pytest.raises(ValueError):
cfg.option('od.interface0.ip_admin_eth0').value.set(None)
def test_default_calc():
var1 = StrOption('var1', "", multi=True, default=['leader1', 'leader2'], properties=frozenset({"mandatory",}))
var2 = StrOption('var2', "", default_multi=[Calculation(calc_value, Params((ParamOption(var1))))], multi=submulti, properties=frozenset({"mandatory",}))
leader = Leadership('interface0', '', [var1, var2])
od1 = OptionDescription('od', '', [leader])
od2 = OptionDescription('root', '', [od1])
cfg = Config(od2)
assert parse_od_get(cfg.value.get()) == {'od.interface0.var1': [{'od.interface0.var1': 'leader1', 'od.interface0.var2': ['leader1']}, {'od.interface0.var1': 'leader2', 'od.interface0.var2': ['leader2']}]}

View file

@ -945,7 +945,7 @@ def test_consistency_leader_and_followers_leader_mandatory_transitive():
try:
cfg.option('val1.val2', 0).value.get()
except PropertiesOptionError as error:
assert str(error) == str(_('cannot access to {0} {1} at index "{2}" because has {3} {4}').format('option', '"val2"', 0, _('property'), '"disabled"'))
assert str(error) == str(_('cannot access to {0} {1} because has {2} {3}').format('option', '"val2"', _('property'), '"disabled"'))
else:
raise Exception('must raises')
assert list(cfg.value.mandatory()) == []

View file

@ -202,10 +202,10 @@ def test_property_get_unique_empty():
od1 = OptionDescription("options", "", [s, s2, s3, s4])
cfg = Config(od1)
cfg.property.read_write()
assert cfg.option('string').property.get() == {"validator", 'empty', 'unique'}
assert cfg.option('string2').property.get() == {"validator", 'empty', 'notunique'}
assert cfg.option('string3').property.get() == {"validator", 'unique', 'notempty'}
assert cfg.option('string4').property.get() == {"validator", 'notunique', 'notempty'}
assert cfg.option('string').property.get() == {'empty', 'unique'}
assert cfg.option('string2').property.get() == {'empty', 'notunique'}
assert cfg.option('string3').property.get() == {'unique', 'notempty'}
assert cfg.option('string4').property.get() == {'notunique', 'notempty'}
# assert not list_sessions()
@ -220,7 +220,7 @@ def test_property_only_raises():
od1 = OptionDescription("options", "", [s, intoption, stroption])
cfg = Config(od1)
cfg.property.read_write()
assert cfg.option('str').property.get() == {'empty', 'unique', 'validator'}
assert cfg.option('str').property.get() == {'empty', 'unique'}
assert cfg.option('str').property.get(only_raises=True) == set()
# assert not list_sessions()
@ -569,23 +569,23 @@ def test_access_by_get_whith_hide():
def test_append_properties():
od1 = make_description()
cfg = Config(od1)
assert cfg.option('gc.dummy').property.get() == {"validator"}
assert cfg.option('gc.dummy').property.get() == set()
cfg.option('gc.dummy').property.add('test')
assert cfg.option('gc.dummy').property.get() == {'test', "validator"}
assert cfg.option('gc.dummy').property.get() == {'test'}
with pytest.raises(ConfigError):
cfg.option('gc.dummy').property.add('force_store_value')
assert cfg.option('gc.dummy').property.get() == {'test', "validator"}
assert cfg.option('gc.dummy').property.get() == {'test'}
# assert not list_sessions()
def test_reset_properties():
od1 = make_description()
cfg = Config(od1)
assert cfg.option('gc.dummy').property.get() == {"validator"}
assert cfg.option('gc.dummy').property.get() == set()
cfg.option('gc.dummy').property.add('frozen')
assert cfg.option('gc.dummy').property.get() == {"validator", 'frozen'}
assert cfg.option('gc.dummy').property.get() == {'frozen'}
cfg.option('gc.dummy').property.reset()
assert cfg.option('gc.dummy').property.get() == {"validator"}
assert cfg.option('gc.dummy').property.get() == set()
# assert not list_sessions()
@ -594,7 +594,7 @@ def test_properties_cached():
od1 = OptionDescription("opt", "", [OptionDescription("sub", "", [b1])])
cfg = Config(od1)
cfg.property.read_write()
assert cfg.option('sub.b1').property.get() == {'test', "validator"}
assert cfg.option('sub.b1').property.get() == {'test'}
# assert not list_sessions()
@ -603,9 +603,9 @@ def test_append_properties_force_store_value():
gcgroup = OptionDescription('gc', '', [gcdummy])
od1 = OptionDescription('tiramisu', '', [gcgroup])
cfg = Config(od1)
assert cfg.option('gc.dummy').property.get() == {'force_store_value', "validator"}
assert cfg.option('gc.dummy').property.get() == {'force_store_value'}
cfg.option('gc.dummy').property.add('test')
assert cfg.option('gc.dummy').property.get() == {'force_store_value', 'test', "validator"}
assert cfg.option('gc.dummy').property.get() == {'force_store_value', 'test'}
# assert not list_sessions()

View file

@ -121,34 +121,6 @@ def test_validator(config_type):
# assert not list_sessions()
def test_validator_no_validation(config_type):
opt1 = StrOption('opt1', '', validators=[Calculation(return_true, Params(ParamSelfOption()))], default='val', properties=frozenset(['novalidator']))
opt2 = StrOption('opt2', '', validators=[Calculation(return_false, Params(ParamSelfOption()))], properties=frozenset(['novalidator']))
od1 = OptionDescription('root', '', [opt1, opt2])
cfg_ori = Config(od1)
cfg = get_config(cfg_ori, config_type)
assert cfg.option('opt1').value.get() == 'val'
assert cfg.option('opt2').value.valid() is True
cfg.option('opt2').value.set('val')
def test_validator_no_validation2(config_type):
opt1 = StrOption('opt1', '', properties=frozenset(['novalidator']))
od1 = OptionDescription('root', '', [opt1])
cfg_ori = Config(od1)
cfg = get_config(cfg_ori, config_type)
cfg.option('opt1').value.set(1)
assert cfg.option('opt1').value.get() == 1
def test_validator_no_validation3(config_type):
opt1 = StrOption('opt1', '', 1, properties=frozenset(['novalidator']))
od1 = OptionDescription('root', '', [opt1])
cfg_ori = Config(od1)
cfg = get_config(cfg_ori, config_type)
assert cfg.option('opt1').value.get() == 1
def test_validator_not_valid(config_type):
with pytest.raises(ValueError):
StrOption('not_a_list', '', validators=Calculation(return_true, Params(ParamSelfOption())), default='val')

View file

@ -426,9 +426,9 @@ def test_requires_transitive_unrestraint(config_type):
#
if config_type == 'tiramisu-api':
cfg.send()
assert cfg_ori.option('activate_service_web').property.get() == {'disabled', "validator"}
assert cfg_ori.option('activate_service_web').property.get() == {'disabled'}
# FIXME assert cfg_ori.unrestraint.option('ip_address_service_web').property.get() == {'disabled'}
assert cfg_ori.option('ip_address_service_web').property.get() == {'disabled', "validator"}
assert cfg_ori.option('ip_address_service_web').property.get() == {'disabled'}
# assert not list_sessions()

View file

@ -28,8 +28,6 @@ def test_symlink_option(config_type):
assert cfg.option('c').issymlinkoption()
assert cfg.option('s1.b').type() == 'boolean'
assert cfg.option('c').type() == 'boolean'
assert cfg.option('s1.b').type(only_self=True) == 'boolean'
assert cfg.option('c').type(only_self=True) == 'symlink'
assert cfg.option('s1.b').value.get() is False
cfg.option("s1.b").value.set(True)
cfg.option("s1.b").value.set(False)
@ -159,7 +157,7 @@ def test_symlink_getproperties():
od1 = OptionDescription('opt', '', [boolopt, linkopt])
cfg = Config(od1)
cfg.property.read_write()
assert boolopt.impl_getproperties() == linkopt.impl_getproperties() == {'test', "validator"}
assert boolopt.impl_getproperties() == linkopt.impl_getproperties() == {'test'}
# assert boolopt.impl_has_callback() == linkopt.impl_has_callback() == False
# assert not list_sessions()

View file

@ -42,7 +42,6 @@ from .error import ConfigError
from .api import Config, MetaConfig, GroupConfig, MixConfig
from .option import __all__ as all_options
from .setting import owners, groups, undefined
from .__version__ import __version__
allfuncs = [
@ -77,3 +76,4 @@ allfuncs.extend(all_options)
del all_options
__all__ = tuple(allfuncs)
del allfuncs
__version__ = "4.1.0"

View file

@ -1 +0,0 @@
__version__ = "5.2.0a9"

View file

@ -139,8 +139,6 @@ def option_type(typ):
@wraps(func)
def wrapped(*args, **kwargs):
self = args[0]
if isinstance(typ, list) and "allow_dynoption" in typ:
self._allow_dynoption = True
config_bag = self._config_bag
if self._config_bag.context.impl_type == "group" and "group" in types:
options_bag = [
@ -274,15 +272,7 @@ class _TiramisuOptionOptionDescription:
_validate_properties = False
@option_type(
[
"optiondescription",
"option",
"with_or_without_index",
"symlink",
"allow_dynoption",
]
)
@option_type(["optiondescription", "option", "with_or_without_index", "symlink"])
def get(self):
"""Get Tiramisu option"""
return self._subconfig.option
@ -300,14 +290,11 @@ class _TiramisuOptionOptionDescription:
@option_type(["optiondescription", "option", "with_or_without_index", "symlink"])
def description(
self,
with_quote: bool = False,
uncalculated: bool = False,
):
"""Get option description"""
if not uncalculated:
return self._subconfig.option.impl_get_display_name(
self._subconfig, with_quote=with_quote
)
return self._subconfig.option.impl_get_display_name(self._subconfig)
return self._subconfig.option._get_information(
self._subconfig,
"doc",
@ -360,13 +347,11 @@ class _TiramisuOptionOptionDescription:
return options
@option_type(["option", "optiondescription", "symlink", "with_or_without_index"])
def type(self, only_self=False):
def type(self):
"""Get de option type"""
option = self._subconfig.option
if option.impl_is_optiondescription():
return "optiondescription"
if only_self and option.impl_is_symlinkoption():
return "symlink"
return option.get_type()
@option_type(["option", "symlink", "with_or_without_index"])
@ -816,11 +801,14 @@ class TiramisuOptionValue(CommonTiramisuOption, _TiramisuODGet):
option = self._subconfig.option
if (
not isinstance(value, Calculation)
and isinstance(value, list)
and option.impl_is_leader()
and len(value) < self._subconfig.parent.get_length_leadership()
):
raise LeadershipError(self._subconfig, "leadership-reduce")
raise LeadershipError(
_("cannot reduce length of the leader {}" "").format(
option.impl_get_display_name(self._subconfig, with_quote=True)
)
)
values = self._config_bag.context.get_values()
return values.set_value(self._subconfig, value)
@ -918,39 +906,34 @@ class TiramisuOptionValue(CommonTiramisuOption, _TiramisuODGet):
def mandatory(self):
"""Return path of options with mandatory property without any value"""
subconfig = self._subconfig
ori_config_bag = self._subconfig.config_bag
config_bag = ori_config_bag.copy()
config_bag.properties -= {"mandatory", "empty", "warnings"}
config_bag.set_permissive()
self._subconfig.config_bag = config_bag
try:
if subconfig.option.impl_is_optiondescription():
options = []
for subconfig in config_bag.context.walk(
self._subconfig,
only_mandatory=True,
):
options.append(
TiramisuOption(
subconfig.path,
subconfig.index,
ori_config_bag,
subconfig=subconfig,
)
if subconfig.option.impl_is_optiondescription():
ori_config_bag = self._subconfig.config_bag
config_bag = ori_config_bag.copy()
config_bag.properties -= {"mandatory", "empty", "warnings"}
config_bag.set_permissive()
self._subconfig.config_bag = config_bag
options = []
for subconfig in self._config_bag.context.walk(
self._subconfig,
only_mandatory=True,
):
options.append(
TiramisuOption(
subconfig.path,
subconfig.index,
ori_config_bag,
subconfig=subconfig,
)
self._subconfig.config_bag = ori_config_bag
return options
try:
self._config_bag.context.walk_valid_value(
self._subconfig, only_mandatory=True
)
except PropertiesOptionError as err:
return err.proptype == ["mandatory"] or err.proptype == ["empty"]
self._subconfig.config_bag = ori_config_bag
return False
except Exception as err:
self._subconfig.config_bag = ori_config_bag
raise err from err
return options
try:
self._config_bag.context.walk_valid_value(
self._subconfig, only_mandatory=True
)
except PropertiesOptionError as err:
return err.proptype == ["mandatory"] or err.proptype == ["empty"]
return False
def _registers(
@ -1544,7 +1527,7 @@ class TiramisuContextOption(TiramisuConfig, _TiramisuOptionWalk):
def get(self):
"""Get Tiramisu option"""
return self._config_bag.context.get_description()
return None
def isleadership(self):
"""Test if option is a leader or a follower"""

View file

@ -22,15 +22,7 @@ from typing import Any, Optional, Union, Callable, Dict, List
from itertools import chain
import weakref
from .error import (
PropertiesOptionError,
ConfigError,
LeadershipError,
ValueWarning,
CancelParam,
display_list,
errors,
)
from .error import PropertiesOptionError, ConfigError, LeadershipError, ValueWarning
from .i18n import _
from .setting import undefined, ConfigBag
from .function import FUNCTION_WAITING_FOR_DICT, FUNCTION_WAITING_FOR_ERROR
@ -57,7 +49,6 @@ def get_calculated_value(
has_calculation = True
elif isinstance(value, list):
# if value is a list, do subcalculation
value = value.copy()
for idx, val in enumerate(value):
value[idx], _has_calculation = get_calculated_value(
subconfig,
@ -157,15 +148,11 @@ class ParamDynOption(ParamOption):
)
if not isinstance(identifiers, list):
raise Exception(
_("identifiers in ParamDynOption must be a list, not {0}").format(
identifiers
)
f"identifiers in ParamDynOption must be a list, not {identifiers}"
)
if not isinstance(optional, bool):
raise Exception(
_("optional in ParamDynOption must be a boolean, not {0}").format(
optional
)
f"optional in ParamDynOption must be a boolean, not {optional}"
)
self.identifiers = identifiers
self.optional = optional
@ -216,11 +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(
@ -460,7 +445,14 @@ def manager_callback(
or param.raisepropertyerror
):
raise err from err
raise ConfigError(err)
display_name = subconfig.option.impl_get_display_name(
subconfig, with_quote=True
)
raise ConfigError(
_("unable to carry out a calculation for {}, {}").format(
display_name, err
)
) from err
except ValueError as err:
display_name = subconfig.option.impl_get_display_name(
subconfig, with_quote=True
@ -472,15 +464,20 @@ def manager_callback(
) from err
except AttributeError as err:
if isinstance(param, ParamDynOption) and param.optional:
# cannot access, simulate a propertyerror
# cannot acces, simulate a propertyerror
raise PropertiesOptionError(
subconfig,
["configerror"],
config_bag.context.get_settings(),
)
errors.raise_carry_out_calculation_error(
subconfig, _("unable to get value for calculating {0}, {1}"), err
display_name = subconfig.option.impl_get_display_name(
subconfig, with_quote=True
)
raise ConfigError(
_("unable to get value for calculating {0}, {1}").format(
display_name, err
)
) from err
return value
def get_option_bag(
@ -512,12 +509,12 @@ def manager_callback(
# raise PropertiesOptionError (which is catched) because must not add value None in carry_out_calculation
if param.notraisepropertyerror or param.raisepropertyerror:
raise err from err
errors.raise_carry_out_calculation_error(
subconfig,
_("unable to carry out a calculation for {0}, {1}"),
err,
option=option,
)
display_name = option.impl_get_display_name(subconfig, with_quote=True)
raise ConfigError(
_("unable to carry out a calculation for {}, {}").format(
display_name, err
)
) from err
except ValueError as err:
display_name = option.impl_get_display_name(subconfig, with_quote=True)
raise ValueError(
@ -527,18 +524,18 @@ def manager_callback(
) from err
except AttributeError as err:
if isinstance(param, ParamDynOption) and param.optional:
# cannot access, simulate a propertyerror
# cannot acces, simulate a propertyerror
raise PropertiesOptionError(
param,
["configerror"],
config_bag.context.get_settings(),
)
errors.raise_carry_out_calculation_error(
subconfig,
_("unable to get value for calculating {0}, {1}"),
err,
option=option,
)
display_name = option.impl_get_display_name(subconfig, with_quote=True)
raise ConfigError(
_("unable to get value for calculating {0}, {1}").format(
display_name, err
)
) from err
return subsubconfig
if isinstance(param, ParamValue):
@ -555,15 +552,14 @@ def manager_callback(
true_path=subconfig.path,
)
if isinstance(isubconfig, list):
display_name = option.impl_get_display_name(
subconfig, with_quote=True
)
search_name = search_option.impl_get_display_name(
None, with_quote=True
)
errors.raise_carry_out_calculation_error(
subconfig,
_("cannot find information for {0}, {1} is a dynamic option"),
None,
option=option,
extra_keys=[search_name],
raise ConfigError(
f"cannot find information for {display_name}, {search_name} is a dynamic option"
)
else:
isubconfig = get_option_bag(
@ -583,12 +579,12 @@ def manager_callback(
param.default_value,
)
except ValueError as err:
errors.raise_carry_out_calculation_error(
subconfig,
_("unable to get value for calculating {0}, {1}"),
err,
option=option,
)
display_name = option.impl_get_display_name(subconfig, with_quote=True)
raise ConfigError(
_("unable to get value for calculating {0}, {1}").format(
display_name, err
)
) from err
if isinstance(param, ParamIndex):
return index
@ -598,17 +594,14 @@ def manager_callback(
not option.impl_is_optiondescription()
or not option.impl_is_dynoptiondescription()
):
errors.raise_carry_out_calculation_error(
subconfig,
display_name = subconfig.option.impl_get_display_name(
subconfig, with_quote=True
)
raise ConfigError(
_(
"option {0} is not a dynoptiondescription or in a dynoptiondescription"
),
None,
option=option,
).format(display_name)
)
if subconfig.identifiers is None:
# if uncalculated
return
return subconfig.identifiers[param.identifier_index]
if isinstance(param, ParamSelfOption):
@ -680,37 +673,7 @@ def manager_callback(
parent,
)
except AttributeError as err:
if parent.path:
child_path = parent.path + "." + name
else:
child_path = name
if param.optional:
raise CancelParam(
callbk_option.impl_getpath(), child_path
)
identifiers = doption.get_identifiers(parent)
if not identifiers:
errors.raise_carry_out_calculation_error(
subconfig,
_(
'cannot calculate arguments for {0}, {1} with identifier "{2}", there is no identifiers'
),
err,
extra_keys=[identifier],
)
else:
identifiers_list = display_list(
identifiers, add_quote=True
)
errors.raise_carry_out_calculation_error(
subconfig,
_(
'cannot calculate arguments for {0}, {1} with identifier "{2}", list of valid identifiers: {3}'
),
err,
extra_keys=[identifier, identifiers_list],
)
raise ConfigError(err) from err
new_parents.append(
parent.get_child(
doption,
@ -814,11 +777,8 @@ def carry_out_calculation(
and option.impl_is_follower()
and index is None
):
errors.raise_carry_out_calculation_error(
subconfig,
_("the follower {0} must have index in carry_out_calculation!"),
None,
option=option,
raise ConfigError(
f"the follower {option.impl_get_display_name(subconfig, with_quote=True)} must have index in carry_out_calculation!"
)
def fake_items(iterator):
@ -868,12 +828,6 @@ 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,
@ -889,14 +843,33 @@ def carry_out_calculation(
and option.impl_is_follower()
and not option.impl_is_submulti()
):
raise LeadershipError(
subconfig,
"leadership-follower-callback-list",
callback=callback.__name__,
args=args,
kwargs=kwargs,
ret=ret,
)
if args or kwargs:
raise LeadershipError(
_(
'the "{}" function with positional arguments "{}" '
'and keyword arguments "{}" must not return '
'a list ("{}") for the follower option {}'
""
).format(
callback.__name__,
args,
kwargs,
ret,
option.impl_get_display_name(subconfig, with_quote=True),
)
)
else:
raise LeadershipError(
_(
'the "{}" function must not return a list ("{}") '
"for the follower option {}"
""
).format(
callback.__name__,
ret,
option.impl_get_display_name(subconfig, with_quote=True),
)
)
return ret
@ -920,7 +893,7 @@ def calculate(
except (ValueError, ValueWarning) as err:
if allow_value_error:
if force_value_warning:
raise ValueWarning(msg=str(err))
raise ValueWarning(str(err))
raise err from err
error = err
except ConfigError as err:
@ -929,17 +902,19 @@ def calculate(
error = err
if args or kwargs:
msg = _(
'unexpected error "{1}" in function "{2}" with arguments "{3}" and "{4}" '
"for option {0}"
)
extra_keys = [
'unexpected error "{0}" in function "{1}" with arguments "{3}" and "{4}" '
"for option {2}"
).format(
str(error),
callback.__name__,
subconfig.option.impl_get_display_name(subconfig, with_quote=True),
args,
kwargs,
]
)
else:
msg = _('unexpected error "{1}" in function "{2}" for option {0}')
extra_keys = [callback.__name__]
errors.raise_carry_out_calculation_error(
subconfig, msg, error, extra_keys=extra_keys
)
msg = _('unexpected error "{0}" in function "{1}" for option {2}' "").format(
str(error),
callback.__name__,
subconfig.option.impl_get_display_name(subconfig, with_quote=True),
)
raise ConfigError(msg) from error

View file

@ -41,7 +41,7 @@ def get_common_path(path1, path2):
return common_path
if common_path.endswith("."):
return common_path[:-1]
elif "." in common_path:
if "." in common_path:
return common_path.rsplit(".", 1)[0]
return None
@ -227,8 +227,7 @@ class SubConfig:
identifiers: Optional[list[str]],
*,
true_path: Optional[str] = None,
# for python 3.9 properties: Union[list[str], undefined] = undefined,
properties=undefined,
properties: Union[list[str], undefined] = undefined,
validate_properties: bool = True,
) -> None:
self.index = index
@ -417,7 +416,13 @@ class SubConfig:
length = self.get_length_leadership()
if index >= length:
raise LeadershipError(
subsubconfig, "leadership-greater", index=index, length=length
_(
'index "{0}" is greater than the leadership length "{1}" for option {2}'
).format(
index,
length,
option.impl_get_display_name(subsubconfig, with_quote=True),
)
)
return subsubconfig
@ -863,10 +868,9 @@ class _Config(CCache):
subconfig, with_quote=True
)
raise LeadershipError(
subconfig,
"leadership-follower-greater",
index=follower_len,
length=length,
_(
"the follower option {0} has greater length ({1}) than the leader length ({2})"
).format(option_name, follower_len, length)
)
self.get_settings().validate_mandatory(
subconfig,

View file

@ -18,23 +18,6 @@
import weakref
from .i18n import _
from typing import Literal, Union
TiramisuErrorCode = Literal[
"option-dynamic",
"option-not-found",
"property-frozen",
"property-error",
"property-mandatory",
"leadership-group_type",
"leadership-wrong_property",
"leadership-force_default_on_freeze",
"leadership-greater",
"leadership-follower-greater",
"leadership-follower-callback-list",
]
def display_list(
lst,
@ -86,8 +69,6 @@ class PropertiesOptionError(AttributeError):
orig_opt=None,
help_properties=None,
):
if orig_opt:
raise Exception("a la")
if opt_type:
self._opt_type = opt_type
self._name = name
@ -106,23 +87,10 @@ class PropertiesOptionError(AttributeError):
self.help_properties = help_properties
self._settings = settings
self.msg = None
if not self.help_properties:
self.help_properties = self.proptype
properties = list(self.help_properties)
if properties == ["frozen"]:
self.code = "property-frozen"
elif properties == ["mandatory"]:
self.code = "property-mandatory"
else:
self.code = "property-error"
super().__init__(None)
def display_properties(self, force_property=False, add_quote=True):
if force_property:
properties = self.proptype
else:
properties = self.help_properties
return display_list(list(properties), add_quote=add_quote)
def set_orig_opt(self, opt):
self._orig_opt = opt
def __str__(self):
# this part is a bit slow, so only execute when display
@ -130,81 +98,42 @@ class PropertiesOptionError(AttributeError):
return self.msg
if self._settings is None:
return "error"
arguments = [self._opt_type]
if self._orig_opt:
arguments.append(
self._orig_opt.impl_get_display_name(subconfig, with_quote=True)
)
arguments.append(self._name)
index = self._subconfig.index
if index is not None:
arguments.append(index)
if self.code == "property-frozen":
if index is not None:
if self._orig_opt:
msg = _(
'cannot modify the {0} {1} at index "{2}" because {3} is frozen'
)
else:
msg = _(
'cannot modify the {0} {1} at index "{2}" because is frozen'
)
else:
if self._orig_opt:
msg = _("cannot modify the {0} {1} because {2} is frozen")
else:
msg = _("cannot modify the {0} {1} because is frozen")
elif self.code == "property-mandatory":
if index is not None:
if self._orig_opt:
msg = _(
'cannot access to {0} {1} at index "{2}" because {3} hasn\'t value'
)
else:
msg = _('{0} {1} at index "{2}" is mandatory but hasn\'t value')
else:
if self._orig_opt:
msg = _("cannot access to {0} {1} because {2} hasn't value")
else:
msg = _("{0} {1} is mandatory but hasn't value")
if self.help_properties:
properties = list(self.help_properties)
else:
if index is not None:
if self._orig_opt:
msg = _(
'cannot access to {0} {1} at index "{2}" because {3} has {4} {5}'
)
else:
msg = _(
'cannot access to {0} {1} at index "{2}" because has {3} {4}'
)
properties = list(self.proptype)
only_one = len(properties) == 1
properties_msg = display_list(properties, add_quote=True)
if only_one:
prop_msg = _("property")
else:
prop_msg = _("properties")
if properties == ["frozen"]:
if self._orig_opt:
msg = _('cannot modify the {0} {1} because "{2}" has {3} {4}')
else:
if self._orig_opt:
msg = _("cannot access to {0} {1} because {2} has {3} {4}")
else:
msg = _("cannot access to {0} {1} because has {2} {3}")
only_one = len(self.help_properties) == 1
if only_one:
arguments.append(_("property"))
msg = _("cannot modify the {0} {1} because has {2} {3}")
else:
if self._orig_opt:
msg = _('cannot access to {0} {1} because "{2}" has {3} {4}')
else:
arguments.append(_("properties"))
arguments.append(self.display_properties())
self.msg = msg.format(*arguments)
msg = _("cannot access to {0} {1} because has {2} {3}")
if self._orig_opt:
# FIXME _orig_opt ?
self.msg = msg.format(
self._opt_type,
self._orig_opt.impl_get_display_name(subconfig, with_quote=True),
self._name,
prop_msg,
properties_msg,
)
else:
self.msg = msg.format(self._opt_type, self._name, prop_msg, properties_msg)
del self._opt_type, self._name
del self._settings, self._orig_opt
return self.msg
class AttributeOptionError(AttributeError):
def __init__(self, path: str, code: TiramisuErrorCode) -> None:
self.path = path
self.code = code
def __str__(self) -> str:
if self.code == "option-dynamic":
return _('cannot access to "{0}" it\'s a dynamic option').format(self.path)
return _('"{0}" is not an option').format(self.path)
# ____________________________________________________________
# Exceptions for a Config
class ConfigError(Exception):
@ -229,74 +158,8 @@ class ConflictError(Exception):
# ____________________________________________________________
# miscellaneous exceptions
class LeadershipError(Exception):
def __init__(
self,
subconfig: Union[str, "SubConfig"],
code,
*,
prop=None,
index=None,
length=None,
callback=None,
args=None,
kwargs=None,
ret=None,
):
if isinstance(subconfig, str):
self.path = self.display_name = subconfig
else:
self.path = subconfig.path
option = subconfig.option
self.display_name = option.impl_get_display_name(subconfig, with_quote=True)
self.code = code
if prop:
self.prop = prop
if index:
self.index = index
if length:
self.length = length
if callback:
self.callback = callback
if args:
self.args = args
if kwargs:
self.kwargs = kwargs
if ret:
self.ret = ret
def __str__(self):
if self.code == "leadership-group_type":
return _('cannot set "group_type" attribute for the Leadership {0}').format(
self.display_name
)
if self.code == "leadership-wrong_property":
return _('the leader {0} cannot have "{1}" property').format(
self.display_name, self.prop
)
if self.code == "leadership-force_default_on_freeze":
return _(
'the leader {0} cannot have "force_default_on_freeze" or "force_metaconfig_on_freeze" property without "frozen"'
).format(self.display_name)
if self.code == "leadership-reduce":
return _("cannot reduce length of the leader {0}").format(self.display_name)
if self.code == "leadership-greater":
return _(
'index "{0}" is greater than the leadership length "{1}" for option {2}'
).format(self.index, self.length, self.display_name)
if self.code == "leadership-follower-greater":
return _(
"the follower option {0} has greater length ({1}) than the leader length ({2})"
).format(self.display_name, self.index, self.length)
if self.code == "leadership-follower-callback-list":
if self.args or self.kwargs:
return _(
'the "{0}" function with positional arguments "{1}" and keyword arguments "{2}" must not return a list ("{3}") for the follower option {4}'
).format(
self.callback, self.args, self.kwargs, self.ret, self.display_name
)
return _(
'the "{0}" function must not return a list ("{1}") for the follower option {2}'
).format(self.callback, self.ret, self.display_name)
"problem with a leadership's value length"
pass
class ConstError(TypeError):
@ -309,7 +172,7 @@ class _CommonError:
self.val = val
self.display_type = display_type
self.opt = weakref.ref(opt)
self.name = opt.impl_get_display_name(subconfig, with_quote=True)
self.name = opt.impl_get_display_name(subconfig)
self.err_msg = err_msg
self.index = index
super().__init__(self.err_msg)
@ -318,9 +181,7 @@ class _CommonError:
try:
msg = self.prefix
except AttributeError:
self.prefix = self.tmpl.format(
self.val, _(self.display_type), self.name, self.index
)
self.prefix = self.tmpl.format(self.val, _(self.display_type), self.name)
msg = self.prefix
if self.err_msg:
if msg:
@ -335,20 +196,13 @@ class _CommonError:
class ValueWarning(_CommonError, UserWarning):
tmpl = None
def __init__(self, **kwargs):
def __init__(self, *args, **kwargs):
if ValueWarning.tmpl is None:
if kwargs.get("index") is None:
ValueWarning.tmpl = _(
'attention, "{0}" could be an invalid {1} for {2}'
)
else:
ValueWarning.tmpl = _(
'attention, "{0}" could be an invalid {1} for {2} at index "{3}"'
)
if list(kwargs) == ["msg"]:
self.msg = kwargs["msg"]
ValueWarning.tmpl = _('attention, "{0}" could be an invalid {1} for "{2}"')
if len(args) == 1 and not kwargs:
self.msg = args[0]
else:
super().__init__(**kwargs)
super().__init__(*args, **kwargs)
self.msg = None
def __str__(self):
@ -360,13 +214,10 @@ class ValueWarning(_CommonError, UserWarning):
class ValueOptionError(_CommonError, ValueError):
tmpl = None
def __init__(self, **kwargs):
def __init__(self, *args, **kwargs):
if ValueOptionError.tmpl is None:
if kwargs.get("index") is None:
self.tmpl = _('"{0}" is an invalid {1} for {2}')
else:
self.tmpl = _('"{0}" is an invalid {1} for {2} at index "{3}"')
super().__init__(**kwargs)
ValueOptionError.tmpl = _('"{0}" is an invalid {1} for "{2}"')
super().__init__(*args, **kwargs)
class ValueErrorWarning(ValueWarning):
@ -374,39 +225,5 @@ class ValueErrorWarning(ValueWarning):
def __init__(self, *args, **kwargs):
if ValueErrorWarning.tmpl is None:
ValueErrorWarning.tmpl = _('"{0}" is an invalid {1} for {2}')
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
def __ne__(self, value):
return value is None or value == ""
def __eq__(self, value):
return value is None or value == ""
def __bool__(self):
return False
class Errors:
@staticmethod
def raise_carry_out_calculation_error(
subconfig, message, original_error, option=None, extra_keys=[]
):
if option is None:
option = subconfig.option
display_name = option.impl_get_display_name(subconfig, with_quote=True)
if original_error:
raise ConfigError(
message.format(display_name, original_error, *extra_keys)
) from original_error
raise ConfigError(message.format(display_name, extra_keys))
errors = Errors()

View file

@ -88,8 +88,6 @@ class Base:
assert isinstance(properties, frozenset), _(
"invalid properties type {0} for {1}," " must be a frozenset"
).format(type(properties), name)
if not self.impl_is_optiondescription() and "novalidator" not in properties:
properties = properties | {"validator"}
_setattr = object.__setattr__
_setattr(self, "_name", name)
_setattr(self, "_informations", {"doc": doc})

View file

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2017-2025 Team tiramisu (see AUTHORS for all contributors)
# Copyright (C) 2017-2024 Team tiramisu (see AUTHORS for all contributors)
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by the
@ -21,7 +21,6 @@
"""DomainnameOption
"""
import re
import socket
from ipaddress import ip_interface
from typing import Any, Optional, List
@ -54,18 +53,12 @@ class DomainnameOption(StrOption):
type: str = "domainname",
allow_without_dot: bool = False,
allow_startswith_dot: bool = False,
test_existence: bool = False,
_extra: dict = None,
**kwargs,
) -> None:
# pylint: disable=too-many-branches,too-many-locals,too-many-arguments
if _extra is None:
extra = {}
else:
extra = _extra
if type not in ["netbios", "hostname", "domainname"]:
raise ValueError(_("unknown type {0} for hostname").format(type))
extra["type"] = type
extra = {"_dom_type": type}
if not isinstance(allow_ip, bool):
raise ValueError(_("allow_ip must be a boolean"))
if not isinstance(allow_cidr_network, bool):
@ -74,8 +67,7 @@ class DomainnameOption(StrOption):
raise ValueError(_("allow_without_dot must be a boolean"))
if not isinstance(allow_startswith_dot, bool):
raise ValueError(_("allow_startswith_dot must be a boolean"))
extra["allow_without_dot"] = allow_without_dot
extra["test_existence"] = test_existence
extra["_allow_without_dot"] = allow_without_dot
if type == "domainname":
if allow_without_dot:
min_time = 0
@ -84,20 +76,14 @@ class DomainnameOption(StrOption):
regexp = r"((?!-)[a-z0-9-]{{{1},{0}}}\.){{{1},}}[a-z0-9-]{{1,{0}}}".format(
self._get_len(type), min_time
)
msg = _(
'must start with lowercase characters followed by lowercase characters, number, "-" and "." characters are allowed'
)
msg_warning = _(
'must start with lowercase characters followed by lowercase characters, number, "-" and "." characters are recommanded'
)
else:
regexp = r"((?!-)[a-z0-9-]{{1,{0}}})".format(self._get_len(type))
msg = _(
'must start with lowercase characters followed by lowercase characters, number and "-" characters are allowed'
)
msg_warning = _(
'must start with lowercase characters followed by lowercase characters, number and "-" characters are recommanded'
)
msg = _(
'must start with lowercase characters followed by lowercase characters, number, "-" and "." characters are allowed'
)
msg_warning = _(
'must start with lowercase characters followed by lowercase characters, number, "-" and "." characters are recommanded'
)
if allow_ip:
msg = _("could be a IP, otherwise {}").format(msg)
msg_warning = _("could be a IP, otherwise {}").format(msg_warning)
@ -119,15 +105,15 @@ class DomainnameOption(StrOption):
name,
doc,
)
extra["allow_ip"] = allow_ip
extra["_allow_ip"] = allow_ip
if allow_cidr_network:
extra["_network"] = NetworkOption(
name,
doc,
cidr=True,
)
extra["allow_cidr_network"] = allow_cidr_network
extra["allow_startswith_dot"] = allow_startswith_dot
extra["_allow_cidr_network"] = allow_cidr_network
extra["_allow_startswith_dot"] = allow_startswith_dot
super().__init__(
name,
@ -151,13 +137,13 @@ class DomainnameOption(StrOption):
_("invalid length (max {0})" "").format(part_name_length)
)
part_name_length = self._get_len(self.impl_get_extra("type"))
if self.impl_get_extra("type") == "domainname":
if not self.impl_get_extra("allow_without_dot") and not "." in value:
part_name_length = self._get_len(self.impl_get_extra("_dom_type"))
if self.impl_get_extra("_dom_type") == "domainname":
if not self.impl_get_extra("_allow_without_dot") and not "." in value:
raise ValueError(_("must have dot"))
if len(value) > 255:
raise ValueError(_("invalid length (max 255)"))
if self.impl_get_extra("allow_startswith_dot") and value.startswith("."):
if self.impl_get_extra("_allow_startswith_dot") and value.startswith("."):
val = value[1:]
else:
val = value
@ -169,22 +155,10 @@ class DomainnameOption(StrOption):
_valid_length(dom)
else:
_valid_length(value)
self._validate_domain_resolution(value)
def _validate_domain_resolution(self, value: str) -> None:
if not value.startswith(".") and self.impl_get_extra("test_existence") is True:
try:
socket.gethostbyname(value)
except socket.gaierror as err:
raise ValueError(_("DNS resolution failed").format(value)) from err
except Exception as err:
raise ValueError(
_("error resolving DNS: {1}").format(value, err)
) from err
def _validate_ip_network(self, value: str) -> None:
allow_ip = self.impl_get_extra("allow_ip")
allow_cidr_network = self.impl_get_extra("allow_cidr_network")
allow_ip = self.impl_get_extra("_allow_ip")
allow_cidr_network = self.impl_get_extra("_allow_cidr_network")
if allow_ip is False and allow_cidr_network is False:
raise ValueError(_("must not be an IP"))
if allow_ip is True:
@ -210,7 +184,7 @@ class DomainnameOption(StrOption):
def _second_level_validation_domain(self, value: str, warnings_only: bool) -> None:
if self.impl_get_extra("_has_upper").search(value):
raise ValueError(_("some characters are uppercase"))
if self.impl_get_extra("allow_startswith_dot") and value.startswith("."):
if self.impl_get_extra("_allow_startswith_dot") and value.startswith("."):
val = value[1:]
else:
val = value
@ -226,8 +200,8 @@ class DomainnameOption(StrOption):
def _second_level_validation_ip_network(
self, value: str, warnings_only: bool
) -> None:
allow_ip = self.impl_get_extra("allow_ip")
allow_cidr_network = self.impl_get_extra("allow_cidr_network")
allow_ip = self.impl_get_extra("_allow_ip")
allow_cidr_network = self.impl_get_extra("_allow_cidr_network")
# it's an IP so validate with IPOption
if allow_ip is True and allow_cidr_network is False:
try:

View file

@ -124,6 +124,7 @@ class DynOptionDescription(OptionDescription):
)[0]
if values is None:
values = []
values_ = []
if __debug__:
if not isinstance(values, list):
raise ValueError(
@ -133,7 +134,6 @@ class DynOptionDescription(OptionDescription):
self.impl_get_display_name(subconfig, with_quote=True), values
)
)
values_ = []
for val in values:
cval = self.convert_identifier_to_path(val)
if not isinstance(cval, str) or re.match(NAME_REGEXP, cval) is None:

View file

@ -52,9 +52,9 @@ class FilenameOption(StrOption):
if typ not in ["file", "directory"]:
raise ValueError(f'unknown type "{typ}" for "{name}"')
extra = {
"allow_relative": allow_relative,
"test_existence": test_existence,
"types": types,
"_allow_relative": allow_relative,
"_test_existence": test_existence,
"_types": types,
}
super().__init__(name, *args, extra=extra, **kwargs)
@ -63,10 +63,10 @@ class FilenameOption(StrOption):
value: str,
) -> None:
super().validate(value)
if not self.impl_get_extra("allow_relative") and not value.startswith("/"):
if not self.impl_get_extra("_allow_relative") and not value.startswith("/"):
raise ValueError(_('must starts with "/"'))
if value is not None and self.impl_get_extra("test_existence"):
types = self.impl_get_extra("types")
if value is not None and self.impl_get_extra("_test_existence"):
types = self.impl_get_extra("_types")
file = Path(value)
found = False
if "file" in types and file.is_file():
@ -74,12 +74,8 @@ class FilenameOption(StrOption):
if not found and "directory" in types and file.is_dir():
found = True
if not found:
translated_types = [
{"file": _("file"), "directory": _("directory")}.get(typ)
for typ in types
]
raise ValueError(
_("cannot find this {0}").format(
display_list(translated_types, separator="or"), value
_('cannot find {0} "{1}"').format(
display_list(types, separator="or"), value
)
)

View file

@ -43,7 +43,7 @@ class IntOption(Option):
value: int,
) -> None:
if not isinstance(value, int):
raise ValueError(_("which is not an integer"))
raise ValueError()
def second_level_validation(self, value, warnings_only):
min_number = self.impl_get_extra("min_number")

View file

@ -43,9 +43,9 @@ class IPOption(StrOption):
):
if extra is None:
extra = {}
extra["private_only"] = private_only
extra["allow_reserved"] = allow_reserved
extra["cidr"] = cidr
extra["_private_only"] = private_only
extra["_allow_reserved"] = allow_reserved
extra["_cidr"] = cidr
super().__init__(*args, extra=extra, **kwargs)
def _validate_cidr(self, value):
@ -66,7 +66,7 @@ class IPOption(StrOption):
def validate(self, value: str) -> None:
super().validate(value)
if self.impl_get_extra("cidr"):
if self.impl_get_extra("_cidr"):
if "/" not in value:
raise ValueError(_('CIDR address must have a "/"'))
self._validate_cidr(value)
@ -75,13 +75,13 @@ class IPOption(StrOption):
def second_level_validation(self, value: str, warnings_only: bool) -> None:
ip_obj = ip_interface(value)
if not self.impl_get_extra("allow_reserved") and ip_obj.is_reserved:
if not self.impl_get_extra("_allow_reserved") and ip_obj.is_reserved:
if warnings_only:
msg = _("shouldn't be reserved IP")
else:
msg = _("mustn't be reserved IP")
raise ValueError(msg)
if self.impl_get_extra("private_only") and not ip_obj.is_private:
if self.impl_get_extra("_private_only") and not ip_obj.is_private:
if warnings_only:
msg = _("should be private IP")
else:

View file

@ -51,7 +51,9 @@ class Leadership(OptionDescription):
**kwargs,
) -> None:
if "group_type" in kwargs:
raise LeadershipError(name, "leadership-group_type")
raise LeadershipError(
_('cannot set "group_type" attribute for a Leadership')
)
super().__init__(
name,
doc,
@ -83,7 +85,9 @@ class Leadership(OptionDescription):
if prop not in ALLOWED_LEADER_PROPERTIES and not isinstance(
prop, Calculation
):
raise LeadershipError(name, "leadership-wrong_property", prop=prop)
raise LeadershipError(
_('leader cannot have "{}" property').format(prop)
)
def _check_child_is_valid(
self,
@ -108,7 +112,7 @@ class Leadership(OptionDescription):
if not child.impl_is_multi():
raise ValueError(
_(
"only multi option are allowed in leadership {0} but option "
"only multi option allowed in leadership {0} but option "
"{1} is not a multi"
""
).format(

View file

@ -32,14 +32,14 @@ class NetworkOption(StrOption):
_type = "network address"
def __init__(self, *args, cidr=False, **kwargs):
extra = {"cidr": cidr}
extra = {"_cidr": cidr}
super().__init__(*args, extra=extra, **kwargs)
def validate(self, value: str) -> None:
super().validate(value)
if value.count(".") != 3:
raise ValueError()
cidr = self.impl_get_extra("cidr")
cidr = self.impl_get_extra("_cidr")
if cidr:
if "/" not in value:
raise ValueError(_("must use CIDR notation"))

View file

@ -127,6 +127,11 @@ class Option(BaseOption):
def test_multi_value(value):
if isinstance(value, Calculation):
return
# option_bag = OptionBag(self,
# None,
# undefined,
# properties=None,
# )
try:
self.validate(value)
self.validate_with_option(
@ -178,19 +183,16 @@ class Option(BaseOption):
# undefined,
# properties=None,
# )
self_properties = getattr(self, "_properties", {})
self.impl_validate(
None,
default,
loaded=True,
self_properties=self_properties,
)
self.impl_validate(
None,
default,
check_error=False,
loaded=True,
self_properties=self_properties,
)
self.value_dependencies(default)
if (is_multi and default != []) or (not is_multi and default is not None):
@ -259,22 +261,16 @@ class Option(BaseOption):
*,
check_error: bool = True,
loaded: bool = False,
self_properties: frozenset = frozenset(),
) -> bool:
"""Return True if value is really valid
If not validate or invalid return it returns False
"""
if check_error:
if subconfig:
config_properties = subconfig.config_bag.properties
self_properties = subconfig.properties
else:
config_properties = {"validator"}
if (
"validator" not in config_properties
or "validator" not in self_properties
):
return False
if (
check_error
and subconfig
and not "validator" in subconfig.config_bag.properties
):
return False
if subconfig:
force_index = subconfig.index
else:
@ -333,12 +329,12 @@ class Option(BaseOption):
except ValueWarning as warn:
warnings.warn_explicit(
ValueWarning(
subconfig=subconfig,
val=val,
display_type=_(self.get_type()),
opt=self,
err_msg=str(warn),
index=_index,
subconfig,
val,
_(self.get_type()),
self,
str(warn),
_index,
),
ValueWarning,
self.__class__.__name__,
@ -374,12 +370,12 @@ class Option(BaseOption):
if is_warnings_only:
warnings.warn_explicit(
ValueWarning(
subconfig=subconfig,
val=_value,
display_type=_(self.get_type()),
opt=self,
err_msg=str(err),
index=_index,
subconfig,
_value,
_(self.get_type()),
self,
str(err),
_index,
),
ValueWarning,
self.__class__.__name__,
@ -446,21 +442,11 @@ class Option(BaseOption):
or "demoting_error_warning" not in subconfig.config_bag.properties
):
raise ValueOptionError(
subconfig=subconfig,
val=val,
display_type=_(self.get_type()),
opt=self,
err_msg=str(err),
index=err_index,
subconfig, val, _(self.get_type()), self, str(err), err_index
) from err
warnings.warn_explicit(
ValueErrorWarning(
subconfig=subconfig,
val=val,
display_type=_(self.get_type()),
opt=self,
err_msg=str(err),
index=err_index,
subconfig, val, _(self.get_type()), self, str(err), err_index
),
ValueErrorWarning,
self.__class__.__name__,

View file

@ -29,7 +29,7 @@ from ..setting import ConfigBag, groups, undefined, owners, Undefined
from .baseoption import BaseOption
# from .syndynoption import SubDynOptionDescription, SynDynOptionDescription
from ..error import ConfigError, ConflictError, AttributeOptionError
from ..error import ConfigError, ConflictError
class CacheOptionDescription(BaseOption):
@ -232,20 +232,19 @@ class OptionDescriptionWalk(CacheOptionDescription):
def get_child_not_dynamic(
self,
name: str,
allow_dynoption: bool,
parent: "SubConfig",
name,
allow_dynoption,
):
if name in self._children[0]: # pylint: disable=no-member
option = self._children[1][
self._children[0].index(name)
] # pylint: disable=no-member
if option.impl_is_dynoptiondescription() and not allow_dynoption:
if parent.path:
path = parent.path + "." + name
else:
path = name
raise AttributeOptionError(path, "option-dynamic")
raise AttributeError(
_(
'unknown option "{0}" in root optiondescription (it\'s a dynamic option)'
).format(name)
)
return option
def get_child(
@ -262,7 +261,6 @@ class OptionDescriptionWalk(CacheOptionDescription):
option = self.get_child_not_dynamic(
name,
allow_dynoption,
parent,
)
if option:
return option
@ -276,11 +274,15 @@ class OptionDescriptionWalk(CacheOptionDescription):
if not with_identifier:
return child
return identifier, child
if parent.path is None:
path = name
else:
path = parent.path + "." + name
raise AttributeOptionError(path, "option-not-found")
if self.impl_get_group_type() == groups.root: # pylint: disable=no-member
raise AttributeError(
_('unknown option "{0}" in root optiondescription').format(name)
)
raise AttributeError(
_('unknown option "{0}" in optiondescription {1}').format(
name, self.impl_get_display_name(parent, with_quote=True)
)
)
def get_children(self) -> List[BaseOption]:
"""get children"""

View file

@ -50,21 +50,15 @@ class PortOption(StrOption):
allow_registred: bool = True,
allow_protocol: bool = False,
allow_private: bool = False,
_extra: dict = None,
**kwargs,
) -> None:
if _extra is None:
extra = {}
else:
extra = _extra
extra["allow_range"] = allow_range
extra["allow_protocol"] = allow_protocol
extra["allow_zero"] = allow_zero
extra["allow_wellknown"] = allow_wellknown
extra["allow_registred"] = allow_registred
extra["allow_private"] = allow_private
extra["_min_value"] = None
extra["_max_value"] = None
extra = {
"_allow_range": allow_range,
"_allow_protocol": allow_protocol,
"_min_value": None,
"_max_value": None,
}
ports_min = [0, 1, 1024, 49152]
ports_max = [0, 1023, 49151, 65535]
is_finally = False
@ -88,11 +82,11 @@ class PortOption(StrOption):
def validate(self, value: str) -> None:
super().validate(value)
if self.impl_get_extra("allow_protocol") and (
if self.impl_get_extra("_allow_protocol") and (
value.startswith("tcp:") or value.startswith("udp:")
):
value = [value[4:]]
elif self.impl_get_extra("allow_range") and ":" in str(value):
elif self.impl_get_extra("_allow_range") and ":" in str(value):
value = value.split(":")
if len(value) != 2:
raise ValueError(_("range must have two values only"))
@ -108,7 +102,7 @@ class PortOption(StrOption):
raise ValueError()
def second_level_validation(self, value: str, warnings_only: bool) -> None:
if self.impl_get_extra("allow_protocol") and (
if self.impl_get_extra("_allow_protocol") and (
value.startswith("tcp:") or value.startswith("udp:")
):
value = [value[4:]]

View file

@ -38,7 +38,7 @@ class StrOption(Option):
) -> None:
"""validation"""
if not isinstance(value, str):
raise ValueError(_("which is not a string"))
raise ValueError()
class RegexpOption(StrOption):

View file

@ -54,25 +54,24 @@ class URLOption(StrOption):
**kwargs,
) -> None:
# pylint: disable=too-many-arguments,too-many-locals,redefined-builtin
extra = {}
extra["_domainname"] = DomainnameOption(
name,
doc,
allow_ip=allow_ip,
type=type,
allow_without_dot=allow_without_dot,
_extra=extra,
)
extra["_port"] = PortOption(
name,
doc,
allow_range=allow_range,
allow_zero=allow_zero,
allow_wellknown=allow_wellknown,
allow_registred=allow_registred,
allow_private=allow_private,
_extra=extra,
)
extra = {
"_domainname": DomainnameOption(
name,
doc,
allow_ip=allow_ip,
type=type,
allow_without_dot=allow_without_dot,
),
"_port": PortOption(
name,
doc,
allow_range=allow_range,
allow_zero=allow_zero,
allow_wellknown=allow_wellknown,
allow_registred=allow_registred,
allow_private=allow_private,
),
}
super().__init__(
name,
doc,
@ -111,18 +110,10 @@ class URLOption(StrOption):
domain, port, files = self._get_domain_port_files(value)
# validate port
portoption = self.impl_get_extra("_port")
try:
portoption.validate(port)
except ValueError as err:
msg = _('the port "{0}" is invalid: {1}').format(domain, err)
raise ValueError(msg) from err
portoption.validate(port)
# validate domainname
domainnameoption = self.impl_get_extra("_domainname")
try:
domainnameoption.validate(domain)
except ValueError as err:
msg = _('the domain "{0}" is invalid: {1}').format(domain, err)
raise ValueError(msg) from err
domainnameoption.validate(domain)
# validate files
if files is not None and files != "" and not self.path_re.search(files):
raise ValueError(_("must ends with a valid resource name"))

View file

@ -94,7 +94,7 @@ EXPIRATION_TIME = 5
# demoting_error_warning
# all value errors are convert to warning (ValueErrorWarning)
DEFAULT_PROPERTIES = frozenset(["cache", "validator", "warnings"])
SPECIAL_PROPERTIES = {"frozen", "mandatory", "empty", "force_store_value", "validator"}
SPECIAL_PROPERTIES = {"frozen", "mandatory", "empty", "force_store_value"}
# Config can be in two defaut mode:
#
@ -149,7 +149,6 @@ FORBIDDEN_SET_PERMISSIVES = frozenset(
"force_default_on_freeze",
"force_metaconfig_on_freeze",
"force_store_value",
"validator",
]
)
ALLOWED_LEADER_PROPERTIES = {
@ -159,8 +158,6 @@ ALLOWED_LEADER_PROPERTIES = {
"unique",
"force_store_value",
"mandatory",
"validator",
"novalidator",
"force_default_on_freeze",
"force_metaconfig_on_freeze",
"frozen",
@ -476,7 +473,7 @@ class Settings:
and new_prop not in ALLOWED_LEADER_PROPERTIES
):
raise LeadershipError(
subconfig, "leadership-wrong_property", prop=new_prop
_('leader cannot have "{new_prop}" property')
)
props.add(new_prop)
props -= self.getpermissives(subconfig)
@ -564,15 +561,19 @@ class Settings:
not_allowed_properties = properties - ALLOWED_LEADER_PROPERTIES
if not_allowed_properties:
raise LeadershipError(
subconfig,
"leadership-wrong_property",
prop=display_list(not_allowed_properties),
_('leader cannot have "{0}" property').format(
display_list(not_allowed_properties)
)
)
if (
"force_default_on_freeze" in properties
or "force_metaconfig_on_freeze" in properties
) and "frozen" not in properties:
raise LeadershipError(subconfig, "leadership-force_default_on_freeze")
raise LeadershipError(
_(
'a leader ({0}) cannot have "force_default_on_freeze" or "force_metaconfig_on_freeze" property without "frozen"'
).format(opt.impl_get_display_name())
)
self._properties.setdefault(subconfig.path, {})[subconfig.index] = properties
# values too because of follower values could have a PropertiesOptionError has value
subconfig.config_bag.context.reset_cache(subconfig)

View file

@ -646,9 +646,9 @@ class TiramisuDict:
if self.remotable == "all" or childapi.has_dependency():
obj_form["remote"] = True
if childtype == "IPOption" and (
child.impl_get_extra("private_only")
or not child.impl_get_extra("allow_reserved")
or child.impl_get_extra("cidr")
child.impl_get_extra("_private_only")
or not child.impl_get_extra("_allow_reserved")
or child.impl_get_extra("_cidr")
):
obj_form["remote"] = True
if childtype == "DateOption":

View file

@ -265,10 +265,9 @@ class Values:
) -> None:
"""set value to option"""
owner = self.get_context_owner()
self_properties = subconfig.properties
setting_properties = subconfig.config_bag.properties
ori_value = value
if "validator" in setting_properties and "validator" in self_properties:
if "validator" in setting_properties:
value, has_calculation = self.setvalue_validation(
subconfig,
value,
@ -296,7 +295,6 @@ class Values:
)
validator = (
"validator" in setting_properties
and "validator" in self_properties
and "demoting_error_warning" not in setting_properties
)
if validator and not has_calculation:
@ -306,11 +304,7 @@ class Values:
value,
validated=validator,
)
elif (
"validator" in setting_properties
and "validator" in self_properties
and has_calculation
):
elif "validator" in setting_properties and has_calculation:
cache = subconfig.config_bag.context.get_values_cache()
cache.delcache(subconfig.path)
@ -593,39 +587,35 @@ class Values:
"""reset value for an option"""
config_bag = subconfig.config_bag
hasvalue = self.hasvalue(subconfig.path)
self_properties = subconfig.properties
context = config_bag.context
setting_properties = config_bag.properties
if (
validate
and hasvalue
and "validator" in setting_properties
and "validator" in self_properties
):
fake_context = context.gen_fake_context()
fake_config_bag = config_bag.copy()
fake_config_bag.remove_validation()
fake_config_bag.context = fake_context
fake_subconfig = fake_context.get_sub_config(
fake_config_bag,
subconfig.path,
subconfig.index,
validate_properties=False,
)
fake_values = fake_context.get_values()
fake_values.reset(fake_subconfig)
fake_subconfig.config_bag.properties = setting_properties
value = fake_values.get_default_value(fake_subconfig)
fake_values.setvalue_validation(
fake_subconfig,
value,
)
if validate:
if hasvalue and "validator" in setting_properties:
fake_context = context.gen_fake_context()
fake_config_bag = config_bag.copy()
fake_config_bag.remove_validation()
fake_config_bag.context = fake_context
fake_subconfig = fake_context.get_sub_config(
fake_config_bag,
subconfig.path,
subconfig.index,
validate_properties=False,
)
fake_values = fake_context.get_values()
fake_values.reset(fake_subconfig)
fake_subconfig.config_bag.properties = setting_properties
value = fake_values.get_default_value(fake_subconfig)
fake_values.setvalue_validation(
fake_subconfig,
value,
)
# if hasvalue:
opt = subconfig.option
if opt.impl_is_leader():
opt.impl_get_leadership().reset(subconfig.parent)
if (
"force_store_value" in setting_properties
and "force_store_value" in self_properties
and "force_store_value" in subconfig.properties
):
value = self.get_default_value(subconfig)
@ -672,11 +662,10 @@ class Values:
index=subconfig.index,
):
return
self_properties = subconfig.properties
config_bag = subconfig.config_bag
context = config_bag.context
setting_properties = config_bag.properties
if "validator" in setting_properties and "validator" in self_properties:
if "validator" in setting_properties:
fake_context = context.gen_fake_context()
fake_config_bag = config_bag.copy()
fake_config_bag.remove_validation()
@ -697,7 +686,7 @@ class Values:
)
if (
"force_store_value" in setting_properties
and "force_store_value" in self_properties
and "force_store_value" in subconfig.properties
):
value = self.get_default_value(
subconfig,