fix: translation + black
This commit is contained in:
parent
b5d477a439
commit
5e66d2074d
50 changed files with 8121 additions and 6694 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,6 +1,5 @@
|
|||
*~
|
||||
*#
|
||||
*.pyc
|
||||
*.mo
|
||||
*.swp
|
||||
build/
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
# Include the README
|
||||
include *.rst
|
||||
|
||||
# Include the license file
|
||||
include LICENSE.txt
|
||||
|
||||
# Include the data files
|
||||
recursive-include tiramisu *.py *.mo
|
18
README.md
18
README.md
|
@ -1,13 +1,25 @@
|
|||
![Logo Tiramisu](logo.png "logo Tiramisu")
|
||||
|
||||
An options controller tool
|
||||
-------------------------------------
|
||||
|
||||
Due to more and more available options required to set up an operating system,
|
||||
compiler options or whatever, it became quite annoying to hand the necessary
|
||||
options to where they are actually used and even more annoying to add new
|
||||
options. To circumvent these problems the configuration control was
|
||||
introduced...
|
||||
|
||||
Tiramisu is an options handler and an options controller, wich aims at
|
||||
producing flexible and fast options access.
|
||||
|
||||
|
||||
[Documentations](doc/README.md)
|
||||
|
||||
|
||||
# LICENSES
|
||||
|
||||
See COPYING for the licences of the code and the documentation.
|
||||
See [COPYING](COPYING) for the licences of the code and the documentation.
|
||||
|
||||
See AUTHORS for the details about the tiramisu's team.
|
||||
See [AUTHORS](AUTHORS) for the details about the tiramisu's team.
|
||||
|
||||
|
||||
|
||||
|
|
1367
locale/fr/LC_MESSAGES/tiramisu.po
Normal file
1367
locale/fr/LC_MESSAGES/tiramisu.po
Normal file
File diff suppressed because it is too large
Load diff
811
locale/tiramisu.pot
Normal file
811
locale/tiramisu.pot
Normal file
|
@ -0,0 +1,811 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR ORGANIZATION
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"POT-Creation-Date: 2024-10-30 13:15+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"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
|
||||
#: tiramisu/api.py:79
|
||||
msgid "Settings:"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:83
|
||||
msgid "Access to option without verifying permissive properties"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:88
|
||||
msgid "Access to option without property restriction"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:93
|
||||
msgid "Do not warnings during validation"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:97
|
||||
msgid "Commands:"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:111 tiramisu/api.py:1840
|
||||
msgid "please specify a valid sub function ({0}.{1})"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:194
|
||||
msgid "please do not specify index ({0}.{1})"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:199 tiramisu/api.py:844
|
||||
msgid "please specify index with a follower option ({0}.{1})"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:220
|
||||
msgid "please specify a valid sub function ({0}.{1}): {2}"
|
||||
msgstr ""
|
||||
|
||||
#: 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:517
|
||||
msgid "cannot get option from a follower symlink without index"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:592
|
||||
msgid "cannot add this property: \"{0}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:619
|
||||
msgid "cannot remove option's property \"{0}\", use permissive instead in option \"{1}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:623
|
||||
msgid "cannot find \"{0}\" in option \"{1}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:628
|
||||
msgid "cannot remove option's property \"{0}\", use permissive instead in option \"{1}\" at index \"{2}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:632
|
||||
msgid "cannot find \"{0}\" in option \"{1}\" at index \"{2}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:676
|
||||
msgid "cannot find \"{0}\""
|
||||
msgstr ""
|
||||
|
||||
#: 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:1020
|
||||
msgid "please specify a valid sub function ({0}.{1}) for {2}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:1407
|
||||
msgid "properties must be a frozenset"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:1411 tiramisu/api.py:1438
|
||||
msgid "unknown when {} (must be in append or remove)"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:1424 tiramisu/api.py:1448 tiramisu/config.py:1680
|
||||
msgid "unknown type {}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:1812
|
||||
msgid "do not use unrestraint, nowarnings or forcepermissive together"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/autolib.py:80
|
||||
msgid "args in params must be a tuple"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/autolib.py:83 tiramisu/autolib.py:88
|
||||
msgid "arg in params must be a Param"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/autolib.py:85
|
||||
msgid "kwargs in params must be a dict"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/autolib.py:113
|
||||
msgid "paramoption needs an option not {}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/autolib.py:119
|
||||
msgid "param must have a boolean not a {} for notraisepropertyerror"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/autolib.py:122
|
||||
msgid "param must have a boolean not a {} for raisepropertyerror"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/autolib.py:212
|
||||
msgid "option in ParamInformation cannot be a symlinkoption"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/autolib.py:215
|
||||
msgid "option in ParamInformation cannot be a follower"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/autolib.py:218
|
||||
msgid "option in ParamInformation cannot be a dynamic option"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/autolib.py:279
|
||||
msgid "first argument ({0}) must be a function"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/autolib.py:283
|
||||
msgid "help_function ({0}) must be a function"
|
||||
msgstr ""
|
||||
|
||||
#: 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:477 tiramisu/autolib.py:535 tiramisu/autolib.py:584
|
||||
msgid "unable to get value for calculating {0}, {1}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/autolib.py:601
|
||||
msgid "option {0} is not a dynoptiondescription or in a dynoptiondescription"
|
||||
msgstr ""
|
||||
|
||||
#: 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:863
|
||||
msgid "the \"{}\" function must not return a list (\"{}\") for the follower option {}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/autolib.py:904
|
||||
msgid "unexpected error \"{0}\" in function \"{1}\" with arguments \"{3}\" and \"{4}\" for option {2}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/autolib.py:915
|
||||
msgid "unexpected error \"{0}\" in function \"{1}\" for option {2}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/config.py:419
|
||||
msgid "index \"{0}\" is greater than the leadership length \"{1}\" for option {2}"
|
||||
msgstr ""
|
||||
|
||||
#: 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/config.py:982 tiramisu/option/optiondescription.py:74
|
||||
msgid "option description seems to be part of an other config"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/config.py:1144
|
||||
msgid "parent of {0} not already exists"
|
||||
msgstr ""
|
||||
|
||||
#: 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:201
|
||||
msgid "attention, \"{0}\" could be an invalid {1} for \"{2}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/error.py:219 tiramisu/error.py:228
|
||||
msgid "\"{0}\" is an invalid {1} for \"{2}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/function.py:65
|
||||
msgid "network \"{0}\" ({1}) does not match with this netmask"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/function.py:83
|
||||
msgid "IP \"{0}\" ({1}) with this netmask is in fact a network address"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/function.py:88
|
||||
msgid "IP \"{0}\" ({1}) with this netmask is in fact a broadcast address"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/function.py:106
|
||||
msgid "broadcast invalid with network {0} ({1}) and netmask {2} ({3})"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/function.py:134
|
||||
msgid "this IP is not in network {network[\"value\"]} ({network[\"name\"]})"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/function.py:136
|
||||
msgid "this IP is not in network {network[\"value\"]} ({network[\"name\"]}) with netmask {netmask[\"value\"]} ({netmask[\"name\"]})"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/function.py:143
|
||||
msgid "this IP with the network {0} ({1}) is in fact a network address"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/function.py:148
|
||||
msgid "this IP with the network {0} ({1}) is in fact a broadcast address"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/function.py:165
|
||||
msgid "value is identical to {0}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/function.py:400
|
||||
msgid "unexpected value in calc_value with join attribute \"{0}\" with invalid length \"{1}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/function.py:527
|
||||
msgid "unexpected {0} condition_operator in calc_value"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/function.py:591
|
||||
msgid "unexpected condition_{0} must have \"todict\" argument"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/function.py:602
|
||||
msgid "the value of \"{0}\" is {1}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/function.py:604
|
||||
msgid "the value of \"{0}\" is not {1}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/baseoption.py:75 tiramisu/option/symlinkoption.py:44
|
||||
msgid "\"{0}\" is an invalid name for an option"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/baseoption.py:88
|
||||
msgid "invalid properties type {0} for {1}, must be a frozenset"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/baseoption.py:98
|
||||
msgid "invalid property type {0} for {1}, must be a string or a Calculation"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/baseoption.py:249
|
||||
msgid "information's item for {0} not found: \"{1}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/baseoption.py:267
|
||||
msgid "'{0}' ({1}) object attribute '{2}' is read-only"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/baseoption.py:308
|
||||
msgid "\"{}\" ({}) object attribute \"{}\" is read-only"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/baseoption.py:320
|
||||
msgid "{0} not part of any Config"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/broadcastoption.py:41
|
||||
msgid "invalid string"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/choiceoption.py:47
|
||||
msgid "values must be a tuple or a calculation for {0}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/choiceoption.py:70
|
||||
msgid "the calculated values \"{0}\" for \"{1}\" is not a list"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/choiceoption.py:101
|
||||
msgid "only \"{0}\" is allowed"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/choiceoption.py:103
|
||||
msgid "only {0} are allowed"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/domainnameoption.py:60
|
||||
msgid "unknown type {0} for hostname"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/domainnameoption.py:63
|
||||
msgid "allow_ip must be a boolean"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/domainnameoption.py:65
|
||||
msgid "allow_cidr_network must be a boolean"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/domainnameoption.py:67
|
||||
msgid "allow_without_dot must be a boolean"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/domainnameoption.py:69
|
||||
msgid "allow_startswith_dot must be a boolean"
|
||||
msgstr ""
|
||||
|
||||
#: 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:84
|
||||
msgid "must start with lowercase characters followed by lowercase characters, number, \"-\" and \".\" characters are recommanded"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/domainnameoption.py:88
|
||||
#: tiramisu/option/domainnameoption.py:89
|
||||
msgid "could be a IP, otherwise {}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/domainnameoption.py:134
|
||||
msgid "invalid length (min 1)"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/domainnameoption.py:137
|
||||
msgid "invalid length (max {0})"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/domainnameoption.py:143
|
||||
msgid "must have dot"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/domainnameoption.py:145
|
||||
msgid "invalid length (max 255)"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/domainnameoption.py:163
|
||||
msgid "must not be an IP"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/domainnameoption.py:186
|
||||
msgid "some characters are uppercase"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/dynoptiondescription.py:131
|
||||
msgid "DynOptionDescription identifiers for option {0}, is not a list ({1})"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/dynoptiondescription.py:142
|
||||
msgid "invalid identifier \"{}\" for option {}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/dynoptiondescription.py:150
|
||||
msgid "DynOptionDescription \"{0}\" identifiers return a list with same values \"{1}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/filenameoption.py:47
|
||||
msgid "types parameter must be a list, not \"{0}\" for \"{1}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/filenameoption.py:67
|
||||
msgid "must starts with \"/\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/filenameoption.py:78
|
||||
msgid "cannot find {0} \"{1}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/intoption.py:52
|
||||
msgid "value should be equal or greater than \"{0}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/intoption.py:54
|
||||
msgid "value must be equal or greater than \"{0}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/intoption.py:59
|
||||
msgid "value should be less than \"{0}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/intoption.py:61
|
||||
msgid "value must be less than \"{0}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/ipoption.py:57
|
||||
msgid "it's in fact a network address"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/ipoption.py:59
|
||||
msgid "it's in fact a broacast address"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/ipoption.py:71
|
||||
msgid "CIDR address must have a \"/\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/ipoption.py:80
|
||||
msgid "shouldn't be reserved IP"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/ipoption.py:82
|
||||
msgid "mustn't be reserved IP"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/ipoption.py:86
|
||||
msgid "should be private IP"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/ipoption.py:88
|
||||
msgid "must be private IP"
|
||||
msgstr ""
|
||||
|
||||
#: 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: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:108
|
||||
msgid "leadership {0} shall not have a subgroup"
|
||||
msgstr ""
|
||||
|
||||
#: 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:141
|
||||
msgid "not allowed default value for follower option {0} in leadership {1}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/networkoption.py:45
|
||||
msgid "must use CIDR notation"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/networkoption.py:60
|
||||
msgid "shouldn't be reserved network"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/networkoption.py:62
|
||||
msgid "mustn't be reserved network"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/option.py:73
|
||||
msgid "default_multi is set whereas multi is False in option: {0}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/option.py:93
|
||||
msgid "invalid multi type \"{}\" for \"{}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/option.py:112
|
||||
msgid "validators must be a list of Calculation for \"{0}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/option.py:117
|
||||
msgid "validators must be a Calculation for \"{0}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/option.py:146
|
||||
msgid "invalid default_multi value \"{0}\" for option {1}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/option.py:154
|
||||
msgid "invalid default_multi value \"{0}\" for option {1}, {2}"
|
||||
msgstr ""
|
||||
|
||||
#: 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:290
|
||||
msgid "the value \"{}\" is not unique"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/option.py:352
|
||||
msgid "which must not be a list"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/option.py:404 tiramisu/option/option.py:430
|
||||
msgid "which must be a list"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/option.py:424
|
||||
msgid "which \"{}\" must be a list of list"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/optiondescription.py:109
|
||||
msgid "duplicate option: {0}"
|
||||
msgstr ""
|
||||
|
||||
#: 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:366
|
||||
msgid "duplicate option name: \"{0}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/optiondescription.py:372
|
||||
msgid "the option's name \"{0}\" start as the dynoptiondescription's name \"{1}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/optiondescription.py:415
|
||||
msgid "cannot change group_type if already set (old {0}, new {1})"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/optiondescription.py:420
|
||||
msgid "group_type: {0} not allowed"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/permissionsoption.py:52
|
||||
msgid "only 3 or 4 octal digits are allowed"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/permissionsoption.py:63
|
||||
msgid "user"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/permissionsoption.py:64
|
||||
#: tiramisu/option/permissionsoption.py:66
|
||||
msgid "group"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/permissionsoption.py:67
|
||||
msgid "other"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/permissionsoption.py:68
|
||||
msgid "{0} has more right than {1}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/permissionsoption.py:71
|
||||
msgid "too weak"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/portoption.py:74
|
||||
msgid "inconsistency in allowed range"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/portoption.py:79
|
||||
msgid "max value is empty"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/portoption.py:92
|
||||
msgid "range must have two values only"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/portoption.py:95
|
||||
msgid "first port in range must be smaller than the second one"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/portoption.py:121
|
||||
msgid "should be between {0} and {1}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/portoption.py:123
|
||||
msgid "must be between {0} and {1}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/symlinkoption.py:51
|
||||
msgid "malformed symlink second parameters must be an option for \"{0}\", not {1}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/urloption.py:91
|
||||
msgid "must start with http:// or https://"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/urloption.py:119
|
||||
msgid "must ends with a valid resource name"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/setting.py:255
|
||||
msgid "can't rebind {0}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/setting.py:262
|
||||
msgid "can't unbind {0}"
|
||||
msgstr ""
|
||||
|
||||
#: 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: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:617
|
||||
msgid "cannot add those permissives: {0}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/setting.py:654
|
||||
msgid "can't reset properties to the symlinkoption \"{}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/setting.py:667
|
||||
msgid "can't reset permissives to the symlinkoption \"{}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/todict.py:395
|
||||
msgid "option {} only works when remotable is not \"none\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/todict.py:561
|
||||
msgid "unable to transform tiramisu object to dict: {}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/todict.py:876 tiramisu/todict.py:1033
|
||||
msgid "unknown form {}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/todict.py:923
|
||||
msgid "not in current area"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/todict.py:947
|
||||
msgid "only multi option can have action \"add\", but \"{}\" is not a multi"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/todict.py:953
|
||||
msgid "unknown action {}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/value.py:564 tiramisu/value.py:861
|
||||
msgid "set owner \"{0}\" is forbidden"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/value.py:571
|
||||
msgid "\"{0}\" is a default value, so we cannot change owner to \"{1}\""
|
||||
msgstr ""
|
||||
|
||||
#: 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:847
|
||||
msgid "information's item not found \"{}\""
|
||||
msgstr ""
|
||||
|
35
pyproject.toml
Normal file
35
pyproject.toml
Normal file
|
@ -0,0 +1,35 @@
|
|||
[build-system]
|
||||
build-backend = "flit_core.buildapi"
|
||||
requires = ["flit_core >=3.8.0,<4"]
|
||||
|
||||
[project]
|
||||
name = "tiramisu"
|
||||
version = "4.1.0"
|
||||
authors = [{name = "Emmanuel Garette", email = "gnunux@gnunux.info"}]
|
||||
readme = "README.md"
|
||||
description = "an options controller tool"
|
||||
requires-python = ">=3.8"
|
||||
classifiers = [
|
||||
"License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)",
|
||||
"Programming Language :: Python",
|
||||
"Programming Language :: Python :: 3.8",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Operating System :: OS Independent",
|
||||
"Natural Language :: English",
|
||||
"Natural Language :: French",
|
||||
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
Home = "https://forge.cloud.silique.fr/stove/tiramisu"
|
||||
|
||||
[tool.commitizen]
|
||||
name = "cz_conventional_commits"
|
||||
tag_format = "$version"
|
||||
version_scheme = "pep440"
|
||||
version_provider = "pep621"
|
||||
update_changelog_on_bump = true
|
52
setup.py
52
setup.py
|
@ -1,52 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from setuptools import setup
|
||||
import os
|
||||
from tiramisu import __version__
|
||||
|
||||
|
||||
ORI_PACKAGE_NAME = 'tiramisu'
|
||||
PACKAGE_NAME = os.environ.get('PACKAGE_DST', ORI_PACKAGE_NAME)
|
||||
|
||||
if PACKAGE_NAME != ORI_PACKAGE_NAME:
|
||||
package_dir = {PACKAGE_NAME: ORI_PACKAGE_NAME}
|
||||
else:
|
||||
package_dir = None
|
||||
|
||||
setup(
|
||||
version=__version__,
|
||||
author="Tiramisu's team",
|
||||
author_email='gnunux@gnunux.info',
|
||||
name=PACKAGE_NAME,
|
||||
description='an options controller tool',
|
||||
url='https://forge.cloud.silique.fr/stove/tiramisu/',
|
||||
license='GNU Library or Lesser General Public License (LGPL)',
|
||||
provides=['tiramisu_api'],
|
||||
install_requires=['setuptools'],
|
||||
classifiers=[
|
||||
"Programming Language :: Python :: 3",
|
||||
"License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)",
|
||||
"Operating System :: OS Independent",
|
||||
"Natural Language :: English",
|
||||
"Natural Language :: French",
|
||||
],
|
||||
long_description="""\
|
||||
An options controller tool
|
||||
-------------------------------------
|
||||
|
||||
Due to more and more available options required to set up an operating system,
|
||||
compiler options or whatever, it became quite annoying to hand the necessary
|
||||
options to where they are actually used and even more annoying to add new
|
||||
options. To circumvent these problems the configuration control was
|
||||
introduced...
|
||||
|
||||
Tiramisu is an options handler and an options controller, wich aims at
|
||||
producing flexible and fast options access.
|
||||
|
||||
|
||||
This version requires Python 3.5 or later.
|
||||
""",
|
||||
include_package_data=True,
|
||||
package_dir=package_dir,
|
||||
packages=[PACKAGE_NAME],
|
||||
)
|
|
@ -86,8 +86,6 @@ def build_variables(*,
|
|||
if hidden:
|
||||
base_name += 'hidden_'
|
||||
#str_mandatory_multi_hidden_information_deps
|
||||
if base_name + 'information_deps' == 'str_mandatory_multi_hidden_information_deps':
|
||||
print('blah', multi, properties, str1_5_informations)
|
||||
str1 = StrOption(base_name + 'information_deps',
|
||||
'',
|
||||
multi=multi,
|
||||
|
@ -465,7 +463,6 @@ def _test_option(option, without_index=False):
|
|||
assert isinstance(option.path(), str) and (option.path() == name or option.path().endswith(f'.{name}'))
|
||||
if '_deps' in name:
|
||||
assert option.has_dependency(False)
|
||||
print(option.path())
|
||||
assert option.dependencies()
|
||||
else:
|
||||
assert not option.has_dependency(False)
|
||||
|
|
|
@ -1046,12 +1046,12 @@ def test_validator_error_prefix():
|
|||
try:
|
||||
cfg.option('b').value.set(1)
|
||||
except Exception as err:
|
||||
assert str(err) == _('"{0}" is an invalid {1} for "{2}"').format('1', _('integer'), 'b') + ', ' + _('value is identical to {}').format('"a"')
|
||||
assert str(err) == _('"{0}" is an invalid {1} for "{2}"').format('1', _('integer'), 'b') + ', ' + _('value is identical to {0}').format('"a"')
|
||||
try:
|
||||
cfg.option('b').value.set(1)
|
||||
except Exception as err:
|
||||
err.prefix = ''
|
||||
assert str(err) == _('value is identical to {}').format('"a"')
|
||||
assert str(err) == _('value is identical to {0}').format('"a"')
|
||||
# assert not list_sessions()
|
||||
|
||||
|
||||
|
|
|
@ -14,11 +14,29 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""Configuration management library written in python
|
||||
"""
|
||||
from .function import calc_value, calc_value_property_help, valid_ip_netmask, \
|
||||
valid_network_netmask, valid_in_network, valid_broadcast, \
|
||||
valid_not_equal, function_waiting_for_dict, function_waiting_for_error
|
||||
from .autolib import Calculation, Params, ParamOption, ParamDynOption, ParamSelfOption, \
|
||||
ParamValue, ParamIndex, ParamIdentifier, ParamInformation, ParamSelfInformation
|
||||
from .function import (
|
||||
calc_value,
|
||||
calc_value_property_help,
|
||||
valid_ip_netmask,
|
||||
valid_network_netmask,
|
||||
valid_in_network,
|
||||
valid_broadcast,
|
||||
valid_not_equal,
|
||||
function_waiting_for_dict,
|
||||
function_waiting_for_error,
|
||||
)
|
||||
from .autolib import (
|
||||
Calculation,
|
||||
Params,
|
||||
ParamOption,
|
||||
ParamDynOption,
|
||||
ParamSelfOption,
|
||||
ParamValue,
|
||||
ParamIndex,
|
||||
ParamIdentifier,
|
||||
ParamInformation,
|
||||
ParamSelfInformation,
|
||||
)
|
||||
from .option import *
|
||||
from .error import ConfigError
|
||||
from .api import Config, MetaConfig, GroupConfig, MixConfig
|
||||
|
@ -26,35 +44,36 @@ from .option import __all__ as all_options
|
|||
from .setting import owners, groups, undefined
|
||||
|
||||
|
||||
allfuncs = ['Calculation',
|
||||
'Params',
|
||||
'ParamOption',
|
||||
'ParamDynOption',
|
||||
'ParamSelfOption',
|
||||
'ParamValue',
|
||||
'ParamIndex',
|
||||
'ParamIdentifier',
|
||||
'ParamInformation',
|
||||
'ParamSelfInformation',
|
||||
'MetaConfig',
|
||||
'MixConfig',
|
||||
'GroupConfig',
|
||||
'Config',
|
||||
'ConfigError',
|
||||
'undefined',
|
||||
'owners',
|
||||
'groups',
|
||||
'calc_value',
|
||||
'calc_value_property_help',
|
||||
'valid_ip_netmask',
|
||||
'valid_network_netmask',
|
||||
'valid_in_network',
|
||||
'valid_broadcast',
|
||||
'function_waiting_for_dict',
|
||||
'function_waiting_for_error',
|
||||
]
|
||||
allfuncs = [
|
||||
"Calculation",
|
||||
"Params",
|
||||
"ParamOption",
|
||||
"ParamDynOption",
|
||||
"ParamSelfOption",
|
||||
"ParamValue",
|
||||
"ParamIndex",
|
||||
"ParamIdentifier",
|
||||
"ParamInformation",
|
||||
"ParamSelfInformation",
|
||||
"MetaConfig",
|
||||
"MixConfig",
|
||||
"GroupConfig",
|
||||
"Config",
|
||||
"ConfigError",
|
||||
"undefined",
|
||||
"owners",
|
||||
"groups",
|
||||
"calc_value",
|
||||
"calc_value_property_help",
|
||||
"valid_ip_netmask",
|
||||
"valid_network_netmask",
|
||||
"valid_in_network",
|
||||
"valid_broadcast",
|
||||
"function_waiting_for_dict",
|
||||
"function_waiting_for_error",
|
||||
]
|
||||
allfuncs.extend(all_options)
|
||||
del(all_options)
|
||||
del all_options
|
||||
__all__ = tuple(allfuncs)
|
||||
del(allfuncs)
|
||||
del allfuncs
|
||||
__version__ = "4.1.0"
|
||||
|
|
1124
tiramisu/api.py
1124
tiramisu/api.py
File diff suppressed because it is too large
Load diff
|
@ -26,29 +26,32 @@ from .error import PropertiesOptionError, ConfigError, LeadershipError, ValueWar
|
|||
from .i18n import _
|
||||
from .setting import undefined, ConfigBag
|
||||
from .function import FUNCTION_WAITING_FOR_DICT, FUNCTION_WAITING_FOR_ERROR
|
||||
|
||||
# ____________________________________________________________
|
||||
|
||||
|
||||
def get_calculated_value(subconfig: "SubConfig",
|
||||
def get_calculated_value(
|
||||
subconfig: "SubConfig",
|
||||
value: Any,
|
||||
*,
|
||||
reset_cache: bool=True,
|
||||
validate_properties: bool=True,
|
||||
) -> Any:
|
||||
"""value could be a calculation, in this case do calculation
|
||||
"""
|
||||
reset_cache: bool = True,
|
||||
validate_properties: bool = True,
|
||||
) -> Any:
|
||||
"""value could be a calculation, in this case do calculation"""
|
||||
has_calculation = False
|
||||
if isinstance(value, Calculation):
|
||||
if subconfig is None:
|
||||
return undefined, False
|
||||
value = value.execute(subconfig,
|
||||
value = value.execute(
|
||||
subconfig,
|
||||
validate_properties=validate_properties,
|
||||
)
|
||||
has_calculation = True
|
||||
elif isinstance(value, list):
|
||||
# if value is a list, do subcalculation
|
||||
for idx, val in enumerate(value):
|
||||
value[idx], _has_calculation = get_calculated_value(subconfig,
|
||||
value[idx], _has_calculation = get_calculated_value(
|
||||
subconfig,
|
||||
val,
|
||||
reset_cache=False,
|
||||
validate_properties=validate_properties,
|
||||
|
@ -61,7 +64,8 @@ def get_calculated_value(subconfig: "SubConfig",
|
|||
|
||||
|
||||
class Params:
|
||||
__slots__ = ('args', 'kwargs')
|
||||
__slots__ = ("args", "kwargs")
|
||||
|
||||
def __init__(self, args=None, kwargs=None, **kwgs):
|
||||
if args is None:
|
||||
args = tuple()
|
||||
|
@ -73,15 +77,15 @@ class Params:
|
|||
args = (args,)
|
||||
else:
|
||||
if not isinstance(args, tuple):
|
||||
raise ValueError(_('args in params must be a tuple'))
|
||||
raise ValueError(_("args in params must be a tuple"))
|
||||
for arg in args:
|
||||
if not isinstance(arg, Param):
|
||||
raise ValueError(_('arg in params must be a Param'))
|
||||
raise ValueError(_("arg in params must be a Param"))
|
||||
if not isinstance(kwargs, dict):
|
||||
raise ValueError(_('kwargs in params must be a dict'))
|
||||
raise ValueError(_("kwargs in params must be a dict"))
|
||||
for arg in kwargs.values():
|
||||
if not isinstance(arg, Param):
|
||||
raise ValueError(_('arg in params must be a Param'))
|
||||
raise ValueError(_("arg in params must be a Param"))
|
||||
self.args = args
|
||||
self.kwargs = kwargs
|
||||
|
||||
|
@ -92,55 +96,74 @@ class Param:
|
|||
|
||||
|
||||
class ParamOption(Param):
|
||||
__slots__ = ('option',
|
||||
'notraisepropertyerror',
|
||||
'raisepropertyerror',
|
||||
__slots__ = (
|
||||
"option",
|
||||
"notraisepropertyerror",
|
||||
"raisepropertyerror",
|
||||
)
|
||||
def __init__(self,
|
||||
option: 'Option',
|
||||
notraisepropertyerror: bool=False,
|
||||
raisepropertyerror: bool=False,
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
option: "Option",
|
||||
notraisepropertyerror: bool = False,
|
||||
raisepropertyerror: bool = False,
|
||||
) -> None:
|
||||
if __debug__ and not hasattr(option, 'impl_is_symlinkoption'):
|
||||
raise ValueError(_('paramoption needs an option not {}').format(type(option)))
|
||||
if __debug__ and not hasattr(option, "impl_is_symlinkoption"):
|
||||
raise ValueError(
|
||||
_("paramoption needs an option not {}").format(type(option))
|
||||
)
|
||||
if option.impl_is_symlinkoption():
|
||||
cur_opt = option.impl_getopt()
|
||||
else:
|
||||
cur_opt = option
|
||||
assert isinstance(notraisepropertyerror, bool), _('param must have a boolean not a {} for notraisepropertyerror').format(type(notraisepropertyerror))
|
||||
assert isinstance(raisepropertyerror, bool), _('param must have a boolean not a {} for raisepropertyerror').format(type(raisepropertyerror))
|
||||
assert isinstance(notraisepropertyerror, bool), _(
|
||||
"param must have a boolean not a {} for notraisepropertyerror"
|
||||
).format(type(notraisepropertyerror))
|
||||
assert isinstance(raisepropertyerror, bool), _(
|
||||
"param must have a boolean not a {} for raisepropertyerror"
|
||||
).format(type(raisepropertyerror))
|
||||
self.option = cur_opt
|
||||
self.notraisepropertyerror = notraisepropertyerror
|
||||
self.raisepropertyerror = raisepropertyerror
|
||||
|
||||
|
||||
class ParamDynOption(ParamOption):
|
||||
__slots__ = ('identifiers',
|
||||
'optional',
|
||||
__slots__ = (
|
||||
"identifiers",
|
||||
"optional",
|
||||
)
|
||||
def __init__(self,
|
||||
option: 'Option',
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
option: "Option",
|
||||
identifiers: list[str],
|
||||
notraisepropertyerror: bool=False,
|
||||
raisepropertyerror: bool=False,
|
||||
optional: bool=False,
|
||||
notraisepropertyerror: bool = False,
|
||||
raisepropertyerror: bool = False,
|
||||
optional: bool = False,
|
||||
) -> None:
|
||||
super().__init__(option,
|
||||
super().__init__(
|
||||
option,
|
||||
notraisepropertyerror,
|
||||
raisepropertyerror,
|
||||
)
|
||||
if not isinstance(identifiers, list):
|
||||
raise Exception(f'identifiers in ParamDynOption must be a list, not {identifiers}')
|
||||
raise Exception(
|
||||
f"identifiers in ParamDynOption must be a list, not {identifiers}"
|
||||
)
|
||||
if not isinstance(optional, bool):
|
||||
raise Exception(f'optional in ParamDynOption must be a boolean, not {optional}')
|
||||
raise Exception(
|
||||
f"optional in ParamDynOption must be a boolean, not {optional}"
|
||||
)
|
||||
self.identifiers = identifiers
|
||||
self.optional = optional
|
||||
|
||||
|
||||
class ParamSelfOption(Param):
|
||||
__slots__ = ('whole')
|
||||
def __init__(self,
|
||||
whole: bool=undefined,
|
||||
__slots__ = "whole"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
whole: bool = undefined,
|
||||
) -> None:
|
||||
"""whole: send all value for a multi, not only indexed value"""
|
||||
if whole is not undefined:
|
||||
|
@ -148,21 +171,25 @@ class ParamSelfOption(Param):
|
|||
|
||||
|
||||
class ParamValue(Param):
|
||||
__slots__ = ('value',)
|
||||
__slots__ = ("value",)
|
||||
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
|
||||
|
||||
class ParamInformation(Param):
|
||||
__slots__ = ('information_name',
|
||||
'default_value',
|
||||
'option',
|
||||
'self_option',
|
||||
__slots__ = (
|
||||
"information_name",
|
||||
"default_value",
|
||||
"option",
|
||||
"self_option",
|
||||
)
|
||||
def __init__(self,
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
information_name: str,
|
||||
default_value: Any=undefined,
|
||||
option: 'Option'=None
|
||||
default_value: Any = undefined,
|
||||
option: "Option" = None,
|
||||
) -> None:
|
||||
self.information_name = information_name
|
||||
self.default_value = default_value
|
||||
|
@ -174,20 +201,22 @@ class ParamInformation(Param):
|
|||
def set_self_option(self, option):
|
||||
self.self_option = option
|
||||
|
||||
def set_option(self,
|
||||
option: 'Option'=None
|
||||
) -> None:
|
||||
if not hasattr(self, 'self_option'):
|
||||
raise ConfigError('cannot add option in information after creating config')
|
||||
def set_option(self, option: "Option" = None) -> None:
|
||||
if not hasattr(self, "self_option"):
|
||||
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(_('option in ParamInformation cannot be a symlinkoption'))
|
||||
raise ValueError(
|
||||
_("option in ParamInformation cannot be a symlinkoption")
|
||||
)
|
||||
if option.impl_is_follower():
|
||||
raise ValueError(_('option in ParamInformation cannot be a follower'))
|
||||
raise ValueError(_("option in ParamInformation cannot be a follower"))
|
||||
if option.impl_is_dynsymlinkoption():
|
||||
raise ValueError(_('option in ParamInformation cannot be a dynamic option'))
|
||||
raise ValueError(
|
||||
_("option in ParamInformation cannot be a dynamic option")
|
||||
)
|
||||
self.option = option
|
||||
if self.self_option:
|
||||
informations = self.self_option._dependencies_information
|
||||
|
@ -195,19 +224,24 @@ class ParamInformation(Param):
|
|||
del self.self_option._dependencies_information
|
||||
else:
|
||||
informations.remove(None)
|
||||
if not getattr(option, '_dependencies_information', {}):
|
||||
if not getattr(option, "_dependencies_information", {}):
|
||||
option._dependencies_information = {None: []}
|
||||
option._dependencies_information[None].append(self)
|
||||
option._dependencies_information.setdefault(self.information_name, []).append(weakref.ref(self.self_option))
|
||||
option._dependencies_information.setdefault(
|
||||
self.information_name, []
|
||||
).append(weakref.ref(self.self_option))
|
||||
|
||||
|
||||
class ParamSelfInformation(ParamInformation):
|
||||
__slots__ = tuple()
|
||||
def __init__(self,
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
information_name: str,
|
||||
default_value: Any=undefined,
|
||||
default_value: Any = undefined,
|
||||
) -> None:
|
||||
return super().__init__(information_name,
|
||||
return super().__init__(
|
||||
information_name,
|
||||
default_value,
|
||||
)
|
||||
|
||||
|
@ -217,29 +251,38 @@ class ParamIndex(Param):
|
|||
|
||||
|
||||
class ParamIdentifier(Param):
|
||||
__slots__ = ('identifier_index',)
|
||||
def __init__(self,
|
||||
identifier_index: int=-1,
|
||||
__slots__ = ("identifier_index",)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
identifier_index: int = -1,
|
||||
) -> None:
|
||||
self.identifier_index = identifier_index
|
||||
|
||||
|
||||
class Calculation:
|
||||
__slots__ = ('function',
|
||||
'params',
|
||||
'help_function',
|
||||
'_has_index',
|
||||
'warnings_only',
|
||||
__slots__ = (
|
||||
"function",
|
||||
"params",
|
||||
"help_function",
|
||||
"_has_index",
|
||||
"warnings_only",
|
||||
)
|
||||
def __init__(self,
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
function: Callable,
|
||||
params: Params=Params(),
|
||||
help_function: Optional[Callable]=None,
|
||||
warnings_only: bool=False,
|
||||
params: Params = Params(),
|
||||
help_function: Optional[Callable] = None,
|
||||
warnings_only: bool = False,
|
||||
):
|
||||
assert isinstance(function, Callable), _('first argument ({0}) must be a function').format(function)
|
||||
assert isinstance(function, Callable), _(
|
||||
"first argument ({0}) must be a function"
|
||||
).format(function)
|
||||
if help_function:
|
||||
assert isinstance(help_function, Callable), _('help_function ({0}) must be a function').format(help_function)
|
||||
assert isinstance(help_function, Callable), _(
|
||||
"help_function ({0}) must be a function"
|
||||
).format(help_function)
|
||||
self.help_function = help_function
|
||||
else:
|
||||
self.help_function = None
|
||||
|
@ -252,16 +295,18 @@ class Calculation:
|
|||
if warnings_only is True:
|
||||
self.warnings_only = warnings_only
|
||||
|
||||
def execute(self,
|
||||
def execute(
|
||||
self,
|
||||
subconfig: "SubConfig",
|
||||
*,
|
||||
orig_value: Any=undefined,
|
||||
allow_value_error: bool=False,
|
||||
force_value_warning: bool=False,
|
||||
for_settings: bool=False,
|
||||
validate_properties: bool=True,
|
||||
orig_value: Any = undefined,
|
||||
allow_value_error: bool = False,
|
||||
force_value_warning: bool = False,
|
||||
for_settings: bool = False,
|
||||
validate_properties: bool = True,
|
||||
) -> Any:
|
||||
return carry_out_calculation(subconfig,
|
||||
return carry_out_calculation(
|
||||
subconfig,
|
||||
callback=self.function,
|
||||
callback_params=self.params,
|
||||
index=subconfig.index,
|
||||
|
@ -273,15 +318,18 @@ class Calculation:
|
|||
validate_properties=validate_properties,
|
||||
)
|
||||
|
||||
def help(self,
|
||||
def help(
|
||||
self,
|
||||
subconfig: "SubConfig",
|
||||
for_settings: bool=False,
|
||||
for_settings: bool = False,
|
||||
) -> str:
|
||||
if not self.help_function:
|
||||
return self.execute(subconfig,
|
||||
return self.execute(
|
||||
subconfig,
|
||||
for_settings=for_settings,
|
||||
)
|
||||
return carry_out_calculation(subconfig,
|
||||
return carry_out_calculation(
|
||||
subconfig,
|
||||
callback=self.help_function,
|
||||
callback_params=self.params,
|
||||
index=subconfig.index,
|
||||
|
@ -293,24 +341,27 @@ class Calculation:
|
|||
return x
|
||||
|
||||
|
||||
def manager_callback(callback: Callable,
|
||||
def manager_callback(
|
||||
callback: Callable,
|
||||
param: Param,
|
||||
subconfig: 'SubConfig',
|
||||
subconfig: "SubConfig",
|
||||
index: Optional[int],
|
||||
orig_value,
|
||||
config_bag: ConfigBag,
|
||||
for_settings: bool,
|
||||
validate_properties: bool,
|
||||
) -> Any:
|
||||
) -> Any:
|
||||
"""replace Param by true value"""
|
||||
option = subconfig.option
|
||||
def calc_apply_index(param,
|
||||
|
||||
def calc_apply_index(
|
||||
param,
|
||||
same_leadership,
|
||||
):
|
||||
return index is not None and \
|
||||
not getattr(param, 'whole', not same_leadership)
|
||||
return index is not None and not getattr(param, "whole", not same_leadership)
|
||||
|
||||
def calc_self(param,
|
||||
def calc_self(
|
||||
param,
|
||||
index,
|
||||
value,
|
||||
config_bag,
|
||||
|
@ -318,15 +369,18 @@ def manager_callback(callback: Callable,
|
|||
# index must be apply only if follower
|
||||
is_follower = subconfig.option.impl_is_follower()
|
||||
# FIXME "same_leadership" or "is_follower"?
|
||||
apply_index = calc_apply_index(param,
|
||||
apply_index = calc_apply_index(
|
||||
param,
|
||||
is_follower,
|
||||
)
|
||||
if value is undefined or (apply_index is False and is_follower):
|
||||
path = subconfig.path
|
||||
properties = config_bag.context.get_settings().getproperties(subconfig,
|
||||
properties = config_bag.context.get_settings().getproperties(
|
||||
subconfig,
|
||||
uncalculated=True,
|
||||
)
|
||||
new_value = get_value(config_bag,
|
||||
new_value = get_value(
|
||||
config_bag,
|
||||
subconfig,
|
||||
param,
|
||||
True,
|
||||
|
@ -340,7 +394,8 @@ def manager_callback(callback: Callable,
|
|||
value = value[index]
|
||||
return value
|
||||
|
||||
def get_value(config_bag,
|
||||
def get_value(
|
||||
config_bag,
|
||||
subconfig,
|
||||
param,
|
||||
self_calc,
|
||||
|
@ -349,52 +404,84 @@ def manager_callback(callback: Callable,
|
|||
properties=undefined,
|
||||
):
|
||||
option = subconfig.option
|
||||
if option.impl_is_follower() and (subconfig.index is None or apply_index is False):
|
||||
if option.impl_is_follower() and (
|
||||
subconfig.index is None or apply_index is False
|
||||
):
|
||||
value = []
|
||||
for idx in range(subconfig.parent.get_length_leadership()):
|
||||
subconfig = get_option_bag(config_bag,
|
||||
subconfig = get_option_bag(
|
||||
config_bag,
|
||||
option,
|
||||
param,
|
||||
idx,
|
||||
self_calc,
|
||||
properties=properties,
|
||||
)
|
||||
value.append(_get_value(param,
|
||||
value.append(
|
||||
_get_value(
|
||||
param,
|
||||
subconfig,
|
||||
))
|
||||
)
|
||||
)
|
||||
else:
|
||||
value = _get_value(param,
|
||||
value = _get_value(
|
||||
param,
|
||||
subconfig,
|
||||
)
|
||||
return value
|
||||
|
||||
def _get_value(param: Params,
|
||||
subconfig: 'SubConfig',
|
||||
def _get_value(
|
||||
param: Params,
|
||||
subconfig: "SubConfig",
|
||||
) -> Any:
|
||||
try:
|
||||
# get value
|
||||
value = config_bag.context.get_value(subconfig)
|
||||
except PropertiesOptionError as err:
|
||||
# raise PropertiesOptionError (which is catched) because must not add value None in carry_out_calculation
|
||||
if isinstance(param, ParamSelfOption) or param.notraisepropertyerror or param.raisepropertyerror:
|
||||
if (
|
||||
isinstance(param, ParamSelfOption)
|
||||
or param.notraisepropertyerror
|
||||
or param.raisepropertyerror
|
||||
):
|
||||
raise err from 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
|
||||
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)
|
||||
raise ValueError(_('the option {0} is used in a calculation but is invalid ({1})').format(display_name, err)) from err
|
||||
display_name = subconfig.option.impl_get_display_name(
|
||||
subconfig, with_quote=True
|
||||
)
|
||||
raise ValueError(
|
||||
_(
|
||||
"the option {0} is used in a calculation but is invalid ({1})"
|
||||
).format(display_name, err)
|
||||
) from err
|
||||
except AttributeError as err:
|
||||
if isinstance(param, ParamDynOption) and param.optional:
|
||||
# cannot acces, simulate a propertyerror
|
||||
raise PropertiesOptionError(subconfig,
|
||||
['configerror'],
|
||||
raise PropertiesOptionError(
|
||||
subconfig,
|
||||
["configerror"],
|
||||
config_bag.context.get_settings(),
|
||||
)
|
||||
display_name = subconfig.option.impl_get_display_name(subconfig, with_quote=True)
|
||||
raise ConfigError(_(f'unable to get value for calculating {display_name}, {err}')) from 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(config_bag,
|
||||
def get_option_bag(
|
||||
config_bag,
|
||||
opt,
|
||||
param,
|
||||
index_,
|
||||
|
@ -404,14 +491,15 @@ def manager_callback(callback: Callable,
|
|||
):
|
||||
# don't validate if option is option that we tried to validate
|
||||
if for_settings:
|
||||
config_bag.properties = config_bag.properties - {'warnings'}
|
||||
config_bag.properties = config_bag.properties - {"warnings"}
|
||||
if not for_settings:
|
||||
config_bag.properties -= {'warnings'}
|
||||
config_bag.properties -= {"warnings"}
|
||||
if self_calc:
|
||||
config_bag.unrestraint()
|
||||
config_bag.remove_validation()
|
||||
try:
|
||||
subsubconfig = config_bag.context.get_sub_config(config_bag,
|
||||
subsubconfig = config_bag.context.get_sub_config(
|
||||
config_bag,
|
||||
opt.impl_getpath(),
|
||||
index_,
|
||||
validate_properties=not self_calc,
|
||||
|
@ -422,19 +510,32 @@ def manager_callback(callback: Callable,
|
|||
if param.notraisepropertyerror or param.raisepropertyerror:
|
||||
raise err from err
|
||||
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
|
||||
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(_('the option {0} is used in a calculation but is invalid ({1})').format(display_name, err)) from err
|
||||
raise ValueError(
|
||||
_(
|
||||
"the option {0} is used in a calculation but is invalid ({1})"
|
||||
).format(display_name, err)
|
||||
) from err
|
||||
except AttributeError as err:
|
||||
if isinstance(param, ParamDynOption) and param.optional:
|
||||
# cannot acces, simulate a propertyerror
|
||||
raise PropertiesOptionError(param,
|
||||
['configerror'],
|
||||
raise PropertiesOptionError(
|
||||
param,
|
||||
["configerror"],
|
||||
config_bag.context.get_settings(),
|
||||
)
|
||||
display_name = option.impl_get_display_name(subconfig, with_quote=True)
|
||||
raise ConfigError(_(f'unable to get value for calculating {display_name}, {err}')) from err
|
||||
raise ConfigError(
|
||||
_("unable to get value for calculating {0}, {1}").format(
|
||||
display_name, err
|
||||
)
|
||||
) from err
|
||||
return subsubconfig
|
||||
|
||||
if isinstance(param, ParamValue):
|
||||
|
@ -446,57 +547,84 @@ def manager_callback(callback: Callable,
|
|||
elif param.option:
|
||||
if param.option.issubdyn():
|
||||
search_option = param.option
|
||||
isubconfig = subconfig.get_common_child(search_option,
|
||||
isubconfig = subconfig.get_common_child(
|
||||
search_option,
|
||||
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)
|
||||
raise ConfigError(f'cannot find information for {display_name}, {search_name} is a dynamic option')
|
||||
display_name = option.impl_get_display_name(
|
||||
subconfig, with_quote=True
|
||||
)
|
||||
search_name = search_option.impl_get_display_name(
|
||||
None, with_quote=True
|
||||
)
|
||||
raise ConfigError(
|
||||
f"cannot find information for {display_name}, {search_name} is a dynamic option"
|
||||
)
|
||||
else:
|
||||
isubconfig = get_option_bag(config_bag,
|
||||
isubconfig = get_option_bag(
|
||||
config_bag,
|
||||
param.option,
|
||||
param,
|
||||
None,
|
||||
False,
|
||||
#properties=properties,
|
||||
# properties=properties,
|
||||
)
|
||||
else:
|
||||
isubconfig = config_bag.context.get_root(config_bag)
|
||||
try:
|
||||
return config_bag.context.get_values().get_information(isubconfig,
|
||||
return config_bag.context.get_values().get_information(
|
||||
isubconfig,
|
||||
param.information_name,
|
||||
param.default_value,
|
||||
)
|
||||
except ValueError as err:
|
||||
display_name = option.impl_get_display_name(subconfig, with_quote=True)
|
||||
raise ConfigError(_(f'unable to get value for calculating {display_name}, {err}')) from err
|
||||
raise ConfigError(
|
||||
_("unable to get value for calculating {0}, {1}").format(
|
||||
display_name, err
|
||||
)
|
||||
) from err
|
||||
|
||||
if isinstance(param, ParamIndex):
|
||||
return index
|
||||
|
||||
if isinstance(param, ParamIdentifier):
|
||||
if not option.issubdyn() and (not option.impl_is_optiondescription() or not option.impl_is_dynoptiondescription()):
|
||||
display_name = subconfig.option.impl_get_display_name(subconfig, with_quote=True)
|
||||
raise ConfigError(_(f'option {display_name} is not a dynoptiondescription or in a dynoptiondescription'))
|
||||
if not option.issubdyn() and (
|
||||
not option.impl_is_optiondescription()
|
||||
or not option.impl_is_dynoptiondescription()
|
||||
):
|
||||
display_name = subconfig.option.impl_get_display_name(
|
||||
subconfig, with_quote=True
|
||||
)
|
||||
raise ConfigError(
|
||||
_(
|
||||
"option {0} is not a dynoptiondescription or in a dynoptiondescription"
|
||||
).format(display_name)
|
||||
)
|
||||
return subconfig.identifiers[param.identifier_index]
|
||||
|
||||
if isinstance(param, ParamSelfOption):
|
||||
value = calc_self(param,
|
||||
value = calc_self(
|
||||
param,
|
||||
index,
|
||||
orig_value,
|
||||
config_bag,
|
||||
)
|
||||
if callback.__name__ not in FUNCTION_WAITING_FOR_DICT:
|
||||
return value
|
||||
return {'name': option.impl_get_display_name(subconfig),
|
||||
'value': value,
|
||||
return {
|
||||
"name": option.impl_get_display_name(subconfig),
|
||||
"value": value,
|
||||
}
|
||||
|
||||
if isinstance(param, ParamOption):
|
||||
callbk_option = param.option
|
||||
if index is not None and callbk_option.impl_get_leadership() and \
|
||||
callbk_option.impl_get_leadership().in_same_leadership(option):
|
||||
if (
|
||||
index is not None
|
||||
and callbk_option.impl_get_leadership()
|
||||
and callbk_option.impl_get_leadership().in_same_leadership(option)
|
||||
):
|
||||
if not callbk_option.impl_is_follower():
|
||||
# leader
|
||||
index_ = None
|
||||
|
@ -511,13 +639,14 @@ def manager_callback(callback: Callable,
|
|||
if callbk_option.issubdyn():
|
||||
if isinstance(param, ParamDynOption):
|
||||
identifiers = param.identifiers.copy()
|
||||
paths = callbk_option.impl_getpath().split('.')
|
||||
paths = callbk_option.impl_getpath().split(".")
|
||||
parents = [config_bag.context.get_root(config_bag)]
|
||||
subconfigs_is_a_list = False
|
||||
for name in paths:
|
||||
new_parents = []
|
||||
for parent in parents:
|
||||
doption = parent.option.get_child(name,
|
||||
doption = parent.option.get_child(
|
||||
name,
|
||||
config_bag,
|
||||
parent,
|
||||
allow_dynoption=True,
|
||||
|
@ -529,31 +658,40 @@ def manager_callback(callback: Callable,
|
|||
identifier = identifiers.pop(0)
|
||||
if not identifier:
|
||||
subconfigs_is_a_list = True
|
||||
new_parents.extend(parent.dyn_to_subconfig(doption,
|
||||
new_parents.extend(
|
||||
parent.dyn_to_subconfig(
|
||||
doption,
|
||||
True,
|
||||
)
|
||||
)
|
||||
else:
|
||||
name = doption.impl_getname(identifier)
|
||||
try:
|
||||
doption = parent.option.get_child(name,
|
||||
doption = parent.option.get_child(
|
||||
name,
|
||||
config_bag,
|
||||
parent,
|
||||
)
|
||||
except AttributeError as err:
|
||||
raise ConfigError(err) from err
|
||||
new_parents.append(parent.get_child(doption,
|
||||
new_parents.append(
|
||||
parent.get_child(
|
||||
doption,
|
||||
None,
|
||||
True,
|
||||
name=name,
|
||||
identifier=identifier,
|
||||
))
|
||||
)
|
||||
)
|
||||
else:
|
||||
new_parents.append(parent.get_child(doption,
|
||||
new_parents.append(
|
||||
parent.get_child(
|
||||
doption,
|
||||
None,
|
||||
True,
|
||||
name=name,
|
||||
))
|
||||
)
|
||||
)
|
||||
parents = new_parents
|
||||
|
||||
if subconfigs_is_a_list:
|
||||
|
@ -563,7 +701,8 @@ def manager_callback(callback: Callable,
|
|||
|
||||
else:
|
||||
search_option = param.option
|
||||
subconfigs = subconfig.get_common_child(search_option,
|
||||
subconfigs = subconfig.get_common_child(
|
||||
search_option,
|
||||
true_path=subconfig.path,
|
||||
validate_properties=validate_properties,
|
||||
)
|
||||
|
@ -573,18 +712,21 @@ def manager_callback(callback: Callable,
|
|||
values = None
|
||||
subconfigs = [subconfigs]
|
||||
else:
|
||||
subconfigs = [get_option_bag(config_bag,
|
||||
subconfigs = [
|
||||
get_option_bag(
|
||||
config_bag,
|
||||
callbk_option,
|
||||
param,
|
||||
index_,
|
||||
False,
|
||||
#properties=properties,
|
||||
# properties=properties,
|
||||
)
|
||||
]
|
||||
values = None
|
||||
for subconfig in subconfigs:
|
||||
callbk_option = subconfig.option
|
||||
value = get_value(config_bag,
|
||||
value = get_value(
|
||||
config_bag,
|
||||
subconfig,
|
||||
param,
|
||||
False,
|
||||
|
@ -597,22 +739,22 @@ def manager_callback(callback: Callable,
|
|||
value = values
|
||||
if callback.__name__ not in FUNCTION_WAITING_FOR_DICT:
|
||||
return value
|
||||
return {'name': callbk_option.impl_get_display_name(subconfig),
|
||||
'value': value}
|
||||
return {"name": callbk_option.impl_get_display_name(subconfig), "value": value}
|
||||
|
||||
|
||||
def carry_out_calculation(subconfig: 'SubConfig',
|
||||
def carry_out_calculation(
|
||||
subconfig: "SubConfig",
|
||||
callback: Callable,
|
||||
callback_params: Optional[Params],
|
||||
index: Optional[int],
|
||||
config_bag: Optional[ConfigBag],
|
||||
orig_value=undefined,
|
||||
allow_value_error: bool=False,
|
||||
force_value_warning: bool=False,
|
||||
for_settings: bool=False,
|
||||
allow_value_error: bool = False,
|
||||
force_value_warning: bool = False,
|
||||
for_settings: bool = False,
|
||||
*,
|
||||
validate_properties: bool=True,
|
||||
):
|
||||
validate_properties: bool = True,
|
||||
):
|
||||
"""a function that carries out a calculation for an option's value
|
||||
|
||||
:param option: the option
|
||||
|
@ -630,18 +772,29 @@ def carry_out_calculation(subconfig: 'SubConfig',
|
|||
if PropertiesOptionError)
|
||||
Values could have multiple values only when key is ''."""
|
||||
option = subconfig.option
|
||||
if not option.impl_is_optiondescription() and option.impl_is_follower() and index is None:
|
||||
raise ConfigError(f'the follower {option.impl_get_display_name(subconfig, with_quote=True)} must have index in carry_out_calculation!')
|
||||
if (
|
||||
not option.impl_is_optiondescription()
|
||||
and option.impl_is_follower()
|
||||
and index is None
|
||||
):
|
||||
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):
|
||||
return ((None, i) for i in iterator)
|
||||
|
||||
args = []
|
||||
kwargs = {}
|
||||
config_bag = config_bag.copy()
|
||||
config_bag.set_permissive()
|
||||
if callback_params:
|
||||
for key, param in chain(fake_items(callback_params.args), callback_params.kwargs.items()):
|
||||
for key, param in chain(
|
||||
fake_items(callback_params.args), callback_params.kwargs.items()
|
||||
):
|
||||
try:
|
||||
value = manager_callback(callback,
|
||||
value = manager_callback(
|
||||
callback,
|
||||
param,
|
||||
subconfig,
|
||||
index,
|
||||
|
@ -659,49 +812,75 @@ def carry_out_calculation(subconfig: 'SubConfig',
|
|||
raise err
|
||||
if callback.__name__ in FUNCTION_WAITING_FOR_DICT:
|
||||
if key is None:
|
||||
args.append({'propertyerror': str(err), 'name': option.impl_get_display_name(subconfig)})
|
||||
args.append(
|
||||
{
|
||||
"propertyerror": str(err),
|
||||
"name": option.impl_get_display_name(subconfig),
|
||||
}
|
||||
)
|
||||
else:
|
||||
kwargs[key] = {'propertyerror': str(err), 'name': option.impl_get_display_name(subconfig)}
|
||||
kwargs[key] = {
|
||||
"propertyerror": str(err),
|
||||
"name": option.impl_get_display_name(subconfig),
|
||||
}
|
||||
if callback.__name__ in FUNCTION_WAITING_FOR_ERROR:
|
||||
if key is None:
|
||||
args.append(err)
|
||||
else:
|
||||
kwargs[key] = err
|
||||
ret = calculate(subconfig,
|
||||
ret = calculate(
|
||||
subconfig,
|
||||
callback,
|
||||
allow_value_error,
|
||||
force_value_warning,
|
||||
args,
|
||||
kwargs,
|
||||
)
|
||||
if isinstance(ret, list) and not option.impl_is_dynoptiondescription() and \
|
||||
not option.impl_is_optiondescription() and \
|
||||
option.impl_is_follower() and not option.impl_is_submulti():
|
||||
if (
|
||||
isinstance(ret, list)
|
||||
and not option.impl_is_dynoptiondescription()
|
||||
and not option.impl_is_optiondescription()
|
||||
and option.impl_is_follower()
|
||||
and not option.impl_is_submulti()
|
||||
):
|
||||
if args or kwargs:
|
||||
raise LeadershipError(_('the "{}" function with positional arguments "{}" '
|
||||
raise LeadershipError(
|
||||
_(
|
||||
'the "{}" function with positional arguments "{}" '
|
||||
'and keyword arguments "{}" must not return '
|
||||
'a list ("{}") for the follower option {}'
|
||||
'').format(callback.__name__,
|
||||
""
|
||||
).format(
|
||||
callback.__name__,
|
||||
args,
|
||||
kwargs,
|
||||
ret,
|
||||
option.impl_get_display_name(subconfig, with_quote=True)))
|
||||
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__,
|
||||
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)))
|
||||
option.impl_get_display_name(subconfig, with_quote=True),
|
||||
)
|
||||
)
|
||||
return ret
|
||||
|
||||
|
||||
def calculate(subconfig,
|
||||
def calculate(
|
||||
subconfig,
|
||||
callback: Callable,
|
||||
allow_value_error: bool,
|
||||
force_value_warning: bool,
|
||||
args,
|
||||
kwargs,
|
||||
):
|
||||
):
|
||||
"""wrapper that launches the 'callback'
|
||||
|
||||
:param callback: callback function
|
||||
|
@ -722,15 +901,20 @@ def calculate(subconfig,
|
|||
except Exception as err:
|
||||
error = err
|
||||
if args or kwargs:
|
||||
msg = _('unexpected error "{0}" in function "{1}" with arguments "{3}" and "{4}" '
|
||||
'for option {2}').format(str(error),
|
||||
msg = _(
|
||||
'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)
|
||||
kwargs,
|
||||
)
|
||||
else:
|
||||
msg = _('unexpected error "{0}" in function "{1}" for option {2}'
|
||||
'').format(str(error),
|
||||
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))
|
||||
subconfig.option.impl_get_display_name(subconfig, with_quote=True),
|
||||
)
|
||||
raise ConfigError(msg) from error
|
||||
|
|
|
@ -19,9 +19,9 @@ from time import time
|
|||
|
||||
|
||||
class Cache:
|
||||
"""cache object
|
||||
"""
|
||||
__slots__ = ('_cache',)
|
||||
"""cache object"""
|
||||
|
||||
__slots__ = ("_cache",)
|
||||
|
||||
def __init__(self):
|
||||
self._cache = {}
|
||||
|
@ -35,29 +35,30 @@ class Cache:
|
|||
index = subconfig.index
|
||||
return path, index
|
||||
|
||||
def getcache(self,
|
||||
def getcache(
|
||||
self,
|
||||
subconfig,
|
||||
type_,
|
||||
expiration=True,
|
||||
):
|
||||
"""get the cache value fot a specified path
|
||||
"""
|
||||
"""get the cache value fot a specified path"""
|
||||
no_cache = False, None, False
|
||||
path, index = self._get_path_index(subconfig)
|
||||
if path not in self._cache or index not in self._cache[path]:
|
||||
return no_cache
|
||||
value, timestamp, validated = self._cache[path][index]
|
||||
props = subconfig.config_bag.properties
|
||||
if type_ == 'self_props':
|
||||
if type_ == "self_props":
|
||||
# cached value is self_props
|
||||
self_props = value
|
||||
else:
|
||||
self_props = subconfig.properties
|
||||
if 'cache' in props or \
|
||||
'cache' in self_props:
|
||||
if expiration and timestamp and \
|
||||
('expire' in props or \
|
||||
'expire' in self_props):
|
||||
if "cache" in props or "cache" in self_props:
|
||||
if (
|
||||
expiration
|
||||
and timestamp
|
||||
and ("expire" in props or "expire" in self_props)
|
||||
):
|
||||
ntime = int(time())
|
||||
if timestamp + subconfig.config_bag.expiration_time >= ntime:
|
||||
return True, value, validated
|
||||
|
@ -65,37 +66,38 @@ class Cache:
|
|||
return True, value, validated
|
||||
return no_cache
|
||||
|
||||
def setcache(self,
|
||||
def setcache(
|
||||
self,
|
||||
subconfig,
|
||||
val,
|
||||
type_='values',
|
||||
type_="values",
|
||||
validated=True,
|
||||
):
|
||||
"""add val in cache for a specified path
|
||||
if follower, add index
|
||||
"""
|
||||
if type_ == 'values':
|
||||
if 'cache' not in subconfig.config_bag.properties and \
|
||||
'cache' not in subconfig.properties:
|
||||
if type_ == "values":
|
||||
if (
|
||||
"cache" not in subconfig.config_bag.properties
|
||||
and "cache" not in subconfig.properties
|
||||
):
|
||||
return
|
||||
elif (subconfig is None or 'cache' not in subconfig.config_bag.properties) and \
|
||||
'cache' not in val:
|
||||
elif (
|
||||
subconfig is None or "cache" not in subconfig.config_bag.properties
|
||||
) and "cache" not in val:
|
||||
return
|
||||
path, index = self._get_path_index(subconfig)
|
||||
self._cache.setdefault(path, {})[index] = (val, int(time()), validated)
|
||||
|
||||
def delcache(self, path):
|
||||
"""reset cache a a specified path
|
||||
"""
|
||||
"""reset cache a a specified path"""
|
||||
if path in self._cache:
|
||||
del self._cache[path]
|
||||
|
||||
def get_cached(self):
|
||||
"""get cache values
|
||||
"""
|
||||
"""get cache values"""
|
||||
return self._cache
|
||||
|
||||
def reset_all_cache(self):
|
||||
"""reset all cache values
|
||||
"""
|
||||
"""reset all cache values"""
|
||||
self._cache.clear()
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -19,17 +19,18 @@ import weakref
|
|||
from .i18n import _
|
||||
|
||||
|
||||
def display_list(lst,
|
||||
def display_list(
|
||||
lst,
|
||||
*,
|
||||
separator='and',
|
||||
separator="and",
|
||||
add_quote=False,
|
||||
) -> str():
|
||||
) -> str():
|
||||
if not lst:
|
||||
return '""'
|
||||
if separator == 'and':
|
||||
separator = _('and')
|
||||
elif separator == 'or':
|
||||
separator = _('or')
|
||||
if separator == "and":
|
||||
separator = _("and")
|
||||
elif separator == "or":
|
||||
separator = _("or")
|
||||
if isinstance(lst, tuple) or isinstance(lst, frozenset):
|
||||
lst = list(lst)
|
||||
if len(lst) == 1:
|
||||
|
@ -51,30 +52,35 @@ def display_list(lst,
|
|||
lst__.append(l)
|
||||
lst__.sort()
|
||||
last = lst__[-1]
|
||||
return ', '.join(lst__[:-1]) + _(' {} ').format(separator) + '{}'.format(last)
|
||||
return ", ".join(lst__[:-1]) + _(" {} ").format(separator) + "{}".format(last)
|
||||
|
||||
|
||||
# Exceptions for an Option
|
||||
class PropertiesOptionError(AttributeError):
|
||||
"attempt to access to an option with a property that is not allowed"
|
||||
def __init__(self,
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
subconfig,
|
||||
proptype,
|
||||
settings,
|
||||
opt_type=None,
|
||||
name=None,
|
||||
orig_opt=None,
|
||||
help_properties=None):
|
||||
help_properties=None,
|
||||
):
|
||||
if opt_type:
|
||||
self._opt_type = opt_type
|
||||
self._name = name
|
||||
self._orig_opt = orig_opt
|
||||
else:
|
||||
if subconfig.option.impl_is_optiondescription():
|
||||
self._opt_type = 'optiondescription'
|
||||
self._opt_type = "optiondescription"
|
||||
else:
|
||||
self._opt_type = 'option'
|
||||
self._name = subconfig.option.impl_get_display_name(subconfig, with_quote=True)
|
||||
self._opt_type = "option"
|
||||
self._name = subconfig.option.impl_get_display_name(
|
||||
subconfig, with_quote=True
|
||||
)
|
||||
self._orig_opt = None
|
||||
self._subconfig = subconfig
|
||||
self.proptype = proptype
|
||||
|
@ -91,7 +97,7 @@ class PropertiesOptionError(AttributeError):
|
|||
if self.msg is not None:
|
||||
return self.msg
|
||||
if self._settings is None:
|
||||
return 'error'
|
||||
return "error"
|
||||
if self.help_properties:
|
||||
properties = list(self.help_properties)
|
||||
else:
|
||||
|
@ -99,43 +105,44 @@ class PropertiesOptionError(AttributeError):
|
|||
only_one = len(properties) == 1
|
||||
properties_msg = display_list(properties, add_quote=True)
|
||||
if only_one:
|
||||
prop_msg = _('property')
|
||||
prop_msg = _("property")
|
||||
else:
|
||||
prop_msg = _('properties')
|
||||
if properties == ['frozen']:
|
||||
prop_msg = _("properties")
|
||||
if properties == ["frozen"]:
|
||||
if self._orig_opt:
|
||||
msg = 'cannot modify the {0} {1} because "{2}" has {3} {4}'
|
||||
msg = _('cannot modify the {0} {1} because "{2}" has {3} {4}')
|
||||
else:
|
||||
msg = 'cannot modify the {0} {1} because has {2} {3}'
|
||||
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}'
|
||||
msg = _('cannot access to {0} {1} because "{2}" has {3} {4}')
|
||||
else:
|
||||
msg = 'cannot access to {0} {1} because has {2} {3}'
|
||||
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.msg = msg.format(
|
||||
self._opt_type,
|
||||
self._orig_opt.impl_get_display_name(subconfig, with_quote=True),
|
||||
self._name,
|
||||
prop_msg,
|
||||
properties_msg)
|
||||
properties_msg,
|
||||
)
|
||||
else:
|
||||
self.msg = _(msg).format(self._opt_type,
|
||||
self._name,
|
||||
prop_msg,
|
||||
properties_msg)
|
||||
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
|
||||
|
||||
|
||||
#____________________________________________________________
|
||||
# ____________________________________________________________
|
||||
# Exceptions for a Config
|
||||
class ConfigError(Exception):
|
||||
"""attempt to change an option's owner without a value
|
||||
or in case of `_descr` is None
|
||||
or if a calculation cannot be carried out"""
|
||||
def __init__(self,
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
exp,
|
||||
ori_err=None,
|
||||
):
|
||||
|
@ -148,8 +155,8 @@ class ConflictError(Exception):
|
|||
pass
|
||||
|
||||
|
||||
#____________________________________________________________
|
||||
# miscellaneous exceptions
|
||||
# ____________________________________________________________
|
||||
# miscellaneous exceptions
|
||||
class LeadershipError(Exception):
|
||||
"problem with a leadership's value length"
|
||||
pass
|
||||
|
@ -161,13 +168,7 @@ class ConstError(TypeError):
|
|||
|
||||
|
||||
class _CommonError:
|
||||
def __init__(self,
|
||||
subconfig,
|
||||
val,
|
||||
display_type,
|
||||
opt,
|
||||
err_msg,
|
||||
index):
|
||||
def __init__(self, subconfig, val, display_type, opt, err_msg, index):
|
||||
self.val = val
|
||||
self.display_type = display_type
|
||||
self.opt = weakref.ref(opt)
|
||||
|
@ -180,24 +181,24 @@ class _CommonError:
|
|||
try:
|
||||
msg = self.prefix
|
||||
except AttributeError:
|
||||
self.prefix = self.tmpl.format(self.val,
|
||||
_(self.display_type),
|
||||
self.name)
|
||||
self.prefix = self.tmpl.format(self.val, _(self.display_type), self.name)
|
||||
msg = self.prefix
|
||||
if self.err_msg:
|
||||
if msg:
|
||||
msg += ', {}'.format(self.err_msg)
|
||||
msg += ", {}".format(self.err_msg)
|
||||
else:
|
||||
msg = self.err_msg
|
||||
if not msg:
|
||||
msg = _('invalid value')
|
||||
msg = _("invalid value")
|
||||
return msg
|
||||
|
||||
|
||||
class ValueWarning(_CommonError, UserWarning):
|
||||
tmpl = _('attention, "{0}" could be an invalid {1} for "{2}"')
|
||||
tmpl = None
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
if ValueWarning.tmpl is None:
|
||||
ValueWarning.tmpl = _('attention, "{0}" could be an invalid {1} for "{2}"')
|
||||
if len(args) == 1 and not kwargs:
|
||||
self.msg = args[0]
|
||||
else:
|
||||
|
@ -211,8 +212,18 @@ class ValueWarning(_CommonError, UserWarning):
|
|||
|
||||
|
||||
class ValueOptionError(_CommonError, ValueError):
|
||||
tmpl = _('"{0}" is an invalid {1} for "{2}"')
|
||||
tmpl = None
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
if ValueOptionError.tmpl is None:
|
||||
ValueOptionError.tmpl = _('"{0}" is an invalid {1} for "{2}"')
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
||||
class ValueErrorWarning(ValueWarning):
|
||||
tmpl = _('"{0}" is an invalid {1} for "{2}"')
|
||||
tmpl = None
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
if ValueErrorWarning.tmpl is None:
|
||||
ValueErrorWarning.tmpl = _('"{0}" is an invalid {1} for "{2}"')
|
||||
super().__init__(*args, **kwargs)
|
||||
|
|
|
@ -48,73 +48,83 @@ def function_waiting_for_error(function):
|
|||
|
||||
|
||||
@function_waiting_for_dict
|
||||
def valid_network_netmask(network: dict,
|
||||
def valid_network_netmask(
|
||||
network: dict,
|
||||
netmask: dict,
|
||||
):
|
||||
):
|
||||
"""
|
||||
validates if network and netmask are coherent
|
||||
this validator must be set to netmask option
|
||||
"""
|
||||
if None in [network['value'], netmask['value']]:
|
||||
if None in [network["value"], netmask["value"]]:
|
||||
return
|
||||
try:
|
||||
ip_network(f'{network["value"]}/{netmask["value"]}')
|
||||
except ValueError as err:
|
||||
raise ValueError(_(f'network "{network["value"]}" ({network["name"]}) does not match '
|
||||
'with this netmask')) from err
|
||||
raise ValueError(
|
||||
_('network "{0}" ({1}) does not match with this netmask').format(
|
||||
network["value"], network["name"]
|
||||
)
|
||||
) from err
|
||||
|
||||
|
||||
@function_waiting_for_dict
|
||||
def valid_ip_netmask(ip: dict, # pylint: disable=invalid-name
|
||||
def valid_ip_netmask(
|
||||
ip: dict, # pylint: disable=invalid-name
|
||||
netmask: dict,
|
||||
):
|
||||
):
|
||||
"""validates if ip and netmask are coherent
|
||||
this validator must be set to netmask option
|
||||
"""
|
||||
if None in [ip['value'], netmask['value']]:
|
||||
if None in [ip["value"], netmask["value"]]:
|
||||
return
|
||||
ip_netmask = ip_interface(f'{ip["value"]}/{netmask["value"]}')
|
||||
if ip_netmask.ip == ip_netmask.network.network_address:
|
||||
msg = _(f'IP "{ip["value"]}" ({ip["name"]}) with this netmask is '
|
||||
'in fact a network address')
|
||||
msg = _('IP "{0}" ({1}) with this netmask is in fact a network address').format(
|
||||
ip["value"], ip["name"]
|
||||
)
|
||||
raise ValueError(msg)
|
||||
if ip_netmask.ip == ip_netmask.network.broadcast_address:
|
||||
msg = _(f'IP "{ip["value"]}" ({ip["name"]}) with this netmask is '
|
||||
'in fact a broacast address')
|
||||
msg = _(
|
||||
'IP "{0}" ({1}) with this netmask is in fact a broadcast address'
|
||||
).format(ip["value"], ip["name"])
|
||||
raise ValueError(msg)
|
||||
|
||||
|
||||
@function_waiting_for_dict
|
||||
def valid_broadcast(network: dict,
|
||||
def valid_broadcast(
|
||||
network: dict,
|
||||
netmask: dict,
|
||||
broadcast: dict,
|
||||
):
|
||||
"""validates if the broadcast is coherent with network and netmask
|
||||
"""
|
||||
if None in [network['value'], netmask['value'], broadcast['value']]:
|
||||
):
|
||||
"""validates if the broadcast is coherent with network and netmask"""
|
||||
if None in [network["value"], netmask["value"], broadcast["value"]]:
|
||||
return
|
||||
if ip_network(f'{network["value"]}/{netmask["value"]}').broadcast_address != \
|
||||
ip_address(broadcast['value']):
|
||||
msg = _(f'broadcast invalid with network {network["value"]} ({network["name"]}) '
|
||||
f'and netmask {netmask["value"]} ({netmask["name"]})')
|
||||
if ip_network(
|
||||
f'{network["value"]}/{netmask["value"]}'
|
||||
).broadcast_address != ip_address(broadcast["value"]):
|
||||
msg = _(
|
||||
"broadcast invalid with network {0} ({1}) and netmask {2} ({3})"
|
||||
).format(network["value"], network["name"], netmask["value"], netmask["name"])
|
||||
raise ValueError(msg)
|
||||
|
||||
|
||||
@function_waiting_for_dict
|
||||
def valid_in_network(ip: dict, # pylint: disable=invalid-name
|
||||
def valid_in_network(
|
||||
ip: dict, # pylint: disable=invalid-name
|
||||
network: dict,
|
||||
netmask=Optional[dict],
|
||||
):
|
||||
):
|
||||
"""validates if an IP is in a network
|
||||
this validator must be set to ip option
|
||||
"""
|
||||
if None in [ip['value'], network['value']]:
|
||||
if None in [ip["value"], network["value"]]:
|
||||
return
|
||||
if '/' in network['value']:
|
||||
if "/" in network["value"]:
|
||||
# it's a CIDR network
|
||||
network_value = network['value']
|
||||
network_value = network["value"]
|
||||
else:
|
||||
if netmask is None or netmask['value'] is None:
|
||||
if netmask is None or netmask["value"] is None:
|
||||
return
|
||||
network_value = f'{network["value"]}/{netmask["value"]}'
|
||||
network_obj = ip_network(network_value)
|
||||
|
@ -123,56 +133,63 @@ def valid_in_network(ip: dict, # pylint: disable=invalid-name
|
|||
if netmask is None:
|
||||
msg = _('this IP is not in network {network["value"]} ({network["name"]})')
|
||||
else:
|
||||
msg = _('this IP is not in network {network["value"]} ({network["name"]}) '
|
||||
'with netmask {netmask["value"]} ({netmask["name"]})')
|
||||
msg = _(
|
||||
'this IP is not in network {network["value"]} ({network["name"]}) '
|
||||
'with netmask {netmask["value"]} ({netmask["name"]})'
|
||||
)
|
||||
raise ValueError(msg)
|
||||
# test if ip is not network/broadcast IP
|
||||
if ip_netmask.ip == ip_netmask.network.network_address:
|
||||
msg = _(f'this IP with the network {network["value"]} ({network["value"]} '
|
||||
'is in fact a network address')
|
||||
msg = _(
|
||||
"this IP with the network {0} ({1}) is in fact a network address"
|
||||
).format(network["value"], network["name"])
|
||||
raise ValueError(msg)
|
||||
if ip_netmask.ip == ip_netmask.network.broadcast_address:
|
||||
msg = _(f'this IP with the network {network["value"]} ({network["value"]} '
|
||||
'is in fact a broadcast address')
|
||||
msg = _(
|
||||
"this IP with the network {0} ({1}) is in fact a broadcast address"
|
||||
).format(network["value"], network["value"])
|
||||
raise ValueError(msg)
|
||||
|
||||
|
||||
@function_waiting_for_dict
|
||||
def valid_not_equal(*values):
|
||||
"""valid that two options have not same value
|
||||
"""
|
||||
"""valid that two options have not same value"""
|
||||
equal = set()
|
||||
for val in values[1:]:
|
||||
if 'propertyerror' in val:
|
||||
if "propertyerror" in val:
|
||||
continue
|
||||
if values[0]['value'] == val['value'] is not None:
|
||||
equal.add(val['name'])
|
||||
if values[0]["value"] == val["value"] is not None:
|
||||
equal.add(val["name"])
|
||||
if not equal:
|
||||
return
|
||||
msg = _(f'value is identical to {display_list(list(equal), add_quote=True)}')
|
||||
msg = _("value is identical to {0}").format(
|
||||
display_list(list(equal), add_quote=True)
|
||||
)
|
||||
raise ValueError(msg)
|
||||
|
||||
|
||||
class CalcValue:
|
||||
"""class to calc_value with different functions
|
||||
"""
|
||||
"""class to calc_value with different functions"""
|
||||
|
||||
# pylint: disable=too-many-instance-attributes
|
||||
def __call__(self,
|
||||
def __call__(
|
||||
self,
|
||||
*args: List[Any],
|
||||
multi: bool=False,
|
||||
default: Any=undefined,
|
||||
condition: Any=undefined,
|
||||
no_condition_is_invalid: bool=False,
|
||||
expected: Any=undefined,
|
||||
condition_operator: str='AND',
|
||||
reverse_condition: bool=False,
|
||||
allow_none: bool=False,
|
||||
remove_duplicate_value: bool=False,
|
||||
join: Optional[str]=None,
|
||||
min_args_len: Optional[int]=None,
|
||||
operator: Optional[str]=None,
|
||||
index: Optional[int]=None,
|
||||
**kwargs) -> Any:
|
||||
multi: bool = False,
|
||||
default: Any = undefined,
|
||||
condition: Any = undefined,
|
||||
no_condition_is_invalid: bool = False,
|
||||
expected: Any = undefined,
|
||||
condition_operator: str = "AND",
|
||||
reverse_condition: bool = False,
|
||||
allow_none: bool = False,
|
||||
remove_duplicate_value: bool = False,
|
||||
join: Optional[str] = None,
|
||||
min_args_len: Optional[int] = None,
|
||||
operator: Optional[str] = None,
|
||||
index: Optional[int] = None,
|
||||
**kwargs,
|
||||
) -> Any:
|
||||
# pylint: disable=too-many-statements,too-many-branches,too-many-nested-blocks,too-many-locals
|
||||
"""calculate value
|
||||
:param args: list of value
|
||||
|
@ -336,8 +353,11 @@ class CalcValue:
|
|||
self.condition_operator = condition_operator
|
||||
self.reverse_condition = reverse_condition
|
||||
self.kwargs = kwargs
|
||||
self.no_condition_is_invalid = no_condition_is_invalid # pylint: disable=attribute-defined-outside-init
|
||||
value = self.get_value(default,
|
||||
self.no_condition_is_invalid = (
|
||||
no_condition_is_invalid # pylint: disable=attribute-defined-outside-init
|
||||
)
|
||||
value = self.get_value(
|
||||
default,
|
||||
min_args_len,
|
||||
)
|
||||
if not multi:
|
||||
|
@ -348,10 +368,11 @@ class CalcValue:
|
|||
value = None
|
||||
elif value and operator:
|
||||
new_value = value[0]
|
||||
oper = {'mul': mul,
|
||||
'add': add,
|
||||
'div': truediv,
|
||||
'sub': sub,
|
||||
oper = {
|
||||
"mul": mul,
|
||||
"add": add,
|
||||
"div": truediv,
|
||||
"sub": sub,
|
||||
}[operator]
|
||||
for val in value[1:]:
|
||||
new_value = oper(new_value, val)
|
||||
|
@ -376,8 +397,9 @@ class CalcValue:
|
|||
break
|
||||
lval = len(val)
|
||||
if length_val is not None and length_val != lval:
|
||||
msg = _('unexpected value in calc_value with join attribute '
|
||||
f'"{val}" with invalid length "{length_val}"')
|
||||
msg = _(
|
||||
'unexpected value in calc_value with join attribute "{0}" with invalid length "{1}"'
|
||||
).format(val, length_val)
|
||||
raise ValueError(msg)
|
||||
length_val = lval
|
||||
new_value = []
|
||||
|
@ -403,19 +425,16 @@ class CalcValue:
|
|||
value = new_value
|
||||
return value
|
||||
|
||||
def value_from_kwargs(self,
|
||||
value: Any,
|
||||
pattern: str,
|
||||
to_dict: bool=False,
|
||||
empty_test=undefined) -> Any:
|
||||
"""get value from kwargs
|
||||
"""
|
||||
def value_from_kwargs(
|
||||
self, value: Any, pattern: str, to_dict: bool = False, empty_test=undefined
|
||||
) -> Any:
|
||||
"""get value from kwargs"""
|
||||
# pylint: disable=too-many-branches
|
||||
# if value attribute exist return it's value
|
||||
# otherwise pattern_0, pattern_1, ...
|
||||
# otherwise undefined
|
||||
if value is not empty_test:
|
||||
if to_dict == 'all':
|
||||
if to_dict == "all":
|
||||
returns = {None: value}
|
||||
else:
|
||||
returns = value
|
||||
|
@ -426,7 +445,7 @@ class CalcValue:
|
|||
if key.startswith(pattern):
|
||||
index = int(key[len_pattern:])
|
||||
if isinstance(pattern_value, dict):
|
||||
pattern_value = pattern_value['value']
|
||||
pattern_value = pattern_value["value"]
|
||||
kwargs_matches[index] = pattern_value
|
||||
if not kwargs_matches:
|
||||
returns = undefined
|
||||
|
@ -443,26 +462,29 @@ class CalcValue:
|
|||
returns.append(kwargs_matches[key])
|
||||
return returns
|
||||
|
||||
def is_condition_matches(self,
|
||||
def is_condition_matches(
|
||||
self,
|
||||
condition_value,
|
||||
):
|
||||
"""verify the condition
|
||||
"""
|
||||
"""verify the condition"""
|
||||
# pylint: disable=too-many-branches
|
||||
calculated_conditions = self.value_from_kwargs(condition_value,
|
||||
'condition_',
|
||||
to_dict='all',
|
||||
calculated_conditions = self.value_from_kwargs(
|
||||
condition_value,
|
||||
"condition_",
|
||||
to_dict="all",
|
||||
)
|
||||
if calculated_conditions is undefined:
|
||||
is_matches = not self.no_condition_is_invalid
|
||||
else:
|
||||
is_matches = None
|
||||
calculated_expected = self.value_from_kwargs(self.expected,
|
||||
'expected_',
|
||||
calculated_expected = self.value_from_kwargs(
|
||||
self.expected,
|
||||
"expected_",
|
||||
to_dict=True,
|
||||
)
|
||||
calculated_reverse = self.value_from_kwargs(self.reverse_condition,
|
||||
'reverse_condition_',
|
||||
calculated_reverse = self.value_from_kwargs(
|
||||
self.reverse_condition,
|
||||
"reverse_condition_",
|
||||
to_dict=True,
|
||||
empty_test=False,
|
||||
)
|
||||
|
@ -470,11 +492,17 @@ class CalcValue:
|
|||
if isinstance(calculated_expected, dict):
|
||||
if idx is not None:
|
||||
if isinstance(calculated_expected[idx], list):
|
||||
current_matches = calculated_condition in calculated_expected[idx]
|
||||
current_matches = (
|
||||
calculated_condition in calculated_expected[idx]
|
||||
)
|
||||
else:
|
||||
current_matches = calculated_condition == calculated_expected[idx]
|
||||
current_matches = (
|
||||
calculated_condition == calculated_expected[idx]
|
||||
)
|
||||
else:
|
||||
current_matches = calculated_condition in calculated_expected.values()
|
||||
current_matches = (
|
||||
calculated_condition in calculated_expected.values()
|
||||
)
|
||||
else:
|
||||
current_matches = calculated_condition == calculated_expected
|
||||
if isinstance(calculated_reverse, dict) and idx in calculated_reverse:
|
||||
|
@ -483,36 +511,41 @@ class CalcValue:
|
|||
reverse_condition = False
|
||||
if is_matches is None:
|
||||
is_matches = current_matches
|
||||
if self.condition_operator == 'AND':
|
||||
if self.condition_operator == "AND":
|
||||
is_matches = is_matches and current_matches
|
||||
if reverse_condition:
|
||||
is_matches = not is_matches
|
||||
if not is_matches:
|
||||
break
|
||||
elif self.condition_operator == 'OR':
|
||||
elif self.condition_operator == "OR":
|
||||
is_matches = is_matches or current_matches
|
||||
if reverse_condition:
|
||||
is_matches = not is_matches
|
||||
if is_matches:
|
||||
break
|
||||
else:
|
||||
msg = _(f'unexpected {self.condition_operator} condition_operator '
|
||||
'in calc_value')
|
||||
msg = _(
|
||||
"unexpected {0} condition_operator " "in calc_value"
|
||||
).format(self.condition_operator)
|
||||
raise ValueError(msg)
|
||||
is_matches = is_matches and not self.reverse_condition \
|
||||
or not is_matches and self.reverse_condition
|
||||
is_matches = (
|
||||
is_matches
|
||||
and not self.reverse_condition
|
||||
or not is_matches
|
||||
and self.reverse_condition
|
||||
)
|
||||
return is_matches
|
||||
|
||||
def get_value(self,
|
||||
def get_value(
|
||||
self,
|
||||
default,
|
||||
min_args_len,
|
||||
):
|
||||
"""get the value from arguments
|
||||
"""
|
||||
"""get the value from arguments"""
|
||||
# retrieve the condition
|
||||
if isinstance(self.condition, dict):
|
||||
if 'value' in self.condition:
|
||||
condition_value = self.condition['value']
|
||||
if "value" in self.condition:
|
||||
condition_value = self.condition["value"]
|
||||
else:
|
||||
condition_value = undefined
|
||||
else:
|
||||
|
@ -527,8 +560,9 @@ class CalcValue:
|
|||
value = []
|
||||
if not value:
|
||||
# default value
|
||||
new_default = self.value_from_kwargs(default,
|
||||
'default_',
|
||||
new_default = self.value_from_kwargs(
|
||||
default,
|
||||
"default_",
|
||||
)
|
||||
if new_default is not undefined:
|
||||
if not isinstance(new_default, list):
|
||||
|
@ -538,34 +572,32 @@ class CalcValue:
|
|||
return value
|
||||
|
||||
def get_args(self):
|
||||
"""get all arguments
|
||||
"""
|
||||
"""get all arguments"""
|
||||
return list(self.args)
|
||||
|
||||
|
||||
class CalcValuePropertyHelp(CalcValue):
|
||||
"""special class to display property error
|
||||
"""
|
||||
"""special class to display property error"""
|
||||
|
||||
def get_name(self):
|
||||
"""get the condition name
|
||||
"""
|
||||
return self.condition['name']
|
||||
"""get the condition name"""
|
||||
return self.condition["name"]
|
||||
|
||||
def get_indexed_name(self, index: int) -> str:
|
||||
"""get name for a specified index
|
||||
"""
|
||||
condition_index = self.kwargs.get(f'condition_{index}')
|
||||
"""get name for a specified index"""
|
||||
condition_index = self.kwargs.get(f"condition_{index}")
|
||||
if condition_index is not None and not isinstance(condition_index, dict):
|
||||
raise ValueError(_(f'unexpected condition_{index} must have "todict" argument'))
|
||||
return condition_index['name']
|
||||
raise ValueError(
|
||||
_('unexpected condition_{0} must have "todict" argument').format(index)
|
||||
)
|
||||
return condition_index["name"]
|
||||
|
||||
|
||||
def build_property_message(self,
|
||||
def build_property_message(
|
||||
self,
|
||||
name: str,
|
||||
value: Any,
|
||||
) -> str:
|
||||
"""prepare message to display error message if needed
|
||||
"""
|
||||
"""prepare message to display error message if needed"""
|
||||
if not self.reverse_condition:
|
||||
msg = _('the value of "{0}" is {1}').format(name, value)
|
||||
else:
|
||||
|
@ -575,21 +607,21 @@ class CalcValuePropertyHelp(CalcValue):
|
|||
def get_args(self):
|
||||
args = super().get_args()
|
||||
action = args[0]
|
||||
calculated_expected = self.value_from_kwargs(self.expected,
|
||||
'expected_',
|
||||
to_dict=True)
|
||||
calculated_expected = self.value_from_kwargs(
|
||||
self.expected, "expected_", to_dict=True
|
||||
)
|
||||
if self.condition is not undefined:
|
||||
if 'propertyerror' in self.condition:
|
||||
msg = self.condition['propertyerror']
|
||||
if "propertyerror" in self.condition:
|
||||
msg = self.condition["propertyerror"]
|
||||
else:
|
||||
name = self.get_name()
|
||||
if isinstance(calculated_expected, dict):
|
||||
calc_values = calculated_expected.values()
|
||||
else:
|
||||
calc_values = [calculated_expected]
|
||||
display_value = display_list([str(val) for val in calc_values],
|
||||
separator='or',
|
||||
add_quote=True)
|
||||
display_value = display_list(
|
||||
[str(val) for val in calc_values], separator="or", add_quote=True
|
||||
)
|
||||
msg = self.build_property_message(name, display_value)
|
||||
else:
|
||||
msgs = []
|
||||
|
@ -601,8 +633,10 @@ class CalcValuePropertyHelp(CalcValue):
|
|||
|
||||
|
||||
calc_value = CalcValue()
|
||||
calc_value.__name__ = 'calc_value' # pylint: disable=attribute-defined-outside-init
|
||||
calc_value.__name__ = "calc_value" # pylint: disable=attribute-defined-outside-init
|
||||
# function_waiting_for_dict(calc_value)
|
||||
calc_value_property_help = CalcValuePropertyHelp()
|
||||
calc_value_property_help.__name__ = 'calc_value_property_help' # pylint: disable=attribute-defined-outside-init
|
||||
calc_value_property_help.__name__ = (
|
||||
"calc_value_property_help" # pylint: disable=attribute-defined-outside-init
|
||||
)
|
||||
function_waiting_for_dict(calc_value_property_help)
|
||||
|
|
|
@ -18,55 +18,9 @@
|
|||
# the rough gus of pypy: pypy: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||
# the whole pypy projet is under MIT licence
|
||||
"internationalisation utilities"
|
||||
from .log import log
|
||||
from gettext import translation
|
||||
from pathlib import Path
|
||||
|
||||
from gettext import translation, NullTranslations
|
||||
from platform import system
|
||||
from pkg_resources import resource_filename
|
||||
from os import environ
|
||||
t = translation('tiramisu', str(Path(__file__).parent / 'locale'), fallback=True)
|
||||
|
||||
|
||||
DEFAULT = 'en'
|
||||
|
||||
|
||||
def get_translation() -> str:
|
||||
"""Sets the user locale as langage
|
||||
The default is set to english
|
||||
"""
|
||||
# Application name (without .i18n)
|
||||
app_name = __name__[:-5]
|
||||
translations_path = resource_filename(app_name, 'locale')
|
||||
|
||||
if 'TIRAMISU_LOCALE' in environ: # pragma: no cover
|
||||
user_locale = environ['TIRAMISU_LOCALE']
|
||||
else:
|
||||
if 'Windows' in system(): # pragma: no cover
|
||||
import ctypes
|
||||
from locale import windows_locale
|
||||
default_locale = windows_locale[ctypes.windll.kernel32.GetUserDefaultUILanguage()]
|
||||
else:
|
||||
from locale import getlocale
|
||||
default_locale = getlocale()
|
||||
if default_locale and isinstance(default_locale, tuple):
|
||||
if default_locale[0] is not None:
|
||||
user_locale = default_locale[0][:2]
|
||||
else:
|
||||
user_locale = DEFAULT
|
||||
elif default_locale: # pragma: no cover
|
||||
user_locale = default_locale[:2]
|
||||
else: # pragma: no cover
|
||||
user_locale = DEFAULT
|
||||
try:
|
||||
trans = translation(domain=app_name,
|
||||
localedir=translations_path,
|
||||
languages=[user_locale],
|
||||
)
|
||||
# codeset='UTF-8')
|
||||
except FileNotFoundError: # pragma: no cover
|
||||
log.debug('cannot found translation file for langage {} in localedir {}'.format(user_locale,
|
||||
translations_path))
|
||||
trans = NullTranslations()
|
||||
return trans.gettext
|
||||
|
||||
|
||||
_ = get_translation()
|
||||
_ = t.gettext
|
||||
|
|
BIN
tiramisu/locale/fr/LC_MESSAGES/tiramisu.mo
Normal file
BIN
tiramisu/locale/fr/LC_MESSAGES/tiramisu.mo
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load diff
|
@ -1,711 +0,0 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR ORGANIZATION
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"POT-Creation-Date: 2023-11-19 21:26+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"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
|
||||
#: tiramisu/api.py:61
|
||||
msgid "Settings:"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:63
|
||||
msgid "Access to option without verifying permissive properties"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:67
|
||||
msgid "Access to option without property restriction"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:70
|
||||
msgid "Do not warnings during validation"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:75
|
||||
msgid "Call: {}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:77
|
||||
msgid "Commands:"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:185
|
||||
msgid "unknown list type {}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:187
|
||||
msgid "unknown group_type: {0}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:352
|
||||
msgid "only multi value has defaultmulti"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:371 tiramisu/option/intoption.py:31
|
||||
msgid "integer"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:374 tiramisu/option/domainnameoption.py:43
|
||||
msgid "domain name"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:376
|
||||
msgid "ip"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:376
|
||||
msgid "netmask"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:376
|
||||
msgid "network"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:471
|
||||
msgid "cannot add this property: \"{0}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:621
|
||||
msgid "cannot reduce length of the leader \"{}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:1088
|
||||
msgid "properties must be a frozenset"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:1094 tiramisu/api.py:1118
|
||||
msgid "unknown when {} (must be in append or remove)"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:1106 tiramisu/api.py:1127 tiramisu/config.py:1210
|
||||
msgid "unknown type {}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:1432
|
||||
msgid "do not use unrestraint, nowarnings or forcepermissive together"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/autolib.py:44
|
||||
msgid "args in params must be a tuple"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/autolib.py:47 tiramisu/autolib.py:52
|
||||
msgid "arg in params must be a Param"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/autolib.py:49
|
||||
msgid "kwargs in params must be a dict"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/autolib.py:72
|
||||
msgid "paramoption needs an option not {}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/autolib.py:77
|
||||
msgid "param must have a boolean not a {} for notraisepropertyerror"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/autolib.py:78
|
||||
msgid "param must have a boolean not a {} for raisepropertyerror"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/autolib.py:133
|
||||
msgid "option in ParamInformation cannot be a symlinkoption"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/autolib.py:135
|
||||
msgid "option in ParamInformation cannot be a follower"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/autolib.py:137
|
||||
msgid "option in ParamInformation cannot be a dynamic option"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/autolib.py:166
|
||||
msgid "first argument ({0}) must be a function"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/autolib.py:168
|
||||
msgid "help_function ({0}) must be a function"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/autolib.py:316 tiramisu/autolib.py:362
|
||||
msgid "unable to carry out a calculation for \"{}\", {}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/autolib.py:319 tiramisu/autolib.py:365
|
||||
msgid "the option \"{0}\" is used in a calculation but is invalid ({1})"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/autolib.py:402
|
||||
msgid "option \"{}\" cannot be calculated: {}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/autolib.py:411
|
||||
msgid "option \"{}\" is not in a dynoptiondescription"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/autolib.py:562
|
||||
msgid "the \"{}\" function with positional arguments \"{}\" and keyword arguments \"{}\" must not return a list (\"{}\") for the follower option \"{}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/autolib.py:571
|
||||
msgid "the \"{}\" function must not return a list (\"{}\") for the follower option \"{}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/autolib.py:604
|
||||
msgid "unexpected error \"{0}\" in function \"{1}\" with arguments \"{3}\" and \"{4}\" for option \"{2}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/autolib.py:611
|
||||
msgid "unexpected error \"{0}\" in function \"{1}\" for option \"{2}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/config.py:82
|
||||
msgid "there is no option description for this config (may be GroupConfig)"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/config.py:269
|
||||
msgid "no option found in config with these criteria"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/config.py:532 tiramisu/option/optiondescription.py:72
|
||||
msgid "option description seems to be part of an other config"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/config.py:790
|
||||
msgid "cannot set leadership object has root optiondescription"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/config.py:792
|
||||
msgid "cannot set dynoptiondescription object has root optiondescription"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/config.py:840
|
||||
msgid "config name must be uniq in groupconfig for \"{0}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/config.py:1024
|
||||
msgid "unknown config \"{}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/config.py:1047
|
||||
msgid "child must be a Config, MixConfig or MetaConfig"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/config.py:1079
|
||||
msgid "force_default, force_default_if_same or force_dont_change_value cannot be set with only_config"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/config.py:1085
|
||||
msgid "force_default and force_dont_change_value cannot be set together"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/config.py:1208
|
||||
msgid "config name must be uniq in groupconfig for {0}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/config.py:1246
|
||||
msgid "config added has no name, the name is mandatory"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/config.py:1248
|
||||
msgid "config name \"{0}\" is not uniq in groupconfig \"{1}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/config.py:1270
|
||||
msgid "cannot find the config {}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/config.py:1294
|
||||
msgid "MetaConfig with optiondescription must have string has child, not {}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/config.py:1303
|
||||
msgid "child must be a Config or MetaConfig"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/config.py:1307
|
||||
msgid "all config in metaconfig must have the same optiondescription"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/config.py:1319
|
||||
msgid "metaconfig must have the same optiondescription"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/error.py:26
|
||||
msgid "and"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/error.py:28
|
||||
msgid "or"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/error.py:50
|
||||
msgid " {} "
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/error.py:98
|
||||
msgid "property"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/error.py:100
|
||||
msgid "properties"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/error.py:187
|
||||
msgid "invalid value"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/error.py:192
|
||||
msgid "attention, \"{0}\" could be an invalid {1} for \"{2}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/error.py:208 tiramisu/error.py:212
|
||||
msgid "\"{0}\" is an invalid {1} for \"{2}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/function.py:113
|
||||
msgid "this IP is not in network {network[\"value\"]} ({network[\"name\"]})"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/function.py:115
|
||||
msgid "this IP is not in network {network[\"value\"]} ({network[\"name\"]}) with netmask {netmask[\"value\"]} ({netmask[\"name\"]})"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/function.py:559
|
||||
msgid "the value of \"{0}\" is {1}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/function.py:561
|
||||
msgid "the value of \"{0}\" is not {1}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/baseoption.py:70 tiramisu/option/symlinkoption.py:40
|
||||
msgid "\"{0}\" is an invalid name for an option"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/baseoption.py:83
|
||||
msgid "invalid properties type {0} for {1}, must be a frozenset"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/baseoption.py:89
|
||||
msgid "invalid property type {0} for {1}, must be a string or a Calculation"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/baseoption.py:227
|
||||
msgid "'{0}' ({1}) object attribute '{2}' is read-only"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/baseoption.py:265
|
||||
msgid "\"{}\" ({}) object attribute \"{}\" is read-only"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/booloption.py:32
|
||||
msgid "boolean"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/broadcastoption.py:33
|
||||
msgid "broadcast address"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/broadcastoption.py:41
|
||||
msgid "invalid string"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/choiceoption.py:38
|
||||
msgid "choice"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/choiceoption.py:51
|
||||
msgid "values must be a tuple or a calculation for {0}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/choiceoption.py:67
|
||||
msgid "the calculated values \"{0}\" for \"{1}\" is not a list"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/choiceoption.py:97
|
||||
msgid "only \"{0}\" is allowed"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/choiceoption.py:99
|
||||
msgid "only {0} are allowed"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/dateoption.py:33
|
||||
msgid "date"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/domainnameoption.py:62
|
||||
msgid "unknown type {0} for hostname"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/domainnameoption.py:65
|
||||
msgid "allow_ip must be a boolean"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/domainnameoption.py:67
|
||||
msgid "allow_cidr_network must be a boolean"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/domainnameoption.py:69
|
||||
msgid "allow_without_dot must be a boolean"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/domainnameoption.py:71
|
||||
msgid "allow_startswith_dot must be a boolean"
|
||||
msgstr ""
|
||||
|
||||
#: 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:82
|
||||
msgid "must start with lowercase characters followed by lowercase characters, number, \"-\" and \".\" characters are recommanded"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/domainnameoption.py:84
|
||||
#: tiramisu/option/domainnameoption.py:85
|
||||
msgid "could be a IP, otherwise {}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/domainnameoption.py:125
|
||||
msgid "invalid length (min 1)"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/domainnameoption.py:127
|
||||
msgid "invalid length (max {0})"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/domainnameoption.py:133
|
||||
msgid "must have dot"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/domainnameoption.py:135
|
||||
msgid "invalid length (max 255)"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/domainnameoption.py:154
|
||||
msgid "must not be an IP"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/domainnameoption.py:180
|
||||
msgid "some characters are uppercase"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/dynoptiondescription.py:65
|
||||
msgid "identifiers in dynoptiondescription has to be a calculation"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/dynoptiondescription.py:109
|
||||
msgid "invalid identifier \"{}\" for option \"{}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/emailoption.py:34
|
||||
msgid "email address"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/filenameoption.py:31
|
||||
msgid "file name"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/filenameoption.py:38
|
||||
msgid "must starts with \"/\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/floatoption.py:32
|
||||
msgid "float"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/ipoption.py:33
|
||||
msgid "IP"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/ipoption.py:57
|
||||
msgid "it's in fact a network address"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/ipoption.py:59
|
||||
msgid "it's in fact a broacast address"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/ipoption.py:72
|
||||
msgid "CIDR address must have a \"/\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/ipoption.py:83
|
||||
msgid "shouldn't be reserved IP"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/ipoption.py:85
|
||||
msgid "mustn't be reserved IP"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/ipoption.py:89
|
||||
msgid "should be private IP"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/ipoption.py:91
|
||||
msgid "must be private IP"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/leadership.py:56
|
||||
msgid "a leader and a follower are mandatories in leadership \"{}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/leadership.py:73
|
||||
msgid "leader cannot have \"{}\" property"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/leadership.py:77
|
||||
msgid "leadership \"{0}\" shall not have a symlinkoption"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/leadership.py:80
|
||||
msgid "leadership \"{0}\" shall not have a subgroup"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/leadership.py:83
|
||||
msgid "only multi option allowed in leadership \"{0}\" but option \"{1}\" is not a multi"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/macoption.py:34
|
||||
msgid "mac address"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/netmaskoption.py:32
|
||||
msgid "netmask address"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/networkoption.py:32
|
||||
msgid "network address"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/networkoption.py:51
|
||||
msgid "must use CIDR notation"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/networkoption.py:68
|
||||
msgid "shouldn't be reserved network"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/networkoption.py:70
|
||||
msgid "mustn't be reserved network"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/option.py:69
|
||||
msgid "default_multi is set whereas multi is False in option: {0}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/option.py:86
|
||||
msgid "invalid multi type \"{}\" for \"{}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/option.py:102
|
||||
msgid "validators must be a Calculation for \"{}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/option.py:127
|
||||
msgid "invalid default_multi value \"{0}\" for option \"{1}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/option.py:137
|
||||
msgid "invalid default_multi value \"{0}\" for option \"{1}\", must be a list for a submulti"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/option.py:291
|
||||
msgid "the value \"{}\" is not unique"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/option.py:331
|
||||
msgid "which must not be a list"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/option.py:373 tiramisu/option/option.py:399
|
||||
msgid "which must be a list"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/option.py:392
|
||||
msgid "which \"{}\" must be a list of list"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/optiondescription.py:109
|
||||
msgid "duplicate option: {0}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/optiondescription.py:306
|
||||
msgid "children in optiondescription \"{}\" must be a list"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/optiondescription.py:329
|
||||
msgid "duplicate option name: \"{0}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/optiondescription.py:374
|
||||
msgid "cannot change group_type if already set (old {0}, new {1})"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/optiondescription.py:378
|
||||
msgid "group_type: {0} not allowed"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/passwordoption.py:32
|
||||
msgid "password"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/permissionsoption.py:38
|
||||
msgid "unix file permissions"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/permissionsoption.py:52
|
||||
msgid "only 3 or 4 octal digits are allowed"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/permissionsoption.py:65
|
||||
msgid "user"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/permissionsoption.py:66
|
||||
#: tiramisu/option/permissionsoption.py:68
|
||||
msgid "group"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/permissionsoption.py:69
|
||||
msgid "other"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/permissionsoption.py:73
|
||||
msgid "too weak"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/portoption.py:41
|
||||
msgid "port"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/portoption.py:71
|
||||
msgid "inconsistency in allowed range"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/portoption.py:76
|
||||
msgid "max value is empty"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/portoption.py:91
|
||||
msgid "range must have two values only"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/portoption.py:93
|
||||
msgid "first port in range must be smaller than the second one"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/stroption.py:33
|
||||
msgid "string"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/symlinkoption.py:44
|
||||
msgid "malformed symlinkoption must be an option for symlink {0}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/symlinkoption.py:60
|
||||
msgid "cannot set symlinkoption in a dynoptiondescription"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/urloption.py:39
|
||||
msgid "URL"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/urloption.py:91
|
||||
msgid "must start with http:// or https://"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/urloption.py:122
|
||||
msgid "must ends with a valid resource name"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/usernameoption.py:35
|
||||
msgid "unix username"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/usernameoption.py:42
|
||||
msgid "unix groupname"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/setting.py:302
|
||||
msgid "can't rebind {0}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/setting.py:308
|
||||
msgid "can't unbind {0}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/setting.py:515
|
||||
msgid "invalid property type {type(new_prop)} for {option_bag.option.impl_getname()} with {prop.function.__name__} function"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/setting.py:521
|
||||
msgid "leader cannot have \"{new_prop}\" property"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/setting.py:591
|
||||
msgid "leader cannot have \"{list(not_allowed_properties)}\" property"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/setting.py:595
|
||||
msgid "a leader ({opt.impl_get_display_name()}) cannot have \"force_default_on_freeze\" or \"force_metaconfig_on_freeze\" property without \"frozen\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/setting.py:626
|
||||
msgid "permissive must be a frozenset"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/setting.py:635
|
||||
msgid "cannot add those permissives: {0}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/todict.py:352
|
||||
msgid "option {} only works when remotable is not \"none\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/todict.py:505
|
||||
msgid "unable to transform tiramisu object to dict: {}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/todict.py:816 tiramisu/todict.py:955
|
||||
msgid "unknown form {}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/todict.py:862
|
||||
msgid "not in current area"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/todict.py:883
|
||||
msgid "only multi option can have action \"add\", but \"{}\" is not a multi"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/todict.py:885
|
||||
msgid "unknown action {}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/value.py:506 tiramisu/value.py:722
|
||||
msgid "set owner \"{0}\" is forbidden"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/value.py:636
|
||||
msgid "index {index} is greater than the length {length} for option {option_bag.option.impl_get_display_name(with_quote=True)}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/value.py:695
|
||||
msgid "information's item not found: {0}"
|
||||
msgstr ""
|
||||
|
|
@ -19,12 +19,12 @@ from logging import getLogger, DEBUG, StreamHandler, Formatter
|
|||
import os
|
||||
|
||||
|
||||
log = getLogger('tiramisu')
|
||||
if os.environ.get('TIRAMISU_DEBUG') == 'True': # pragma: no cover
|
||||
log = getLogger("tiramisu")
|
||||
if os.environ.get("TIRAMISU_DEBUG") == "True": # pragma: no cover
|
||||
log.setLevel(DEBUG)
|
||||
handler = StreamHandler()
|
||||
handler.setLevel(DEBUG)
|
||||
formatter = Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||
formatter = Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
|
||||
handler.setFormatter(formatter)
|
||||
|
||||
log.addHandler(handler)
|
||||
|
|
|
@ -25,7 +25,8 @@ from .dynoptiondescription import DynOptionDescription
|
|||
from .leadership import Leadership
|
||||
from .baseoption import submulti
|
||||
from .symlinkoption import SymLinkOption
|
||||
#from .syndynoption import SynDynOption, SynDynOptionDescription, SynDynLeadership
|
||||
|
||||
# from .syndynoption import SynDynOption, SynDynOptionDescription, SynDynLeadership
|
||||
from .option import Option
|
||||
from .choiceoption import ChoiceOption
|
||||
from .booloption import BoolOption
|
||||
|
@ -48,12 +49,33 @@ from .macoption import MACOption
|
|||
from .permissionsoption import PermissionsOption
|
||||
|
||||
|
||||
__all__ = ('Leadership', 'OptionDescription', 'DynOptionDescription',
|
||||
# 'SynDynOptionDescription', 'SynDynLeadership','SynDynOption',
|
||||
'Option', 'SymLinkOption',
|
||||
'ChoiceOption', 'BoolOption', 'DateOption',
|
||||
'IntOption', 'FloatOption', 'StrOption',
|
||||
'IPOption', 'PortOption', 'NetworkOption', 'NetmaskOption',
|
||||
'BroadcastOption', 'DomainnameOption', 'EmailOption', 'URLOption',
|
||||
'UsernameOption', 'GroupnameOption', 'FilenameOption', 'PasswordOption', 'submulti',
|
||||
'RegexpOption', 'MACOption', 'PermissionsOption')
|
||||
__all__ = (
|
||||
"Leadership",
|
||||
"OptionDescription",
|
||||
"DynOptionDescription",
|
||||
# 'SynDynOptionDescription', 'SynDynLeadership','SynDynOption',
|
||||
"Option",
|
||||
"SymLinkOption",
|
||||
"ChoiceOption",
|
||||
"BoolOption",
|
||||
"DateOption",
|
||||
"IntOption",
|
||||
"FloatOption",
|
||||
"StrOption",
|
||||
"IPOption",
|
||||
"PortOption",
|
||||
"NetworkOption",
|
||||
"NetmaskOption",
|
||||
"BroadcastOption",
|
||||
"DomainnameOption",
|
||||
"EmailOption",
|
||||
"URLOption",
|
||||
"UsernameOption",
|
||||
"GroupnameOption",
|
||||
"FilenameOption",
|
||||
"PasswordOption",
|
||||
"submulti",
|
||||
"RegexpOption",
|
||||
"MACOption",
|
||||
"PermissionsOption",
|
||||
)
|
||||
|
|
|
@ -36,39 +36,40 @@ submulti = 2
|
|||
|
||||
|
||||
def valid_name(name):
|
||||
"""valid option name
|
||||
"""
|
||||
"""valid option name"""
|
||||
if not isinstance(name, str):
|
||||
return False
|
||||
if '.' in name:
|
||||
if "." in name:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
#____________________________________________________________
|
||||
# ____________________________________________________________
|
||||
#
|
||||
class Base:
|
||||
"""Base use by all *Option* classes (Option, OptionDescription, SymLinkOption, ...)
|
||||
"""
|
||||
__slots__ = ('_name',
|
||||
'_path',
|
||||
'_informations',
|
||||
'_subdyns',
|
||||
'_properties',
|
||||
'_has_dependency',
|
||||
'_dependencies',
|
||||
'_dependencies_information',
|
||||
'_identifiers_dependencies',
|
||||
'__weakref__'
|
||||
"""Base use by all *Option* classes (Option, OptionDescription, SymLinkOption, ...)"""
|
||||
|
||||
__slots__ = (
|
||||
"_name",
|
||||
"_path",
|
||||
"_informations",
|
||||
"_subdyns",
|
||||
"_properties",
|
||||
"_has_dependency",
|
||||
"_dependencies",
|
||||
"_dependencies_information",
|
||||
"_identifiers_dependencies",
|
||||
"__weakref__",
|
||||
)
|
||||
|
||||
def __init__(self,
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
doc: str,
|
||||
informations: Optional[Dict],
|
||||
*,
|
||||
properties=None,
|
||||
is_multi: bool=False,
|
||||
is_multi: bool = False,
|
||||
) -> None:
|
||||
if not valid_name(name):
|
||||
raise ValueError(_('"{0}" is an invalid name for an option').format(name))
|
||||
|
@ -80,88 +81,99 @@ class Base:
|
|||
# if option is a multi, it cannot be 'empty' (None not allowed in the list)
|
||||
# and cannot have multiple time the same value
|
||||
# 'empty' and 'unique' are removed for follower's option
|
||||
if 'notunique' not in properties:
|
||||
properties = properties | {'unique'}
|
||||
if 'notempty' not in properties:
|
||||
properties = properties | {'empty'}
|
||||
assert isinstance(properties, frozenset), _('invalid properties type {0} for {1},'
|
||||
' must be a frozenset').format(type(properties),
|
||||
name)
|
||||
if "notunique" not in properties:
|
||||
properties = properties | {"unique"}
|
||||
if "notempty" not in properties:
|
||||
properties = properties | {"empty"}
|
||||
assert isinstance(properties, frozenset), _(
|
||||
"invalid properties type {0} for {1}," " must be a frozenset"
|
||||
).format(type(properties), name)
|
||||
_setattr = object.__setattr__
|
||||
_setattr(self, '_name', name)
|
||||
_setattr(self, '_informations', {'doc': doc})
|
||||
_setattr(self, "_name", name)
|
||||
_setattr(self, "_informations", {"doc": doc})
|
||||
for prop in properties:
|
||||
if not isinstance(prop, str):
|
||||
if not isinstance(prop, Calculation):
|
||||
raise ValueError(_('invalid property type {0} for {1}, must be a string or a '
|
||||
'Calculation').format(type(prop), name))
|
||||
raise ValueError(
|
||||
_(
|
||||
"invalid property type {0} for {1}, must be a string or a "
|
||||
"Calculation"
|
||||
).format(type(prop), name)
|
||||
)
|
||||
for param in chain(prop.params.args, prop.params.kwargs.values()):
|
||||
if isinstance(param, ParamOption):
|
||||
param.option._add_dependency(self)
|
||||
if properties:
|
||||
_setattr(self, '_properties', properties)
|
||||
_setattr(self, "_properties", properties)
|
||||
self.set_informations(informations)
|
||||
|
||||
def set_informations(self,
|
||||
def set_informations(
|
||||
self,
|
||||
informations: Optional[Dict],
|
||||
) -> None:
|
||||
if not informations:
|
||||
return
|
||||
for key, value in informations.items():
|
||||
self._set_information(key,
|
||||
self._set_information(
|
||||
key,
|
||||
value,
|
||||
)
|
||||
|
||||
def impl_has_dependency(self,
|
||||
self_is_dep: bool=True,
|
||||
def impl_has_dependency(
|
||||
self,
|
||||
self_is_dep: bool = True,
|
||||
) -> bool:
|
||||
"""this has dependency
|
||||
"""
|
||||
"""this has dependency"""
|
||||
if self_is_dep is True:
|
||||
return getattr(self, '_has_dependency', False)
|
||||
return hasattr(self, '_dependencies')
|
||||
return getattr(self, "_has_dependency", False)
|
||||
return hasattr(self, "_dependencies")
|
||||
|
||||
def get_dependencies(self,
|
||||
def get_dependencies(
|
||||
self,
|
||||
context_od,
|
||||
) -> Set[str]:
|
||||
ret = set(getattr(self, '_dependencies', STATIC_TUPLE))
|
||||
if context_od and hasattr(context_od, '_dependencies'):
|
||||
ret = set(getattr(self, "_dependencies", STATIC_TUPLE))
|
||||
if context_od and hasattr(context_od, "_dependencies"):
|
||||
# add options that have context is set in calculation
|
||||
return set(context_od._dependencies) | ret # pylint: disable=protected-access
|
||||
return (
|
||||
set(context_od._dependencies) | ret
|
||||
) # pylint: disable=protected-access
|
||||
return ret
|
||||
|
||||
def _get_identifiers_dependencies(self) -> Set[str]:
|
||||
return getattr(self, '_identifiers_dependencies', STATIC_TUPLE)
|
||||
return getattr(self, "_identifiers_dependencies", STATIC_TUPLE)
|
||||
|
||||
def _add_dependency(self,
|
||||
def _add_dependency(
|
||||
self,
|
||||
option,
|
||||
is_identifier: bool=False,
|
||||
is_identifier: bool = False,
|
||||
) -> None:
|
||||
woption = weakref.ref(option)
|
||||
options = self.get_dependencies(None)
|
||||
options.add(woption)
|
||||
self._dependencies = tuple(options) # pylint: disable=attribute-defined-outside-init
|
||||
self._dependencies = tuple(
|
||||
options
|
||||
) # pylint: disable=attribute-defined-outside-init
|
||||
if is_identifier:
|
||||
options = list(self._get_identifiers_dependencies())
|
||||
options.append(woption)
|
||||
self._identifiers_dependencies = tuple(options) # pylint: disable=attribute-defined-outside-init
|
||||
self._identifiers_dependencies = tuple(
|
||||
options
|
||||
) # pylint: disable=attribute-defined-outside-init
|
||||
|
||||
def impl_is_optiondescription(self) -> bool:
|
||||
"""option is an option description
|
||||
"""
|
||||
"""option is an option description"""
|
||||
return False
|
||||
|
||||
def impl_is_dynoptiondescription(self) -> bool:
|
||||
"""option is not a dyn option description
|
||||
"""
|
||||
"""option is not a dyn option description"""
|
||||
return False
|
||||
|
||||
def impl_is_sub_dyn_optiondescription(self):
|
||||
return False
|
||||
|
||||
def impl_getname(self) -> str:
|
||||
"""get name
|
||||
"""
|
||||
"""get name"""
|
||||
return self._name # pylint: disable=no-member
|
||||
|
||||
def _set_readonly(self) -> None:
|
||||
|
@ -170,40 +182,39 @@ class Base:
|
|||
dico = self._informations # pylint: disable=no-member
|
||||
keys = tuple(dico.keys())
|
||||
if len(keys) == 1:
|
||||
dico = dico['doc']
|
||||
dico = dico["doc"]
|
||||
else:
|
||||
dico = tuple([keys, tuple(dico.values())])
|
||||
_setattr(self, '_informations', dico)
|
||||
extra = getattr(self, '_extra', None)
|
||||
_setattr(self, "_informations", dico)
|
||||
extra = getattr(self, "_extra", None)
|
||||
if extra is not None:
|
||||
_setattr(self, '_extra', tuple([tuple(extra.keys()), tuple(extra.values())]))
|
||||
_setattr(
|
||||
self, "_extra", tuple([tuple(extra.keys()), tuple(extra.values())])
|
||||
)
|
||||
|
||||
def impl_is_readonly(self) -> str:
|
||||
"""the option is readonly
|
||||
"""
|
||||
return hasattr(self, '_path')
|
||||
"""the option is readonly"""
|
||||
return hasattr(self, "_path")
|
||||
|
||||
def impl_getproperties(self) -> FrozenSet[str]:
|
||||
"""get properties
|
||||
"""
|
||||
return getattr(self, '_properties', frozenset())
|
||||
"""get properties"""
|
||||
return getattr(self, "_properties", frozenset())
|
||||
|
||||
def _setsubdyn(self,
|
||||
def _setsubdyn(
|
||||
self,
|
||||
subdyn,
|
||||
) -> None:
|
||||
# pylint: disable=attribute-defined-outside-init
|
||||
if getattr(self, '_subdyns', None) is None:
|
||||
if getattr(self, "_subdyns", None) is None:
|
||||
self._subdyns = []
|
||||
self._subdyns.append(subdyn)
|
||||
|
||||
def issubdyn(self) -> bool:
|
||||
"""is sub dynoption
|
||||
"""
|
||||
return getattr(self, '_subdyns', None) is not None
|
||||
"""is sub dynoption"""
|
||||
return getattr(self, "_subdyns", None) is not None
|
||||
|
||||
def getsubdyn(self):
|
||||
"""get sub dynoption
|
||||
"""
|
||||
"""get sub dynoption"""
|
||||
return self._subdyns[0]()
|
||||
|
||||
def get_sub_dyns(self):
|
||||
|
@ -211,10 +222,11 @@ class Base:
|
|||
|
||||
# ____________________________________________________________
|
||||
# information
|
||||
def _get_information(self,
|
||||
def _get_information(
|
||||
self,
|
||||
subconfig: "SubConfig",
|
||||
key: str,
|
||||
default: Any=undefined,
|
||||
default: Any = undefined,
|
||||
) -> Any:
|
||||
"""retrieves one information's item
|
||||
|
||||
|
@ -225,7 +237,7 @@ class Base:
|
|||
if key in dico[0]:
|
||||
return dico[1][dico[0].index(key)]
|
||||
elif isinstance(dico, str):
|
||||
if key == 'doc':
|
||||
if key == "doc":
|
||||
return dico
|
||||
elif isinstance(dico, dict):
|
||||
if key in dico:
|
||||
|
@ -233,10 +245,14 @@ class Base:
|
|||
if default is not undefined:
|
||||
return default
|
||||
# pylint: disable=no-member
|
||||
raise ValueError(_(f'information\'s item for {self.impl_get_display_name(subconfig, with_quote=True)} '
|
||||
f'not found: "{key}"'))
|
||||
raise ValueError(
|
||||
_('information\'s item for {0} not found: "{1}"').format(
|
||||
self.impl_get_display_name(subconfig, with_quote=True), key
|
||||
)
|
||||
)
|
||||
|
||||
def _set_information(self,
|
||||
def _set_information(
|
||||
self,
|
||||
key: str,
|
||||
value: Any,
|
||||
) -> None:
|
||||
|
@ -247,20 +263,20 @@ class Base:
|
|||
:param value: information's value (ex: "the help string")
|
||||
"""
|
||||
if self.impl_is_readonly():
|
||||
raise AttributeError(_("'{0}' ({1}) object attribute '{2}' is"
|
||||
" read-only").format(self.__class__.__name__,
|
||||
self,
|
||||
key))
|
||||
raise AttributeError(
|
||||
_("'{0}' ({1}) object attribute '{2}' is" " read-only").format(
|
||||
self.__class__.__name__, self, key
|
||||
)
|
||||
)
|
||||
self._informations[key] = value # pylint: disable=no-member
|
||||
|
||||
def _list_information(self) -> Any:
|
||||
"""get the list of information keys
|
||||
"""
|
||||
"""get the list of information keys"""
|
||||
dico = self._informations # pylint: disable=no-member
|
||||
if isinstance(dico, tuple):
|
||||
return list(dico[0])
|
||||
if not isinstance(dico, dict):
|
||||
return ['doc']
|
||||
return ["doc"]
|
||||
# it's a dict
|
||||
return list(dico.keys())
|
||||
|
||||
|
@ -270,9 +286,11 @@ class BaseOption(Base):
|
|||
in options that have to be set only once, it is of course done in the
|
||||
__setattr__ method
|
||||
"""
|
||||
__slots__ = ('_display_name_function',)
|
||||
|
||||
def __setattr__(self,
|
||||
__slots__ = ("_display_name_function",)
|
||||
|
||||
def __setattr__(
|
||||
self,
|
||||
name: str,
|
||||
value: Any,
|
||||
) -> Any:
|
||||
|
@ -286,72 +304,78 @@ class BaseOption(Base):
|
|||
"""
|
||||
# never change _name in an option or attribute when object is readonly
|
||||
if self.impl_is_readonly():
|
||||
raise AttributeError(_('"{}" ({}) object attribute "{}" is'
|
||||
' read-only').format(self.__class__.__name__,
|
||||
self.impl_get_display_name(None),
|
||||
name))
|
||||
raise AttributeError(
|
||||
_('"{}" ({}) object attribute "{}" is' " read-only").format(
|
||||
self.__class__.__name__, self.impl_get_display_name(None), name
|
||||
)
|
||||
)
|
||||
super().__setattr__(name, value)
|
||||
|
||||
def impl_getpath(self) -> str:
|
||||
"""get the path of the option
|
||||
"""
|
||||
"""get the path of the option"""
|
||||
try:
|
||||
return self._path
|
||||
except AttributeError as err:
|
||||
raise AttributeError(_(f'{self.impl_get_display_name(None, with_quote=True)} not part of any Config')) \
|
||||
from err
|
||||
raise AttributeError(
|
||||
_("{0} not part of any Config").format(
|
||||
self.impl_get_display_name(None, with_quote=True)
|
||||
)
|
||||
) from err
|
||||
|
||||
def impl_get_display_name(self,
|
||||
def impl_get_display_name(
|
||||
self,
|
||||
subconfig: "SubConfig",
|
||||
*,
|
||||
with_quote: bool=False,
|
||||
with_quote: bool = False,
|
||||
) -> str:
|
||||
"""get display name
|
||||
"""
|
||||
if hasattr(self, '_display_name_function'):
|
||||
return self._display_name_function(self,
|
||||
"""get display name"""
|
||||
if hasattr(self, "_display_name_function"):
|
||||
return self._display_name_function(
|
||||
self,
|
||||
subconfig,
|
||||
with_quote=with_quote,
|
||||
)
|
||||
name = self._get_information(subconfig, 'doc', None)
|
||||
if name is None or name == '':
|
||||
name = self._get_information(subconfig, "doc", None)
|
||||
if name is None or name == "":
|
||||
if subconfig and subconfig.path:
|
||||
name = subconfig.path.rsplit('.', 1)[-1]
|
||||
name = subconfig.path.rsplit(".", 1)[-1]
|
||||
else:
|
||||
name = self._name
|
||||
if with_quote:
|
||||
return f'"{name}"'
|
||||
return name
|
||||
|
||||
def reset_cache(self,
|
||||
def reset_cache(
|
||||
self,
|
||||
path: str,
|
||||
config_bag: 'OptionBag',
|
||||
config_bag: "OptionBag",
|
||||
resetted_opts: List[Base], # pylint: disable=unused-argument
|
||||
) -> None:
|
||||
"""reset cache
|
||||
"""
|
||||
"""reset cache"""
|
||||
context = config_bag.context
|
||||
context.properties_cache.delcache(path)
|
||||
context._impl_permissives_cache.delcache(path) # pylint: disable=protected-access
|
||||
context._impl_permissives_cache.delcache(
|
||||
path
|
||||
) # pylint: disable=protected-access
|
||||
if not self.impl_is_optiondescription():
|
||||
context.get_values_cache().delcache(path) # pylint: disable=protected-access
|
||||
context.get_values_cache().delcache(
|
||||
path
|
||||
) # pylint: disable=protected-access
|
||||
|
||||
def impl_is_symlinkoption(self) -> bool:
|
||||
"""the option is not a symlinkoption
|
||||
"""
|
||||
"""the option is not a symlinkoption"""
|
||||
return False
|
||||
|
||||
def get_dependencies_information(self) -> List[str]:
|
||||
"""get dependencies information
|
||||
"""
|
||||
return getattr(self, '_dependencies_information', {})
|
||||
"""get dependencies information"""
|
||||
return getattr(self, "_dependencies_information", {})
|
||||
|
||||
def value_dependencies(self,
|
||||
def value_dependencies(
|
||||
self,
|
||||
value: Any,
|
||||
is_identifier: bool=False,
|
||||
is_identifier: bool = False,
|
||||
) -> Any:
|
||||
"""parse dependancies to add dependencies
|
||||
"""
|
||||
"""parse dependancies to add dependencies"""
|
||||
if isinstance(value, list):
|
||||
for val in value:
|
||||
if isinstance(value, list):
|
||||
|
@ -361,12 +385,12 @@ class BaseOption(Base):
|
|||
elif isinstance(value, Calculation):
|
||||
self.value_dependency(value, is_identifier)
|
||||
|
||||
def value_dependency(self,
|
||||
def value_dependency(
|
||||
self,
|
||||
value: Any,
|
||||
is_identifier: bool=False,
|
||||
is_identifier: bool = False,
|
||||
) -> Any:
|
||||
"""parse dependancy to add dependencies
|
||||
"""
|
||||
"""parse dependancy to add dependencies"""
|
||||
for param in chain(value.params.args, value.params.kwargs.values()):
|
||||
if isinstance(param, ParamOption):
|
||||
# pylint: disable=protected-access
|
||||
|
@ -382,7 +406,9 @@ class BaseOption(Base):
|
|||
else:
|
||||
param.set_self_option(self)
|
||||
opt = None
|
||||
if not getattr(dest, '_dependencies_information', {}):
|
||||
if not getattr(dest, "_dependencies_information", {}):
|
||||
dest._dependencies_information = {None: []}
|
||||
dest._dependencies_information[None].append(param)
|
||||
dest._dependencies_information.setdefault(param.information_name, []).append(opt)
|
||||
dest._dependencies_information.setdefault(
|
||||
param.information_name, []
|
||||
).append(opt)
|
||||
|
|
|
@ -26,15 +26,15 @@ from .option import Option
|
|||
|
||||
|
||||
class BoolOption(Option):
|
||||
"""represents a choice between ``True`` and ``False``
|
||||
"""
|
||||
__slots__ = tuple()
|
||||
_type = 'boolean'
|
||||
"""represents a choice between ``True`` and ``False``"""
|
||||
|
||||
def validate(self,
|
||||
__slots__ = tuple()
|
||||
_type = "boolean"
|
||||
|
||||
def validate(
|
||||
self,
|
||||
value: bool,
|
||||
) -> None:
|
||||
"""validate value
|
||||
"""
|
||||
"""validate value"""
|
||||
if not isinstance(value, bool):
|
||||
raise ValueError()
|
||||
|
|
|
@ -27,21 +27,21 @@ from .option import Option
|
|||
|
||||
|
||||
class BroadcastOption(Option):
|
||||
"""represents the choice of a broadcast
|
||||
"""
|
||||
__slots__ = tuple()
|
||||
_type = 'broadcast address'
|
||||
"""represents the choice of a broadcast"""
|
||||
|
||||
def validate(self,
|
||||
__slots__ = tuple()
|
||||
_type = "broadcast address"
|
||||
|
||||
def validate(
|
||||
self,
|
||||
value: str,
|
||||
) -> None:
|
||||
"""validate
|
||||
"""
|
||||
"""validate"""
|
||||
if not isinstance(value, str):
|
||||
raise ValueError(_('invalid string'))
|
||||
if value.count('.') != 3:
|
||||
raise ValueError(_("invalid string"))
|
||||
if value.count(".") != 3:
|
||||
raise ValueError()
|
||||
for val in value.split('.'):
|
||||
for val in value.split("."):
|
||||
if val.startswith("0") and len(val) > 1:
|
||||
raise ValueError()
|
||||
try:
|
||||
|
|
|
@ -34,55 +34,53 @@ class ChoiceOption(Option):
|
|||
|
||||
The option can also have the value ``None``
|
||||
"""
|
||||
|
||||
__slots__ = tuple()
|
||||
_type = 'choice'
|
||||
|
||||
def __init__(self,
|
||||
name,
|
||||
doc,
|
||||
values,
|
||||
*args,
|
||||
**kwargs):
|
||||
_type = "choice"
|
||||
|
||||
def __init__(self, name, doc, values, *args, **kwargs):
|
||||
"""
|
||||
:param values: is a list of values the option can possibly take
|
||||
"""
|
||||
if not isinstance(values, (Calculation, tuple)):
|
||||
raise TypeError(_('values must be a tuple or a calculation for {0}'
|
||||
).format(name))
|
||||
raise TypeError(
|
||||
_("values must be a tuple or a calculation for {0}").format(name)
|
||||
)
|
||||
self._choice_values = values
|
||||
super().__init__(name,
|
||||
doc,
|
||||
*args,
|
||||
**kwargs)
|
||||
super().__init__(name, doc, *args, **kwargs)
|
||||
|
||||
def impl_get_values(self,
|
||||
def impl_get_values(
|
||||
self,
|
||||
subconfig: "SubConfig",
|
||||
uncalculated: bool=False,
|
||||
uncalculated: bool = False,
|
||||
):
|
||||
"""get values allowed by option
|
||||
"""
|
||||
"""get values allowed by option"""
|
||||
choices = self._choice_values
|
||||
if isinstance(choices, tuple):
|
||||
choices = list(choices)
|
||||
if uncalculated:
|
||||
return choices
|
||||
values = get_calculated_value(subconfig,
|
||||
values = get_calculated_value(
|
||||
subconfig,
|
||||
choices,
|
||||
)[0]
|
||||
|
||||
if values != undefined and not isinstance(values, (list, tuple)):
|
||||
raise ConfigError(_('the calculated values "{0}" for "{1}" is not a list'
|
||||
'').format(values, self.impl_getname()))
|
||||
raise ConfigError(
|
||||
_('the calculated values "{0}" for "{1}" is not a list' "").format(
|
||||
values, self.impl_getname()
|
||||
)
|
||||
)
|
||||
return values
|
||||
|
||||
def validate(self,
|
||||
def validate(
|
||||
self,
|
||||
value: Any,
|
||||
) -> None:
|
||||
"""nothing to valide
|
||||
"""
|
||||
"""nothing to valide"""
|
||||
|
||||
def validate_with_option(self,
|
||||
def validate_with_option(
|
||||
self,
|
||||
value: Any,
|
||||
subconfig: "SubConfig",
|
||||
loaded: bool,
|
||||
|
@ -92,15 +90,17 @@ class ChoiceOption(Option):
|
|||
values = self.impl_get_values(subconfig)
|
||||
self.validate_values(value, values)
|
||||
|
||||
def validate_values(self,
|
||||
def validate_values(
|
||||
self,
|
||||
value,
|
||||
values,
|
||||
) -> None:
|
||||
"""validate values
|
||||
"""
|
||||
"""validate values"""
|
||||
if values is not undefined and value not in values:
|
||||
if len(values) == 1:
|
||||
raise ValueError(_('only "{0}" is allowed'
|
||||
'').format(values[0]))
|
||||
raise ValueError(_('only {0} are allowed'
|
||||
'').format(display_list(values, add_quote=True)))
|
||||
raise ValueError(_('only "{0}" is allowed' "").format(values[0]))
|
||||
raise ValueError(
|
||||
_("only {0} are allowed" "").format(
|
||||
display_list(values, add_quote=True)
|
||||
)
|
||||
)
|
||||
|
|
|
@ -27,13 +27,12 @@ from .stroption import StrOption
|
|||
|
||||
|
||||
class DateOption(StrOption):
|
||||
"""represents the choice of a date
|
||||
"""
|
||||
__slots__ = tuple()
|
||||
_type = 'date'
|
||||
"""represents the choice of a date"""
|
||||
|
||||
def validate(self,
|
||||
value: str) -> None:
|
||||
__slots__ = tuple()
|
||||
_type = "date"
|
||||
|
||||
def validate(self, value: str) -> None:
|
||||
super().validate(value)
|
||||
try:
|
||||
datetime.strptime(value, "%Y-%m-%d")
|
||||
|
|
|
@ -39,69 +39,84 @@ class DomainnameOption(StrOption):
|
|||
domainname:
|
||||
fqdn: with tld, not supported yet
|
||||
"""
|
||||
__slots__ = tuple()
|
||||
_type = 'domain name'
|
||||
|
||||
def __init__(self,
|
||||
__slots__ = tuple()
|
||||
_type = "domain name"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
doc: str,
|
||||
*args,
|
||||
allow_ip: bool=False,
|
||||
allow_cidr_network: bool=False,
|
||||
type: str='domainname',
|
||||
allow_without_dot: bool=False,
|
||||
allow_startswith_dot: bool=False,
|
||||
allow_ip: bool = False,
|
||||
allow_cidr_network: bool = False,
|
||||
type: str = "domainname",
|
||||
allow_without_dot: bool = False,
|
||||
allow_startswith_dot: bool = False,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
# pylint: disable=too-many-branches,too-many-locals,too-many-arguments
|
||||
if type not in ['netbios', 'hostname', 'domainname']:
|
||||
raise ValueError(_('unknown type {0} for hostname').format(type))
|
||||
extra = {'_dom_type': type}
|
||||
if type not in ["netbios", "hostname", "domainname"]:
|
||||
raise ValueError(_("unknown type {0} for hostname").format(type))
|
||||
extra = {"_dom_type": type}
|
||||
if not isinstance(allow_ip, bool):
|
||||
raise ValueError(_('allow_ip must be a boolean'))
|
||||
raise ValueError(_("allow_ip must be a boolean"))
|
||||
if not isinstance(allow_cidr_network, bool):
|
||||
raise ValueError(_('allow_cidr_network must be a boolean'))
|
||||
raise ValueError(_("allow_cidr_network must be a boolean"))
|
||||
if not isinstance(allow_without_dot, bool):
|
||||
raise ValueError(_('allow_without_dot must be a boolean'))
|
||||
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
|
||||
if type == 'domainname':
|
||||
raise ValueError(_("allow_startswith_dot must be a boolean"))
|
||||
extra["_allow_without_dot"] = allow_without_dot
|
||||
if type == "domainname":
|
||||
if allow_without_dot:
|
||||
min_time = 0
|
||||
else:
|
||||
min_time = 1
|
||||
regexp = r'((?!-)[a-z0-9-]{{{1},{0}}}\.){{{1},}}[a-z0-9-]{{1,{0}}}'.format(self._get_len(type), min_time)
|
||||
regexp = r"((?!-)[a-z0-9-]{{{1},{0}}}\.){{{1},}}[a-z0-9-]{{1,{0}}}".format(
|
||||
self._get_len(type), min_time
|
||||
)
|
||||
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')
|
||||
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'
|
||||
)
|
||||
if allow_ip:
|
||||
msg = _('could be a IP, otherwise {}').format(msg)
|
||||
msg_warning = _('could be a IP, otherwise {}').format(msg_warning)
|
||||
msg = _("could be a IP, otherwise {}").format(msg)
|
||||
msg_warning = _("could be a IP, otherwise {}").format(msg_warning)
|
||||
if not allow_cidr_network:
|
||||
regexp = r'(?:{0}|(?:(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){{3}}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)))'.format(regexp)
|
||||
regexp = r"(?:{0}|(?:(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){{3}}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)))".format(
|
||||
regexp
|
||||
)
|
||||
else:
|
||||
regexp = r'(?:{0}|(?:(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){{3}}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/[0-9][0-9]))'.format(regexp)
|
||||
regexp = r'^{0}$'.format(regexp)
|
||||
extra['_domain_re'] = re.compile(regexp)
|
||||
extra['_domain_re_message'] = msg
|
||||
extra['_domain_re_message_warning'] = msg_warning
|
||||
extra['_has_upper'] = re.compile('[A-Z]')
|
||||
regexp = r"(?:{0}|(?:(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){{3}}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/[0-9][0-9]))".format(
|
||||
regexp
|
||||
)
|
||||
regexp = r"^{0}$".format(regexp)
|
||||
extra["_domain_re"] = re.compile(regexp)
|
||||
extra["_domain_re_message"] = msg
|
||||
extra["_domain_re_message_warning"] = msg_warning
|
||||
extra["_has_upper"] = re.compile("[A-Z]")
|
||||
if allow_ip:
|
||||
extra['_ip'] = IPOption(name,
|
||||
extra["_ip"] = IPOption(
|
||||
name,
|
||||
doc,
|
||||
)
|
||||
extra['_allow_ip'] = allow_ip
|
||||
extra["_allow_ip"] = allow_ip
|
||||
if allow_cidr_network:
|
||||
extra['_network'] = NetworkOption(name,
|
||||
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,
|
||||
super().__init__(
|
||||
name,
|
||||
doc,
|
||||
*args,
|
||||
extra=extra,
|
||||
|
@ -109,56 +124,54 @@ class DomainnameOption(StrOption):
|
|||
)
|
||||
|
||||
def _get_len(self, type_):
|
||||
if type_ == 'netbios':
|
||||
if type_ == "netbios":
|
||||
return 15
|
||||
return 63
|
||||
|
||||
def _validate_domain(self,
|
||||
value: str) -> None:
|
||||
def _validate_domain(self, value: str) -> None:
|
||||
def _valid_length(val):
|
||||
if len(val) < 1:
|
||||
raise ValueError(_("invalid length (min 1)"))
|
||||
if len(val) > part_name_length:
|
||||
raise ValueError(_("invalid length (max {0})"
|
||||
"").format(part_name_length))
|
||||
raise ValueError(
|
||||
_("invalid length (max {0})" "").format(part_name_length)
|
||||
)
|
||||
|
||||
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:
|
||||
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
|
||||
if val.endswith('.'):
|
||||
if val.endswith("."):
|
||||
nval = val[:-1]
|
||||
else:
|
||||
nval = val
|
||||
for dom in nval.split('.'):
|
||||
for dom in nval.split("."):
|
||||
_valid_length(dom)
|
||||
else:
|
||||
_valid_length(value)
|
||||
|
||||
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')
|
||||
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")
|
||||
if allow_ip is False and allow_cidr_network is False:
|
||||
raise ValueError(_('must not be an IP'))
|
||||
raise ValueError(_("must not be an IP"))
|
||||
if allow_ip is True:
|
||||
try:
|
||||
self.impl_get_extra('_ip').validate(value)
|
||||
self.impl_get_extra("_ip").validate(value)
|
||||
return
|
||||
except ValueError as err:
|
||||
if allow_cidr_network is False:
|
||||
raise err
|
||||
if allow_cidr_network is True:
|
||||
self.impl_get_extra('_network').validate(value)
|
||||
self.impl_get_extra("_network").validate(value)
|
||||
|
||||
def validate(self,
|
||||
value: str) -> None:
|
||||
def validate(self, value: str) -> None:
|
||||
super().validate(value)
|
||||
try:
|
||||
# check if it's an IP or network
|
||||
|
@ -168,42 +181,40 @@ class DomainnameOption(StrOption):
|
|||
else:
|
||||
self._validate_ip_network(value)
|
||||
|
||||
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('.'):
|
||||
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("."):
|
||||
val = value[1:]
|
||||
else:
|
||||
val = value
|
||||
if val.endswith('.'):
|
||||
if val.endswith("."):
|
||||
nval = val[:-1]
|
||||
else:
|
||||
nval = val
|
||||
if not self.impl_get_extra('_domain_re').search(nval):
|
||||
if not self.impl_get_extra("_domain_re").search(nval):
|
||||
if warnings_only:
|
||||
raise ValueError(self.impl_get_extra('_domain_re_message_warning'))
|
||||
raise ValueError(self.impl_get_extra('_domain_re_message'))
|
||||
raise ValueError(self.impl_get_extra("_domain_re_message_warning"))
|
||||
raise ValueError(self.impl_get_extra("_domain_re_message"))
|
||||
|
||||
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')
|
||||
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")
|
||||
# it's an IP so validate with IPOption
|
||||
if allow_ip is True and allow_cidr_network is False:
|
||||
try:
|
||||
self.impl_get_extra('_ip').second_level_validation(value, warnings_only)
|
||||
self.impl_get_extra("_ip").second_level_validation(value, warnings_only)
|
||||
return
|
||||
except ValueError as err:
|
||||
raise err
|
||||
if allow_cidr_network is True:
|
||||
self.impl_get_extra('_network').second_level_validation(value, warnings_only)
|
||||
self.impl_get_extra("_network").second_level_validation(
|
||||
value, warnings_only
|
||||
)
|
||||
|
||||
def second_level_validation(self,
|
||||
value: str,
|
||||
warnings_only: bool) -> None:
|
||||
def second_level_validation(self, value: str, warnings_only: bool) -> None:
|
||||
try:
|
||||
# check if it's an IP or network
|
||||
ip_interface(value)
|
||||
|
|
|
@ -35,15 +35,19 @@ from ..error import ConfigError
|
|||
from ..autolib import Calculation, get_calculated_value
|
||||
|
||||
|
||||
NAME_REGEXP = re.compile(r'^[a-zA-Z\d\-_]*$')
|
||||
NAME_REGEXP = re.compile(r"^[a-zA-Z\d\-_]*$")
|
||||
|
||||
|
||||
class DynOptionDescription(OptionDescription):
|
||||
"""dyn option description
|
||||
"""
|
||||
__slots__ = ('_identifiers',
|
||||
'_subdyns',
|
||||
"""dyn option description"""
|
||||
|
||||
__slots__ = (
|
||||
"_identifiers",
|
||||
"_subdyns",
|
||||
)
|
||||
|
||||
def __init__(self,
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
doc: str,
|
||||
children: List[BaseOption],
|
||||
|
@ -51,7 +55,8 @@ class DynOptionDescription(OptionDescription):
|
|||
**kwargs,
|
||||
) -> None:
|
||||
# pylint: disable=too-many-arguments
|
||||
super().__init__(name,
|
||||
super().__init__(
|
||||
name,
|
||||
doc,
|
||||
children,
|
||||
**kwargs,
|
||||
|
@ -64,44 +69,45 @@ class DynOptionDescription(OptionDescription):
|
|||
self.value_dependencies(identifiers, is_identifier=True)
|
||||
self._identifiers = identifiers
|
||||
|
||||
def convert_identifier_to_path(self,
|
||||
def convert_identifier_to_path(
|
||||
self,
|
||||
identifier: Any,
|
||||
) -> str:
|
||||
"""convert identifier to use it to a path
|
||||
"""
|
||||
"""convert identifier to use it to a path"""
|
||||
if identifier is None:
|
||||
return None
|
||||
if not isinstance(identifier, str):
|
||||
identifier = str(identifier)
|
||||
if '.' in identifier:
|
||||
identifier = identifier.replace('.', '_')
|
||||
if "." in identifier:
|
||||
identifier = identifier.replace(".", "_")
|
||||
return identifier
|
||||
|
||||
def impl_is_dynoptiondescription(self) -> bool:
|
||||
return True
|
||||
|
||||
def option_is_self(self,
|
||||
def option_is_self(
|
||||
self,
|
||||
option,
|
||||
) -> bool:
|
||||
return option == self
|
||||
|
||||
def impl_getname(self, identifier=None) -> str:
|
||||
"""get name
|
||||
"""
|
||||
"""get name"""
|
||||
name = super().impl_getname()
|
||||
if identifier is None:
|
||||
return name
|
||||
path_identifier = self.convert_identifier_to_path(identifier)
|
||||
return name + path_identifier
|
||||
|
||||
def get_identifiers(self,
|
||||
parent: 'SubConfig',
|
||||
def get_identifiers(
|
||||
self,
|
||||
parent: "SubConfig",
|
||||
*,
|
||||
uncalculated: bool=False,
|
||||
uncalculated: bool = False,
|
||||
) -> List[str]:
|
||||
"""get dynamic identifiers
|
||||
"""
|
||||
subconfig = parent.get_child(self,
|
||||
"""get dynamic identifiers"""
|
||||
subconfig = parent.get_child(
|
||||
self,
|
||||
None,
|
||||
False,
|
||||
properties=None,
|
||||
|
@ -111,7 +117,8 @@ class DynOptionDescription(OptionDescription):
|
|||
identifiers = identifiers.copy()
|
||||
if uncalculated:
|
||||
return identifiers
|
||||
values = get_calculated_value(subconfig,
|
||||
values = get_calculated_value(
|
||||
subconfig,
|
||||
identifiers,
|
||||
validate_properties=False,
|
||||
)[0]
|
||||
|
@ -120,19 +127,28 @@ class DynOptionDescription(OptionDescription):
|
|||
values_ = []
|
||||
if __debug__:
|
||||
if not isinstance(values, list):
|
||||
raise ValueError(_('DynOptionDescription identifiers for '
|
||||
f'option {self.impl_get_display_name(subconfig, with_quote=True)}, is not '
|
||||
f'a list ({values})'))
|
||||
raise ValueError(
|
||||
_(
|
||||
"DynOptionDescription identifiers for option {0}, is not a list ({1})"
|
||||
).format(
|
||||
self.impl_get_display_name(subconfig, with_quote=True), 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:
|
||||
if __debug__ and cval is not None:
|
||||
raise ValueError(_('invalid identifier "{}" for option {}'
|
||||
'').format(cval,
|
||||
self.impl_get_display_name(subconfig, with_quote=True)))
|
||||
raise ValueError(
|
||||
_('invalid identifier "{}" for option {}' "").format(
|
||||
cval, self.impl_get_display_name(subconfig, with_quote=True)
|
||||
)
|
||||
)
|
||||
else:
|
||||
values_.append(val)
|
||||
if __debug__ and len(values_) > len(set(values_)):
|
||||
raise ValueError(_(f'DynOptionDescription "{self._name}" identifiers return a list with '
|
||||
f'same values "{values_}"'''))
|
||||
raise ValueError(
|
||||
_(
|
||||
'DynOptionDescription "{0}" identifiers return a list with same values "{1}"'
|
||||
).format(self._name, values_)
|
||||
)
|
||||
return values_
|
||||
|
|
|
@ -27,8 +27,10 @@ from .stroption import RegexpOption
|
|||
|
||||
|
||||
class EmailOption(RegexpOption):
|
||||
"""represents a choice of an email
|
||||
"""
|
||||
"""represents a choice of an email"""
|
||||
|
||||
__slots__ = tuple()
|
||||
_regexp = re.compile(r"^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$")
|
||||
_type = 'email address'
|
||||
_regexp = re.compile(
|
||||
r"^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$"
|
||||
)
|
||||
_type = "email address"
|
||||
|
|
|
@ -28,45 +28,54 @@ from .stroption import StrOption
|
|||
|
||||
|
||||
class FilenameOption(StrOption):
|
||||
"""validate file or directory name
|
||||
"""
|
||||
__slots__ = tuple()
|
||||
_type = 'file name'
|
||||
"""validate file or directory name"""
|
||||
|
||||
def __init__(self,
|
||||
__slots__ = tuple()
|
||||
_type = "file name"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
*args,
|
||||
allow_relative=False,
|
||||
test_existence=False,
|
||||
types=['file', 'directory'],
|
||||
**kwargs):
|
||||
types=["file", "directory"],
|
||||
**kwargs,
|
||||
):
|
||||
if not isinstance(types, list):
|
||||
raise ValueError(_(f'types parameter must be a list, not "{types}" for "{name}"'))
|
||||
raise ValueError(
|
||||
_('types parameter must be a list, not "{0}" for "{1}"').format(
|
||||
types, name
|
||||
)
|
||||
)
|
||||
for typ in types:
|
||||
if typ not in ['file', 'directory']:
|
||||
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,
|
||||
extra = {
|
||||
"_allow_relative": allow_relative,
|
||||
"_test_existence": test_existence,
|
||||
"_types": types,
|
||||
}
|
||||
super().__init__(name,
|
||||
*args,
|
||||
extra=extra,
|
||||
**kwargs)
|
||||
super().__init__(name, *args, extra=extra, **kwargs)
|
||||
|
||||
def validate(self,
|
||||
def validate(
|
||||
self,
|
||||
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():
|
||||
if "file" in types and file.is_file():
|
||||
found = True
|
||||
if not found and 'directory' in types and file.is_dir():
|
||||
if not found and "directory" in types and file.is_dir():
|
||||
found = True
|
||||
if not found:
|
||||
raise ValueError(_(f'cannot find {display_list(types, separator="or")} "{value}"'))
|
||||
raise ValueError(
|
||||
_('cannot find {0} "{1}"').format(
|
||||
display_list(types, separator="or"), value
|
||||
)
|
||||
)
|
||||
|
|
|
@ -26,12 +26,11 @@ from .option import Option
|
|||
|
||||
|
||||
class FloatOption(Option):
|
||||
"""represents a choice of a floating point number
|
||||
"""
|
||||
__slots__ = tuple()
|
||||
_type = 'float'
|
||||
"""represents a choice of a floating point number"""
|
||||
|
||||
def validate(self,
|
||||
value: float) -> None:
|
||||
__slots__ = tuple()
|
||||
_type = "float"
|
||||
|
||||
def validate(self, value: float) -> None:
|
||||
if not isinstance(value, float):
|
||||
raise ValueError()
|
||||
|
|
|
@ -28,40 +28,35 @@ from .option import Option
|
|||
class IntOption(Option):
|
||||
"represents a choice of an integer"
|
||||
__slots__ = tuple()
|
||||
_type = 'integer'
|
||||
_type = "integer"
|
||||
|
||||
def __init__(self,
|
||||
*args,
|
||||
min_number=None,
|
||||
max_number=None,
|
||||
**kwargs):
|
||||
def __init__(self, *args, min_number=None, max_number=None, **kwargs):
|
||||
extra = {}
|
||||
if min_number is not None:
|
||||
extra['min_number'] = min_number
|
||||
extra["min_number"] = min_number
|
||||
if max_number is not None:
|
||||
extra['max_number'] = max_number
|
||||
extra["max_number"] = max_number
|
||||
super().__init__(*args, extra=extra, **kwargs)
|
||||
|
||||
def validate(self,
|
||||
def validate(
|
||||
self,
|
||||
value: int,
|
||||
) -> None:
|
||||
if not isinstance(value, int):
|
||||
raise ValueError()
|
||||
|
||||
def second_level_validation(self,
|
||||
value,
|
||||
warnings_only):
|
||||
min_number = self.impl_get_extra('min_number')
|
||||
def second_level_validation(self, value, warnings_only):
|
||||
min_number = self.impl_get_extra("min_number")
|
||||
if min_number is not None and value < min_number:
|
||||
if warnings_only:
|
||||
msg = 'value should be equal or greater than "{0}"'
|
||||
msg = _('value should be equal or greater than "{0}"')
|
||||
else:
|
||||
msg = 'value must be equal or greater than "{0}"'
|
||||
raise ValueError(_(msg).format(min_number))
|
||||
max_number = self.impl_get_extra('max_number')
|
||||
msg = _('value must be equal or greater than "{0}"')
|
||||
raise ValueError(msg.format(min_number))
|
||||
max_number = self.impl_get_extra("max_number")
|
||||
if max_number is not None and value > max_number:
|
||||
if warnings_only:
|
||||
msg = 'value should be less than "{0}"'
|
||||
msg = _('value should be less than "{0}"')
|
||||
else:
|
||||
msg = 'value must be less than "{0}"'
|
||||
raise ValueError(_(msg).format(max_number))
|
||||
msg = _('value must be less than "{0}"')
|
||||
raise ValueError(msg.format(max_number))
|
||||
|
|
|
@ -27,26 +27,26 @@ from .stroption import StrOption
|
|||
|
||||
|
||||
class IPOption(StrOption):
|
||||
"""represents the choice of an ip
|
||||
"""
|
||||
__slots__ = tuple()
|
||||
_type = 'IP'
|
||||
"""represents the choice of an ip"""
|
||||
|
||||
def __init__(self,
|
||||
__slots__ = tuple()
|
||||
_type = "IP"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*args,
|
||||
private_only=False,
|
||||
allow_reserved=False,
|
||||
cidr=False,
|
||||
extra=None,
|
||||
**kwargs):
|
||||
**kwargs,
|
||||
):
|
||||
if extra is None:
|
||||
extra = {}
|
||||
extra['_private_only'] = private_only
|
||||
extra['_allow_reserved'] = allow_reserved
|
||||
extra['_cidr'] = cidr
|
||||
super().__init__(*args,
|
||||
extra=extra,
|
||||
**kwargs)
|
||||
extra["_private_only"] = private_only
|
||||
extra["_allow_reserved"] = allow_reserved
|
||||
extra["_cidr"] = cidr
|
||||
super().__init__(*args, extra=extra, **kwargs)
|
||||
|
||||
def _validate_cidr(self, value):
|
||||
try:
|
||||
|
@ -64,27 +64,24 @@ class IPOption(StrOption):
|
|||
except ValueError as err:
|
||||
raise ValueError() from err
|
||||
|
||||
def validate(self,
|
||||
value: str) -> None:
|
||||
def validate(self, value: str) -> None:
|
||||
super().validate(value)
|
||||
if self.impl_get_extra('_cidr'):
|
||||
if '/' not in value:
|
||||
if self.impl_get_extra("_cidr"):
|
||||
if "/" not in value:
|
||||
raise ValueError(_('CIDR address must have a "/"'))
|
||||
self._validate_cidr(value)
|
||||
else:
|
||||
self._validate_ip(value)
|
||||
|
||||
def second_level_validation(self,
|
||||
value: str,
|
||||
warnings_only: bool) -> None:
|
||||
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:
|
||||
|
|
|
@ -26,6 +26,7 @@ from typing import List, Iterator, Optional
|
|||
from ..i18n import _
|
||||
from ..setting import groups, undefined, ALLOWED_LEADER_PROPERTIES
|
||||
from .optiondescription import OptionDescription
|
||||
|
||||
# from .syndynoption import SynDynLeadership
|
||||
from .baseoption import BaseOption
|
||||
from .option import Option
|
||||
|
@ -34,22 +35,27 @@ from ..autolib import Calculation
|
|||
|
||||
|
||||
class Leadership(OptionDescription):
|
||||
"""Leadership
|
||||
"""
|
||||
"""Leadership"""
|
||||
|
||||
# pylint: disable=too-many-arguments
|
||||
__slots__ = ('leader',
|
||||
'followers',
|
||||
__slots__ = (
|
||||
"leader",
|
||||
"followers",
|
||||
)
|
||||
|
||||
def __init__(self,
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
doc,
|
||||
children: List[BaseOption],
|
||||
**kwargs,
|
||||
) -> None:
|
||||
if 'group_type' in kwargs:
|
||||
raise LeadershipError(_('cannot set "group_type" attribute for a Leadership'))
|
||||
super().__init__(name,
|
||||
if "group_type" in kwargs:
|
||||
raise LeadershipError(
|
||||
_('cannot set "group_type" attribute for a Leadership')
|
||||
)
|
||||
super().__init__(
|
||||
name,
|
||||
doc,
|
||||
children,
|
||||
**kwargs,
|
||||
|
@ -57,8 +63,11 @@ class Leadership(OptionDescription):
|
|||
self._group_type = groups.leadership
|
||||
followers = []
|
||||
if len(children) < 2:
|
||||
raise ValueError(_('a leader and a follower are mandatories in leadership "{}"'
|
||||
'').format(name))
|
||||
raise ValueError(
|
||||
_(
|
||||
'a leader and a follower are mandatories in leadership "{}"' ""
|
||||
).format(name)
|
||||
)
|
||||
for idx, child in enumerate(children):
|
||||
if __debug__:
|
||||
self._check_child_is_valid(child, idx, children)
|
||||
|
@ -66,34 +75,51 @@ class Leadership(OptionDescription):
|
|||
if __debug__:
|
||||
self._check_default_value(child)
|
||||
# remove empty property for follower
|
||||
child._properties = frozenset(child._properties - {'empty', 'unique'})
|
||||
child._properties = frozenset(child._properties - {"empty", "unique"})
|
||||
followers.append(child)
|
||||
child._add_dependency(self)
|
||||
child._leadership = weakref.ref(self)
|
||||
if __debug__:
|
||||
leader = children[0]
|
||||
for prop in leader.impl_getproperties():
|
||||
if prop not in ALLOWED_LEADER_PROPERTIES and not isinstance(prop, Calculation):
|
||||
raise LeadershipError(_('leader cannot have "{}" property').format(prop))
|
||||
if prop not in ALLOWED_LEADER_PROPERTIES and not isinstance(
|
||||
prop, Calculation
|
||||
):
|
||||
raise LeadershipError(
|
||||
_('leader cannot have "{}" property').format(prop)
|
||||
)
|
||||
|
||||
def _check_child_is_valid(self,
|
||||
def _check_child_is_valid(
|
||||
self,
|
||||
child: BaseOption,
|
||||
index: int,
|
||||
children: [BaseOption],
|
||||
) -> None:
|
||||
if child.impl_is_symlinkoption():
|
||||
if not index:
|
||||
raise ValueError(_('leadership {0} shall not have '
|
||||
"a symlinkoption").format(self.impl_get_display_name(None, with_quote=True)))
|
||||
raise ValueError(
|
||||
_("leadership {0} shall not have " "a symlinkoption").format(
|
||||
self.impl_get_display_name(None, with_quote=True)
|
||||
)
|
||||
)
|
||||
return
|
||||
if not isinstance(child, Option):
|
||||
raise ValueError(_('leadership {0} shall not have '
|
||||
'a subgroup').format(self.impl_get_display_name(None, with_quote=True)))
|
||||
raise ValueError(
|
||||
_("leadership {0} shall not have " "a subgroup").format(
|
||||
self.impl_get_display_name(None, with_quote=True)
|
||||
)
|
||||
)
|
||||
if not child.impl_is_multi():
|
||||
raise ValueError(_('only multi option allowed in leadership {0} but option '
|
||||
'{1} is not a multi'
|
||||
'').format(self.impl_get_display_name(None, with_quote=True),
|
||||
child.impl_get_display_name(None, with_quote=True)))
|
||||
raise ValueError(
|
||||
_(
|
||||
"only multi option allowed in leadership {0} but option "
|
||||
"{1} is not a multi"
|
||||
""
|
||||
).format(
|
||||
self.impl_get_display_name(None, with_quote=True),
|
||||
child.impl_get_display_name(None, with_quote=True),
|
||||
)
|
||||
)
|
||||
|
||||
def _check_default_value(self, child: BaseOption):
|
||||
if child.impl_is_symlinkoption():
|
||||
|
@ -111,78 +137,84 @@ class Leadership(OptionDescription):
|
|||
else:
|
||||
calculation = isinstance(default, Calculation)
|
||||
if not calculation:
|
||||
raise ValueError(_('not allowed default value for follower option '
|
||||
f'{child.impl_get_display_name(None, with_quote=True)} in leadership '
|
||||
f'{self.impl_get_display_name(None, with_quote=True)}'))
|
||||
raise ValueError(
|
||||
_(
|
||||
"not allowed default value for follower option {0} in leadership {1}"
|
||||
).format(
|
||||
child.impl_get_display_name(None, with_quote=True),
|
||||
self.impl_get_display_name(None, with_quote=True),
|
||||
)
|
||||
)
|
||||
|
||||
def _setsubdyn(self,
|
||||
def _setsubdyn(
|
||||
self,
|
||||
subdyn,
|
||||
) -> None:
|
||||
for chld in self._children[1]:
|
||||
chld._setsubdyn(subdyn)
|
||||
super()._setsubdyn(subdyn)
|
||||
|
||||
def is_leader(self,
|
||||
def is_leader(
|
||||
self,
|
||||
opt: Option,
|
||||
) -> bool:
|
||||
"""the option is the leader
|
||||
"""
|
||||
"""the option is the leader"""
|
||||
leader = self.get_leader()
|
||||
if opt.impl_is_dynsymlinkoption():
|
||||
opt = opt.opt
|
||||
return opt == leader
|
||||
|
||||
def get_leader(self) -> Option:
|
||||
"""get leader
|
||||
"""
|
||||
"""get leader"""
|
||||
return self._children[1][0]
|
||||
|
||||
def get_followers(self) -> Iterator[Option]:
|
||||
"""get all followers
|
||||
"""
|
||||
"""get all followers"""
|
||||
for follower in self._children[1][1:]:
|
||||
yield follower
|
||||
|
||||
def in_same_leadership(self,
|
||||
def in_same_leadership(
|
||||
self,
|
||||
opt: Option,
|
||||
) -> bool:
|
||||
"""check if followers are in same leadership
|
||||
"""
|
||||
"""check if followers are in same leadership"""
|
||||
if opt.impl_is_dynsymlinkoption():
|
||||
opt = opt.opt
|
||||
return opt in self._children[1]
|
||||
|
||||
def reset(self, parent: "SubConfig") -> None:
|
||||
"""reset follower value
|
||||
"""
|
||||
"""reset follower value"""
|
||||
values = parent.config_bag.context.get_values()
|
||||
for follower in self.get_followers():
|
||||
subconfig_follower = parent.get_child(follower,
|
||||
subconfig_follower = parent.get_child(
|
||||
follower,
|
||||
None,
|
||||
False,
|
||||
)
|
||||
values.reset(subconfig_follower,
|
||||
values.reset(
|
||||
subconfig_follower,
|
||||
validate=False,
|
||||
)
|
||||
|
||||
def follower_force_store_value(self,
|
||||
def follower_force_store_value(
|
||||
self,
|
||||
value,
|
||||
subconfig: 'SubConfig',
|
||||
subconfig: "SubConfig",
|
||||
owner,
|
||||
) -> None:
|
||||
"""apply force_store_value to follower
|
||||
"""
|
||||
"""apply force_store_value to follower"""
|
||||
if not value:
|
||||
return
|
||||
config_bag = subconfig.config_bag
|
||||
values = config_bag.context.get_values()
|
||||
for idx, follower in enumerate(self.get_children()):
|
||||
sub_subconfig = subconfig.get_child(follower,
|
||||
sub_subconfig = subconfig.get_child(
|
||||
follower,
|
||||
None,
|
||||
False,
|
||||
config_bag=config_bag,
|
||||
)
|
||||
if 'force_store_value' not in sub_subconfig.properties:
|
||||
if "force_store_value" not in sub_subconfig.properties:
|
||||
continue
|
||||
self_path = sub_subconfig.path
|
||||
if not idx:
|
||||
|
@ -193,25 +225,27 @@ class Leadership(OptionDescription):
|
|||
apply_requires = False
|
||||
indexes = range(len(value))
|
||||
for index in indexes:
|
||||
i_sub_subconfig = subconfig.get_child(follower,
|
||||
i_sub_subconfig = subconfig.get_child(
|
||||
follower,
|
||||
index,
|
||||
False,
|
||||
config_bag=config_bag,
|
||||
)
|
||||
values.set_storage_value(self_path,
|
||||
values.set_storage_value(
|
||||
self_path,
|
||||
index,
|
||||
values.get_value(i_sub_subconfig)[0],
|
||||
owner,
|
||||
)
|
||||
|
||||
def pop(self,
|
||||
subconfig: 'SubConfig',
|
||||
def pop(
|
||||
self,
|
||||
subconfig: "SubConfig",
|
||||
index: int,
|
||||
*,
|
||||
followers: Optional[List[Option]]=undefined,
|
||||
followers: Optional[List[Option]] = undefined,
|
||||
) -> None:
|
||||
"""pop leader value and follower's one
|
||||
"""
|
||||
"""pop leader value and follower's one"""
|
||||
if followers is undefined:
|
||||
# followers are not undefined only in SynDynLeadership
|
||||
followers = self.get_followers()
|
||||
|
@ -219,7 +253,8 @@ class Leadership(OptionDescription):
|
|||
config_bag.remove_validation()
|
||||
values = config_bag.context.get_values()
|
||||
for follower in followers:
|
||||
sub_subconfig = subconfig.parent.get_child(follower,
|
||||
sub_subconfig = subconfig.parent.get_child(
|
||||
follower,
|
||||
index,
|
||||
True,
|
||||
properties=set(), # do not check force_default_on_freeze
|
||||
|
@ -228,39 +263,45 @@ class Leadership(OptionDescription):
|
|||
)
|
||||
values.reduce_index(sub_subconfig)
|
||||
|
||||
def reset_cache(self,
|
||||
def reset_cache(
|
||||
self,
|
||||
path: str,
|
||||
config_bag: 'ConfigBag',
|
||||
config_bag: "ConfigBag",
|
||||
resetted_opts: List[Option],
|
||||
) -> None:
|
||||
self._reset_cache(path,
|
||||
self._reset_cache(
|
||||
path,
|
||||
self.get_leader(),
|
||||
self.get_followers(),
|
||||
config_bag,
|
||||
resetted_opts,
|
||||
)
|
||||
|
||||
def _reset_cache(self,
|
||||
def _reset_cache(
|
||||
self,
|
||||
path: str,
|
||||
leader: Option,
|
||||
followers: List[Option],
|
||||
config_bag: 'ConfigBag',
|
||||
config_bag: "ConfigBag",
|
||||
resetted_opts: List[Option],
|
||||
) -> None:
|
||||
super().reset_cache(path,
|
||||
super().reset_cache(
|
||||
path,
|
||||
config_bag,
|
||||
resetted_opts,
|
||||
)
|
||||
leader_path = leader.impl_getpath()
|
||||
if leader_path not in resetted_opts:
|
||||
leader.reset_cache(leader_path,
|
||||
leader.reset_cache(
|
||||
leader_path,
|
||||
config_bag,
|
||||
resetted_opts,
|
||||
)
|
||||
for follower in followers:
|
||||
follower_path = follower.impl_getpath()
|
||||
if follower_path not in resetted_opts:
|
||||
follower.reset_cache(follower_path,
|
||||
follower.reset_cache(
|
||||
follower_path,
|
||||
config_bag,
|
||||
resetted_opts,
|
||||
)
|
||||
|
|
|
@ -27,8 +27,8 @@ from .stroption import RegexpOption
|
|||
|
||||
|
||||
class MACOption(RegexpOption):
|
||||
"""represents the choice of a mac address
|
||||
"""
|
||||
"""represents the choice of a mac address"""
|
||||
|
||||
__slots__ = tuple()
|
||||
_regexp = re.compile(r"^([0-9A-Fa-f]{2}[:]){5}([0-9A-Fa-f]{2})$")
|
||||
_type = 'mac address'
|
||||
_type = "mac address"
|
||||
|
|
|
@ -26,18 +26,17 @@ from .stroption import StrOption
|
|||
|
||||
|
||||
class NetmaskOption(StrOption):
|
||||
"""represents the choice of a netmask
|
||||
"""
|
||||
__slots__ = tuple()
|
||||
_type = 'netmask address'
|
||||
"""represents the choice of a netmask"""
|
||||
|
||||
def validate(self,
|
||||
value: str) -> None:
|
||||
__slots__ = tuple()
|
||||
_type = "netmask address"
|
||||
|
||||
def validate(self, value: str) -> None:
|
||||
super().validate(value)
|
||||
for val in value.split('.'):
|
||||
for val in value.split("."):
|
||||
if val.startswith("0") and len(val) > 1:
|
||||
raise ValueError()
|
||||
try:
|
||||
ip_network(f'0.0.0.0/{value}')
|
||||
ip_network(f"0.0.0.0/{value}")
|
||||
except ValueError as err:
|
||||
raise ValueError() from err
|
||||
|
|
|
@ -29,30 +29,24 @@ from .stroption import StrOption
|
|||
class NetworkOption(StrOption):
|
||||
"represents the choice of a network"
|
||||
__slots__ = tuple()
|
||||
_type = 'network address'
|
||||
_type = "network address"
|
||||
|
||||
def __init__(self,
|
||||
*args,
|
||||
cidr=False,
|
||||
**kwargs):
|
||||
extra = {'_cidr': cidr}
|
||||
super().__init__(*args,
|
||||
extra=extra,
|
||||
**kwargs)
|
||||
def __init__(self, *args, cidr=False, **kwargs):
|
||||
extra = {"_cidr": cidr}
|
||||
super().__init__(*args, extra=extra, **kwargs)
|
||||
|
||||
def validate(self,
|
||||
value: str) -> None:
|
||||
def validate(self, value: str) -> None:
|
||||
super().validate(value)
|
||||
if value.count('.') != 3:
|
||||
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'))
|
||||
value_ = value.split('/')[0]
|
||||
if "/" not in value:
|
||||
raise ValueError(_("must use CIDR notation"))
|
||||
value_ = value.split("/")[0]
|
||||
else:
|
||||
value_ = value
|
||||
for val in value_.split('.'):
|
||||
for val in value_.split("."):
|
||||
if val.startswith("0") and len(val) > 1:
|
||||
raise ValueError()
|
||||
try:
|
||||
|
@ -60,9 +54,7 @@ class NetworkOption(StrOption):
|
|||
except ValueError as err:
|
||||
raise ValueError() from err
|
||||
|
||||
def second_level_validation(self,
|
||||
value: str,
|
||||
warnings_only: bool) -> None:
|
||||
def second_level_validation(self, value: str, warnings_only: bool) -> None:
|
||||
if ip_network(value).network_address.is_reserved:
|
||||
if warnings_only:
|
||||
msg = _("shouldn't be reserved network")
|
||||
|
|
|
@ -37,37 +37,43 @@ class Option(BaseOption):
|
|||
|
||||
Reminder: an Option object is **not** a container for the value.
|
||||
"""
|
||||
__slots__ = ('_extra',
|
||||
'_warnings_only',
|
||||
__slots__ = (
|
||||
"_extra",
|
||||
"_warnings_only",
|
||||
# multi
|
||||
'_multi',
|
||||
"_multi",
|
||||
# value
|
||||
'_default',
|
||||
'_default_multi',
|
||||
"_default",
|
||||
"_default_multi",
|
||||
#
|
||||
'_validators',
|
||||
"_validators",
|
||||
#
|
||||
'_leadership',
|
||||
'_choice_values',
|
||||
'_choice_values_params',
|
||||
"_leadership",
|
||||
"_choice_values",
|
||||
"_choice_values_params",
|
||||
)
|
||||
_type = None
|
||||
def __init__(self,
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
doc: str,
|
||||
default: Any=undefined,
|
||||
default_multi: Any=None,
|
||||
multi: bool=False,
|
||||
validators: Optional[List[Calculation]]=None,
|
||||
properties: Optional[List[str]]=None,
|
||||
warnings_only: bool=False,
|
||||
extra: Optional[Dict]=None,
|
||||
informations: Optional[Dict]=None,
|
||||
default: Any = undefined,
|
||||
default_multi: Any = None,
|
||||
multi: bool = False,
|
||||
validators: Optional[List[Calculation]] = None,
|
||||
properties: Optional[List[str]] = None,
|
||||
warnings_only: bool = False,
|
||||
extra: Optional[Dict] = None,
|
||||
informations: Optional[Dict] = None,
|
||||
):
|
||||
_setattr = object.__setattr__
|
||||
if not multi and default_multi is not None:
|
||||
raise ValueError(_("default_multi is set whereas multi is False"
|
||||
" in option: {0}").format(name))
|
||||
raise ValueError(
|
||||
_(
|
||||
"default_multi is set whereas multi is False" " in option: {0}"
|
||||
).format(name)
|
||||
)
|
||||
if default is undefined:
|
||||
if multi is False:
|
||||
default = None
|
||||
|
@ -83,14 +89,18 @@ class Option(BaseOption):
|
|||
is_multi = True
|
||||
_multi = submulti
|
||||
else:
|
||||
raise ValueError(_('invalid multi type "{}" for "{}"').format(multi,
|
||||
raise ValueError(
|
||||
_('invalid multi type "{}" for "{}"').format(
|
||||
multi,
|
||||
name,
|
||||
))
|
||||
)
|
||||
)
|
||||
if _multi != 1:
|
||||
_setattr(self, '_multi', _multi)
|
||||
_setattr(self, "_multi", _multi)
|
||||
if multi is not False and default is None:
|
||||
default = []
|
||||
super().__init__(name,
|
||||
super().__init__(
|
||||
name,
|
||||
doc,
|
||||
informations,
|
||||
properties=properties,
|
||||
|
@ -98,102 +108,121 @@ class Option(BaseOption):
|
|||
)
|
||||
if validators is not None:
|
||||
if __debug__ and not isinstance(validators, list):
|
||||
raise ValueError(_(f'validators must be a list of Calculation for "{name}"'))
|
||||
raise ValueError(
|
||||
_('validators must be a list of Calculation for "{0}"').format(name)
|
||||
)
|
||||
for validator in validators:
|
||||
if __debug__ and not isinstance(validator, Calculation):
|
||||
raise ValueError(_('validators must be a Calculation for "{}"').format(name))
|
||||
raise ValueError(
|
||||
_('validators must be a Calculation for "{0}"').format(name)
|
||||
)
|
||||
self.value_dependency(validator)
|
||||
self._validators = tuple(validators)
|
||||
if extra is not None and extra != {}:
|
||||
_setattr(self, '_extra', extra)
|
||||
_setattr(self, "_extra", extra)
|
||||
if warnings_only is True:
|
||||
_setattr(self, '_warnings_only', warnings_only)
|
||||
_setattr(self, "_warnings_only", warnings_only)
|
||||
if is_multi and default_multi is not None:
|
||||
|
||||
def test_multi_value(value):
|
||||
if isinstance(value, Calculation):
|
||||
return
|
||||
# option_bag = OptionBag(self,
|
||||
# None,
|
||||
# undefined,
|
||||
# properties=None,
|
||||
# )
|
||||
# option_bag = OptionBag(self,
|
||||
# None,
|
||||
# undefined,
|
||||
# properties=None,
|
||||
# )
|
||||
try:
|
||||
self.validate(value)
|
||||
self.validate_with_option(value,
|
||||
self.validate_with_option(
|
||||
value,
|
||||
None,
|
||||
loaded=True,
|
||||
)
|
||||
except ValueError as err:
|
||||
str_err = str(err)
|
||||
if not str_err:
|
||||
raise ValueError(_('invalid default_multi value "{0}" '
|
||||
'for option {1}').format(str(value),
|
||||
self.impl_get_display_name(None, with_quote=True))
|
||||
raise ValueError(
|
||||
_(
|
||||
'invalid default_multi value "{0}" ' "for option {1}"
|
||||
).format(
|
||||
str(value),
|
||||
self.impl_get_display_name(None, with_quote=True),
|
||||
)
|
||||
) from err
|
||||
raise ValueError(_(f'invalid default_multi value "{value}" for option '
|
||||
f'{self.impl_get_display_name(None, with_quote=True)}, {str_err}')
|
||||
raise ValueError(
|
||||
_(
|
||||
'invalid default_multi value "{0}" for option {1}, {2}'
|
||||
).format(
|
||||
value,
|
||||
self.impl_get_display_name(None, with_quote=True),
|
||||
str_err,
|
||||
)
|
||||
) from err
|
||||
|
||||
if _multi is submulti:
|
||||
if not isinstance(default_multi, Calculation):
|
||||
if not isinstance(default_multi, list):
|
||||
raise ValueError(_('invalid default_multi value "{0}" '
|
||||
'for option {1}, must be a list for a submulti'
|
||||
'').format(str(default_multi),
|
||||
self.impl_get_display_name(None, with_quote=True)))
|
||||
raise ValueError(
|
||||
_(
|
||||
'invalid default_multi value "{0}" '
|
||||
"for option {1}, must be a list for a submulti"
|
||||
""
|
||||
).format(
|
||||
str(default_multi),
|
||||
self.impl_get_display_name(None, with_quote=True),
|
||||
)
|
||||
)
|
||||
for value in default_multi:
|
||||
test_multi_value(value)
|
||||
else:
|
||||
test_multi_value(default_multi)
|
||||
_setattr(self, '_default_multi', default_multi)
|
||||
# option_bag = OptionBag(self,
|
||||
# None,
|
||||
# undefined,
|
||||
# properties=None,
|
||||
# )
|
||||
self.impl_validate(None,
|
||||
_setattr(self, "_default_multi", default_multi)
|
||||
# option_bag = OptionBag(self,
|
||||
# None,
|
||||
# undefined,
|
||||
# properties=None,
|
||||
# )
|
||||
self.impl_validate(
|
||||
None,
|
||||
default,
|
||||
loaded=True,
|
||||
)
|
||||
self.impl_validate(None,
|
||||
self.impl_validate(
|
||||
None,
|
||||
default,
|
||||
check_error=False,
|
||||
loaded=True,
|
||||
)
|
||||
self.value_dependencies(default)
|
||||
if (is_multi and default != []) or \
|
||||
(not is_multi and default is not None):
|
||||
if (is_multi and default != []) or (not is_multi and default is not None):
|
||||
if is_multi and isinstance(default, list):
|
||||
default = tuple(default)
|
||||
_setattr(self, '_default', default)
|
||||
_setattr(self, "_default", default)
|
||||
|
||||
#__________________________________________________________________________
|
||||
# __________________________________________________________________________
|
||||
# option's information
|
||||
|
||||
def impl_is_multi(self) -> bool:
|
||||
"""is it a multi option
|
||||
"""
|
||||
return getattr(self, '_multi', 1) != 1
|
||||
"""is it a multi option"""
|
||||
return getattr(self, "_multi", 1) != 1
|
||||
|
||||
def impl_is_submulti(self) -> bool:
|
||||
"""is it a submulti option
|
||||
"""
|
||||
return getattr(self, '_multi', 1) == 2
|
||||
"""is it a submulti option"""
|
||||
return getattr(self, "_multi", 1) == 2
|
||||
|
||||
def impl_is_dynsymlinkoption(self) -> bool:
|
||||
"""is a dynsymlinkoption?
|
||||
"""
|
||||
"""is a dynsymlinkoption?"""
|
||||
return False
|
||||
|
||||
def get_type(self) -> str:
|
||||
"""get the type of option
|
||||
"""
|
||||
"""get the type of option"""
|
||||
return self._type
|
||||
|
||||
def impl_getdefault(self) -> Any:
|
||||
"""accessing the default value
|
||||
"""
|
||||
"""accessing the default value"""
|
||||
is_multi = self.impl_is_multi()
|
||||
default = getattr(self, '_default', undefined)
|
||||
default = getattr(self, "_default", undefined)
|
||||
if default is undefined:
|
||||
if is_multi:
|
||||
default = []
|
||||
|
@ -204,72 +233,77 @@ class Option(BaseOption):
|
|||
return default
|
||||
|
||||
def impl_getdefault_multi(self) -> Any:
|
||||
"""accessing the default value for a multi
|
||||
"""
|
||||
"""accessing the default value for a multi"""
|
||||
if self.impl_is_submulti():
|
||||
default_value = []
|
||||
else:
|
||||
default_value = None
|
||||
return getattr(self, '_default_multi', default_value)
|
||||
return getattr(self, "_default_multi", default_value)
|
||||
|
||||
def impl_get_extra(self,
|
||||
def impl_get_extra(
|
||||
self,
|
||||
key: str,
|
||||
) -> Any:
|
||||
"""if extra parameters are store get it
|
||||
"""
|
||||
extra = getattr(self, '_extra', {})
|
||||
"""if extra parameters are store get it"""
|
||||
extra = getattr(self, "_extra", {})
|
||||
if isinstance(extra, tuple):
|
||||
if key in extra[0]:
|
||||
return extra[1][extra[0].index(key)]
|
||||
return None
|
||||
return extra.get(key)
|
||||
|
||||
#__________________________________________________________________________
|
||||
# __________________________________________________________________________
|
||||
# validator
|
||||
def impl_validate(self,
|
||||
def impl_validate(
|
||||
self,
|
||||
subconfig: Optional["SubConfig"],
|
||||
value: Any,
|
||||
*,
|
||||
check_error: bool=True,
|
||||
loaded: bool=False,
|
||||
check_error: bool = True,
|
||||
loaded: bool = False,
|
||||
) -> bool:
|
||||
"""Return True if value is really valid
|
||||
If not validate or invalid return it returns False
|
||||
"""
|
||||
if check_error and subconfig and \
|
||||
not 'validator' in subconfig.config_bag.properties:
|
||||
if (
|
||||
check_error
|
||||
and subconfig
|
||||
and not "validator" in subconfig.config_bag.properties
|
||||
):
|
||||
return False
|
||||
if subconfig:
|
||||
force_index = subconfig.index
|
||||
else:
|
||||
force_index = None
|
||||
is_warnings_only = getattr(self, '_warnings_only', False)
|
||||
is_warnings_only = getattr(self, "_warnings_only", False)
|
||||
|
||||
def _is_not_unique(value):
|
||||
# if set(value) has not same length than value
|
||||
if not subconfig or not check_error or \
|
||||
'unique' not in subconfig.properties:
|
||||
if not subconfig or not check_error or "unique" not in subconfig.properties:
|
||||
return
|
||||
lvalue = [val for val in value if val is not None]
|
||||
if len(set(lvalue)) == len(lvalue):
|
||||
return
|
||||
for idx, val in enumerate(value):
|
||||
if val not in value[idx+1:]:
|
||||
if val not in value[idx + 1 :]:
|
||||
continue
|
||||
raise ValueError(_('the value "{}" is not unique'
|
||||
'').format(val))
|
||||
raise ValueError(_('the value "{}" is not unique' "").format(val))
|
||||
|
||||
def calculation_validator(val,
|
||||
def calculation_validator(
|
||||
val,
|
||||
_index,
|
||||
):
|
||||
for validator in getattr(self, '_validators', []):
|
||||
calc_is_warnings_only = hasattr(validator, 'warnings_only') and \
|
||||
validator.warnings_only
|
||||
if ((check_error and not calc_is_warnings_only) or
|
||||
(not check_error and calc_is_warnings_only)):
|
||||
for validator in getattr(self, "_validators", []):
|
||||
calc_is_warnings_only = (
|
||||
hasattr(validator, "warnings_only") and validator.warnings_only
|
||||
)
|
||||
if (check_error and not calc_is_warnings_only) or (
|
||||
not check_error and calc_is_warnings_only
|
||||
):
|
||||
try:
|
||||
kwargs = {'allow_value_error': True,
|
||||
'force_value_warning': calc_is_warnings_only,
|
||||
kwargs = {
|
||||
"allow_value_error": True,
|
||||
"force_value_warning": calc_is_warnings_only,
|
||||
}
|
||||
if _index is not None and subconfig.index == _index:
|
||||
lsubconfig = subconfig
|
||||
|
@ -277,21 +311,25 @@ class Option(BaseOption):
|
|||
identifier = subconfig.identifiers
|
||||
if identifier is not None:
|
||||
identifier = identifier[-1]
|
||||
lsubconfig = subconfig.parent.get_child(subconfig.option,
|
||||
lsubconfig = subconfig.parent.get_child(
|
||||
subconfig.option,
|
||||
_index,
|
||||
False,
|
||||
properties=subconfig.properties,
|
||||
identifier=identifier,
|
||||
name=subconfig.path.rsplit('.', 1)[-1],
|
||||
name=subconfig.path.rsplit(".", 1)[-1],
|
||||
check_index=False,
|
||||
)
|
||||
kwargs['orig_value'] = value
|
||||
kwargs["orig_value"] = value
|
||||
|
||||
validator.execute(lsubconfig,
|
||||
validator.execute(
|
||||
lsubconfig,
|
||||
**kwargs,
|
||||
)
|
||||
except ValueWarning as warn:
|
||||
warnings.warn_explicit(ValueWarning(subconfig,
|
||||
warnings.warn_explicit(
|
||||
ValueWarning(
|
||||
subconfig,
|
||||
val,
|
||||
_(self.get_type()),
|
||||
self,
|
||||
|
@ -299,65 +337,80 @@ class Option(BaseOption):
|
|||
_index,
|
||||
),
|
||||
ValueWarning,
|
||||
self.__class__.__name__, 319)
|
||||
self.__class__.__name__,
|
||||
319,
|
||||
)
|
||||
|
||||
def do_validation(_value,
|
||||
def do_validation(
|
||||
_value,
|
||||
_index,
|
||||
):
|
||||
#
|
||||
if _value is None:
|
||||
return
|
||||
if isinstance(_value, list):
|
||||
raise ValueError(_('which must not be a list'))
|
||||
raise ValueError(_("which must not be a list"))
|
||||
if isinstance(_value, Calculation) and not subconfig:
|
||||
return
|
||||
# option validation
|
||||
if check_error:
|
||||
self.validate(_value)
|
||||
self.validate_with_option(_value,
|
||||
self.validate_with_option(
|
||||
_value,
|
||||
subconfig,
|
||||
loaded=loaded,
|
||||
)
|
||||
# second level validation
|
||||
if (check_error and not is_warnings_only) or (not check_error and is_warnings_only):
|
||||
if (check_error and not is_warnings_only) or (
|
||||
not check_error and is_warnings_only
|
||||
):
|
||||
try:
|
||||
self.second_level_validation(_value,
|
||||
is_warnings_only)
|
||||
self.second_level_validation(_value, is_warnings_only)
|
||||
except ValueError as err:
|
||||
if is_warnings_only:
|
||||
warnings.warn_explicit(ValueWarning(subconfig,
|
||||
warnings.warn_explicit(
|
||||
ValueWarning(
|
||||
subconfig,
|
||||
_value,
|
||||
_(self.get_type()),
|
||||
self,
|
||||
str(err),
|
||||
_index),
|
||||
_index,
|
||||
),
|
||||
ValueWarning,
|
||||
self.__class__.__name__, 0)
|
||||
self.__class__.__name__,
|
||||
0,
|
||||
)
|
||||
else:
|
||||
raise err from err
|
||||
# ?
|
||||
if not loaded:
|
||||
calculation_validator(_value,
|
||||
calculation_validator(
|
||||
_value,
|
||||
_index,
|
||||
)
|
||||
|
||||
val = value
|
||||
err_index = force_index
|
||||
try:
|
||||
if not self.impl_is_multi():
|
||||
do_validation(val,
|
||||
do_validation(
|
||||
val,
|
||||
None,
|
||||
)
|
||||
elif force_index is not None:
|
||||
if self.impl_is_submulti():
|
||||
if not isinstance(value, list):
|
||||
raise ValueError(_('which must be a list'))
|
||||
raise ValueError(_("which must be a list"))
|
||||
for val in value:
|
||||
do_validation(val,
|
||||
do_validation(
|
||||
val,
|
||||
force_index,
|
||||
)
|
||||
_is_not_unique(value)
|
||||
else:
|
||||
do_validation(val,
|
||||
do_validation(
|
||||
val,
|
||||
force_index,
|
||||
)
|
||||
elif isinstance(value, Calculation) and not subconfig:
|
||||
|
@ -367,83 +420,79 @@ class Option(BaseOption):
|
|||
if isinstance(lval, Calculation):
|
||||
continue
|
||||
if not isinstance(lval, list):
|
||||
raise ValueError(_('which "{}" must be a list of list'
|
||||
'').format(lval))
|
||||
raise ValueError(
|
||||
_('which "{}" must be a list of list' "").format(lval)
|
||||
)
|
||||
for val in lval:
|
||||
do_validation(val,
|
||||
err_index)
|
||||
do_validation(val, err_index)
|
||||
_is_not_unique(lval)
|
||||
elif not isinstance(value, list):
|
||||
raise ValueError(_('which must be a list'))
|
||||
raise ValueError(_("which must be a list"))
|
||||
else:
|
||||
# FIXME suboptimal, not several time for whole=True!
|
||||
for err_index, val in enumerate(value):
|
||||
do_validation(val,
|
||||
do_validation(
|
||||
val,
|
||||
err_index,
|
||||
)
|
||||
_is_not_unique(value)
|
||||
except ValueError as err:
|
||||
if not subconfig or \
|
||||
'demoting_error_warning' not in subconfig.config_bag.properties:
|
||||
raise ValueOptionError(subconfig,
|
||||
val,
|
||||
_(self.get_type()),
|
||||
self,
|
||||
str(err),
|
||||
err_index) from err
|
||||
warnings.warn_explicit(ValueErrorWarning(subconfig,
|
||||
val,
|
||||
_(self.get_type()),
|
||||
self,
|
||||
str(err),
|
||||
err_index),
|
||||
if (
|
||||
not subconfig
|
||||
or "demoting_error_warning" not in subconfig.config_bag.properties
|
||||
):
|
||||
raise ValueOptionError(
|
||||
subconfig, val, _(self.get_type()), self, str(err), err_index
|
||||
) from err
|
||||
warnings.warn_explicit(
|
||||
ValueErrorWarning(
|
||||
subconfig, val, _(self.get_type()), self, str(err), err_index
|
||||
),
|
||||
ValueErrorWarning,
|
||||
self.__class__.__name__, 0)
|
||||
self.__class__.__name__,
|
||||
0,
|
||||
)
|
||||
return False
|
||||
return True
|
||||
|
||||
def validate_with_option(self,
|
||||
def validate_with_option(
|
||||
self,
|
||||
value: Any,
|
||||
subconfig: "SubConfig",
|
||||
*,
|
||||
loaded: bool,
|
||||
) -> None:
|
||||
"""validation function with option
|
||||
"""
|
||||
"""validation function with option"""
|
||||
|
||||
def second_level_validation(self,
|
||||
def second_level_validation(
|
||||
self,
|
||||
value: Any,
|
||||
warnings_only: bool,
|
||||
) -> None:
|
||||
"""less import validation function
|
||||
"""
|
||||
"""less import validation function"""
|
||||
|
||||
def impl_is_leader(self):
|
||||
"""check if option is a leader in a leadership
|
||||
"""
|
||||
"""check if option is a leader in a leadership"""
|
||||
leadership = self.impl_get_leadership()
|
||||
if leadership is None:
|
||||
return False
|
||||
return leadership.is_leader(self)
|
||||
|
||||
def impl_is_follower(self):
|
||||
"""check if option is a leader in a follower
|
||||
"""
|
||||
"""check if option is a leader in a follower"""
|
||||
leadership = self.impl_get_leadership()
|
||||
if leadership is None:
|
||||
return False
|
||||
return not leadership.is_leader(self)
|
||||
|
||||
def impl_get_leadership(self):
|
||||
"""get leadership
|
||||
"""
|
||||
leadership = getattr(self, '_leadership', None)
|
||||
"""get leadership"""
|
||||
leadership = getattr(self, "_leadership", None)
|
||||
if leadership is None:
|
||||
return leadership
|
||||
#pylint: disable=not-callable
|
||||
# pylint: disable=not-callable
|
||||
return leadership()
|
||||
|
||||
def validate(self, value: Any):
|
||||
"""option needs a validate function
|
||||
"""
|
||||
"""option needs a validate function"""
|
||||
raise NotImplementedError()
|
||||
|
|
|
@ -27,33 +27,34 @@ from typing import Optional, Iterator, Union, List, Dict
|
|||
from ..i18n import _
|
||||
from ..setting import ConfigBag, groups, undefined, owners, Undefined
|
||||
from .baseoption import BaseOption
|
||||
|
||||
# from .syndynoption import SubDynOptionDescription, SynDynOptionDescription
|
||||
from ..error import ConfigError, ConflictError
|
||||
|
||||
|
||||
class CacheOptionDescription(BaseOption):
|
||||
"""manage cache for option description
|
||||
"""
|
||||
__slots__ = ('_cache_force_store_values',
|
||||
'_cache_dependencies_information',
|
||||
"""manage cache for option description"""
|
||||
|
||||
__slots__ = (
|
||||
"_cache_force_store_values",
|
||||
"_cache_dependencies_information",
|
||||
)
|
||||
|
||||
def impl_already_build_caches(self) -> bool:
|
||||
"""is a readonly option?
|
||||
"""
|
||||
"""is a readonly option?"""
|
||||
return self.impl_is_readonly()
|
||||
|
||||
def _build_cache(self,
|
||||
def _build_cache(
|
||||
self,
|
||||
display_name,
|
||||
_consistencies=None,
|
||||
_consistencies_id=0,
|
||||
currpath: List[str]=None,
|
||||
currpath: List[str] = None,
|
||||
cache_option=None,
|
||||
force_store_values=None,
|
||||
dependencies_information=None,
|
||||
) -> None:
|
||||
"""validate options and set option has readonly option
|
||||
"""
|
||||
"""validate options and set option has readonly option"""
|
||||
# pylint: disable=too-many-branches,too-many-arguments
|
||||
# _consistencies is None only when we start to build cache
|
||||
if _consistencies is None:
|
||||
|
@ -69,16 +70,18 @@ class CacheOptionDescription(BaseOption):
|
|||
|
||||
if self.impl_is_readonly():
|
||||
# cache already set
|
||||
raise ConfigError(_('option description seems to be part of an other '
|
||||
'config'))
|
||||
raise ConfigError(
|
||||
_("option description seems to be part of an other " "config")
|
||||
)
|
||||
for option in self.get_children():
|
||||
if __debug__:
|
||||
cache_option.append(option)
|
||||
sub_currpath = currpath + [option.impl_getname()]
|
||||
subpath = '.'.join(sub_currpath)
|
||||
subpath = ".".join(sub_currpath)
|
||||
if isinstance(option, OptionDescription):
|
||||
# pylint: disable=protected-access
|
||||
option._build_cache(display_name,
|
||||
option._build_cache(
|
||||
display_name,
|
||||
_consistencies,
|
||||
_consistencies_id,
|
||||
sub_currpath,
|
||||
|
@ -91,78 +94,100 @@ class CacheOptionDescription(BaseOption):
|
|||
if informations:
|
||||
for param in informations.pop(None):
|
||||
del param.self_option
|
||||
for information, options in option.get_dependencies_information().items():
|
||||
for (
|
||||
information,
|
||||
options,
|
||||
) in option.get_dependencies_information().items():
|
||||
if None in options:
|
||||
dependencies_information.setdefault(information, []).append(option)
|
||||
dependencies_information.setdefault(information, []).append(
|
||||
option
|
||||
)
|
||||
properties = option.impl_getproperties()
|
||||
if 'force_store_value' in properties:
|
||||
if "force_store_value" in properties:
|
||||
force_store_values.append(option)
|
||||
if option.impl_is_readonly():
|
||||
raise ConflictError(_('duplicate option: {0}').format(option))
|
||||
raise ConflictError(_("duplicate option: {0}").format(option))
|
||||
if not self.impl_is_readonly() and display_name:
|
||||
option._display_name_function = display_name # pylint: disable=protected-access
|
||||
option._display_name_function = (
|
||||
display_name # pylint: disable=protected-access
|
||||
)
|
||||
option._path = subpath # pylint: disable=protected-access
|
||||
option._set_readonly() # pylint: disable=protected-access
|
||||
if init:
|
||||
self._cache_force_store_values = force_store_values # pylint: disable=attribute-defined-outside-init
|
||||
self._cache_force_store_values = (
|
||||
force_store_values # pylint: disable=attribute-defined-outside-init
|
||||
)
|
||||
self._cache_dependencies_information = dependencies_information # pylint: disable=attribute-defined-outside-init
|
||||
self._path = None # pylint: disable=attribute-defined-outside-init,no-member
|
||||
self._path = (
|
||||
None # pylint: disable=attribute-defined-outside-init,no-member
|
||||
)
|
||||
self._set_readonly()
|
||||
|
||||
def impl_build_force_store_values(self,
|
||||
def impl_build_force_store_values(
|
||||
self,
|
||||
config_bag: ConfigBag,
|
||||
) -> None:
|
||||
"""set value to force_store_values option
|
||||
"""
|
||||
"""set value to force_store_values option"""
|
||||
# pylint: disable=too-many-branches
|
||||
context = config_bag.context
|
||||
if 'force_store_value' not in config_bag.properties:
|
||||
if "force_store_value" not in config_bag.properties:
|
||||
return
|
||||
|
||||
values = config_bag.context.get_values()
|
||||
for option in self._cache_force_store_values:
|
||||
if option.issubdyn():
|
||||
paths = option.impl_getpath().split('.')
|
||||
paths = option.impl_getpath().split(".")
|
||||
parents = [config_bag.context.get_root(config_bag)]
|
||||
for name in paths:
|
||||
new_parents = []
|
||||
for parent in parents:
|
||||
doption = parent.option.get_child(name,
|
||||
doption = parent.option.get_child(
|
||||
name,
|
||||
config_bag,
|
||||
parent,
|
||||
allow_dynoption=True,
|
||||
)
|
||||
if doption.impl_is_dynoptiondescription():
|
||||
new_parents.extend(parent.dyn_to_subconfig(doption,
|
||||
new_parents.extend(
|
||||
parent.dyn_to_subconfig(
|
||||
doption,
|
||||
True,
|
||||
)
|
||||
)
|
||||
else:
|
||||
new_parents.append(parent.get_child(doption,
|
||||
new_parents.append(
|
||||
parent.get_child(
|
||||
doption,
|
||||
None,
|
||||
True,
|
||||
name=name,
|
||||
))
|
||||
)
|
||||
)
|
||||
parents = new_parents
|
||||
subconfigs = new_parents
|
||||
else:
|
||||
subconfigs = [context.get_sub_config(config_bag,
|
||||
subconfigs = [
|
||||
context.get_sub_config(
|
||||
config_bag,
|
||||
option.impl_getpath(),
|
||||
None,
|
||||
properties=None,
|
||||
validate_properties=False,
|
||||
)]
|
||||
)
|
||||
]
|
||||
|
||||
if option.impl_is_follower():
|
||||
for follower_subconfig in subconfigs:
|
||||
parent = follower_subconfig.parent
|
||||
follower_len = parent.get_length_leadership()
|
||||
for index in range(follower_len):
|
||||
if values.hasvalue(follower_subconfig.path,
|
||||
if values.hasvalue(
|
||||
follower_subconfig.path,
|
||||
index=index,
|
||||
):
|
||||
continue
|
||||
idx_follower_subconfig = parent.get_child(follower_subconfig.option,
|
||||
idx_follower_subconfig = parent.get_child(
|
||||
follower_subconfig.option,
|
||||
index,
|
||||
validate_properties=False,
|
||||
)
|
||||
|
@ -170,7 +195,8 @@ class CacheOptionDescription(BaseOption):
|
|||
value = values.get_value(idx_follower_subconfig)[0]
|
||||
if value is None:
|
||||
continue
|
||||
values.set_storage_value(follower_subconfig.path,
|
||||
values.set_storage_value(
|
||||
follower_subconfig.path,
|
||||
index,
|
||||
value,
|
||||
owners.forced,
|
||||
|
@ -183,7 +209,8 @@ class CacheOptionDescription(BaseOption):
|
|||
continue
|
||||
if values.hasvalue(subconfig.path):
|
||||
continue
|
||||
values.set_storage_value(subconfig.path,
|
||||
values.set_storage_value(
|
||||
subconfig.path,
|
||||
None,
|
||||
value,
|
||||
owners.forced,
|
||||
|
@ -191,42 +218,48 @@ class CacheOptionDescription(BaseOption):
|
|||
|
||||
|
||||
class OptionDescriptionWalk(CacheOptionDescription):
|
||||
"""get child of option description
|
||||
"""
|
||||
__slots__ = ('_children',)
|
||||
"""get child of option description"""
|
||||
|
||||
def get_path(self,
|
||||
__slots__ = ("_children",)
|
||||
|
||||
def get_path(
|
||||
self,
|
||||
config_bag,
|
||||
):
|
||||
if config_bag is undefined or \
|
||||
config_bag.context.get_description() == self:
|
||||
return ''
|
||||
if config_bag is undefined or config_bag.context.get_description() == self:
|
||||
return ""
|
||||
return self.impl_getpath()
|
||||
|
||||
def get_child_not_dynamic(self,
|
||||
def get_child_not_dynamic(
|
||||
self,
|
||||
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
|
||||
option = self._children[1][
|
||||
self._children[0].index(name)
|
||||
] # pylint: disable=no-member
|
||||
if option.impl_is_dynoptiondescription() and not allow_dynoption:
|
||||
raise AttributeError(_(f'unknown option "{name}" '
|
||||
"in root optiondescription (it's a dynamic option)"
|
||||
))
|
||||
raise AttributeError(
|
||||
_(
|
||||
'unknown option "{0}" in root optiondescription (it\'s a dynamic option)'
|
||||
).format(name)
|
||||
)
|
||||
return option
|
||||
|
||||
def get_child(self,
|
||||
def get_child(
|
||||
self,
|
||||
name: str,
|
||||
config_bag: ConfigBag,
|
||||
parent: 'SubConfig',
|
||||
parent: "SubConfig",
|
||||
*,
|
||||
with_identifier: bool=False,
|
||||
allow_dynoption: bool=False,
|
||||
with_identifier: bool = False,
|
||||
allow_dynoption: bool = False,
|
||||
) -> Union[BaseOption]:
|
||||
"""get a child
|
||||
"""
|
||||
"""get a child"""
|
||||
# if not dyn
|
||||
option = self.get_child_not_dynamic(name,
|
||||
option = self.get_child_not_dynamic(
|
||||
name,
|
||||
allow_dynoption,
|
||||
)
|
||||
if option:
|
||||
|
@ -242,39 +275,42 @@ class OptionDescriptionWalk(CacheOptionDescription):
|
|||
return child
|
||||
return identifier, child
|
||||
if self.impl_get_group_type() == groups.root: # pylint: disable=no-member
|
||||
raise AttributeError(_(f'unknown option "{name}" '
|
||||
'in root optiondescription'
|
||||
))
|
||||
raise AttributeError(_(f'unknown option "{name}" '
|
||||
f'in optiondescription {self.impl_get_display_name(parent, with_quote=True)}'
|
||||
))
|
||||
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
|
||||
"""
|
||||
"""get children"""
|
||||
return self._children[1]
|
||||
|
||||
def get_children_recursively(self,
|
||||
def get_children_recursively(
|
||||
self,
|
||||
bytype: Optional[BaseOption],
|
||||
byname: Optional[str],
|
||||
config_bag: ConfigBag,
|
||||
self_opt: BaseOption=None,
|
||||
self_opt: BaseOption = None,
|
||||
*,
|
||||
option_identifiers: Optional[list]=None
|
||||
option_identifiers: Optional[list] = None,
|
||||
) -> Iterator[Union[BaseOption]]:
|
||||
"""get children recursively
|
||||
"""
|
||||
"""get children recursively"""
|
||||
if self_opt is None:
|
||||
self_opt = self
|
||||
for option in self_opt.get_children():
|
||||
if option.impl_is_optiondescription():
|
||||
for subopt in option.get_children_recursively(bytype,
|
||||
for subopt in option.get_children_recursively(
|
||||
bytype,
|
||||
byname,
|
||||
config_bag,
|
||||
):
|
||||
yield subopt
|
||||
elif (byname is None or option.impl_getname() == byname) and \
|
||||
(bytype is None or isinstance(option, bytype)):
|
||||
elif (byname is None or option.impl_getname() == byname) and (
|
||||
bytype is None or isinstance(option, bytype)
|
||||
):
|
||||
yield option
|
||||
|
||||
|
||||
|
@ -282,24 +318,28 @@ class OptionDescription(OptionDescriptionWalk):
|
|||
"""Config's schema (organisation, group) and container of Options
|
||||
The `OptionsDescription` objects lives in the `tiramisu.config.Config`.
|
||||
"""
|
||||
__slots__ = ('_group_type',)
|
||||
|
||||
def __init__(self,
|
||||
__slots__ = ("_group_type",)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
doc: str,
|
||||
children: List[BaseOption],
|
||||
*,
|
||||
properties=None,
|
||||
informations: Optional[Dict]=None,
|
||||
group_type: Optional[groups.GroupType]=groups.default,
|
||||
informations: Optional[Dict] = None,
|
||||
group_type: Optional[groups.GroupType] = groups.default,
|
||||
) -> None:
|
||||
"""
|
||||
:param children: a list of options (including optiondescriptions)
|
||||
|
||||
"""
|
||||
assert isinstance(children, list), _('children in optiondescription "{}" '
|
||||
'must be a list').format(name)
|
||||
super().__init__(name,
|
||||
assert isinstance(children, list), _(
|
||||
'children in optiondescription "{}" ' "must be a list"
|
||||
).format(name)
|
||||
super().__init__(
|
||||
name,
|
||||
doc,
|
||||
informations,
|
||||
properties=properties,
|
||||
|
@ -322,20 +362,25 @@ class OptionDescription(OptionDescriptionWalk):
|
|||
old = None
|
||||
for child in child_names:
|
||||
if child == old:
|
||||
raise ConflictError(_('duplicate option name: '
|
||||
'"{0}"').format(child))
|
||||
raise ConflictError(
|
||||
_("duplicate option name: " '"{0}"').format(child)
|
||||
)
|
||||
if dynopt_names:
|
||||
for dynopt in dynopt_names:
|
||||
if child != dynopt and child.startswith(dynopt):
|
||||
raise ConflictError(_(f'the option\'s name "{child}" start as '
|
||||
f'the dynoptiondescription\'s name "{dynopt}"'))
|
||||
raise ConflictError(
|
||||
_(
|
||||
'the option\'s name "{0}" start as the dynoptiondescription\'s name "{1}"'
|
||||
).format(child, dynopt)
|
||||
)
|
||||
old = child
|
||||
self._children = children_
|
||||
# the group_type is useful for filtering OptionDescriptions in a config
|
||||
self._group_type = None
|
||||
self.impl_set_group_type(group_type)
|
||||
|
||||
def _setsubdyn(self,
|
||||
def _setsubdyn(
|
||||
self,
|
||||
subdyn,
|
||||
) -> None:
|
||||
for child in self._children[1]:
|
||||
|
@ -343,22 +388,20 @@ class OptionDescription(OptionDescriptionWalk):
|
|||
super()._setsubdyn(subdyn)
|
||||
|
||||
def impl_is_optiondescription(self) -> bool:
|
||||
"""the option is an option description
|
||||
"""
|
||||
"""the option is an option description"""
|
||||
return True
|
||||
|
||||
def impl_is_dynoptiondescription(self) -> bool:
|
||||
"""the option is not dynamic
|
||||
"""
|
||||
"""the option is not dynamic"""
|
||||
return False
|
||||
|
||||
def impl_is_leadership(self) -> bool:
|
||||
"""the option is not a leadership
|
||||
"""
|
||||
"""the option is not a leadership"""
|
||||
return False
|
||||
|
||||
# ____________________________________________________________
|
||||
def impl_set_group_type(self,
|
||||
def impl_set_group_type(
|
||||
self,
|
||||
group_type: groups.GroupType,
|
||||
) -> None:
|
||||
"""sets a given group object to an OptionDescription
|
||||
|
@ -368,22 +411,23 @@ class OptionDescription(OptionDescriptionWalk):
|
|||
"""
|
||||
if __debug__:
|
||||
if self._group_type is not None and self._group_type != groups.default:
|
||||
raise ValueError(_('cannot change group_type if already set '
|
||||
'(old {0}, new {1})').format(self._group_type,
|
||||
group_type))
|
||||
raise ValueError(
|
||||
_(
|
||||
"cannot change group_type if already set " "(old {0}, new {1})"
|
||||
).format(self._group_type, group_type)
|
||||
)
|
||||
if not isinstance(group_type, groups.GroupType):
|
||||
raise ValueError(_('group_type: {0}'
|
||||
' not allowed').format(group_type))
|
||||
raise ValueError(_("group_type: {0}" " not allowed").format(group_type))
|
||||
if isinstance(group_type, groups.LeadershipGroupType):
|
||||
raise ConfigError('please use Leadership object instead of OptionDescription')
|
||||
raise ConfigError(
|
||||
"please use Leadership object instead of OptionDescription"
|
||||
)
|
||||
self._group_type = group_type
|
||||
|
||||
def impl_get_group_type(self) -> groups.GroupType:
|
||||
"""get the group type of option description
|
||||
"""
|
||||
"""get the group type of option description"""
|
||||
return self._group_type
|
||||
|
||||
def impl_is_dynsymlinkoption(self) -> bool:
|
||||
"""option is not a dyn symlink option
|
||||
"""
|
||||
"""option is not a dyn symlink option"""
|
||||
return False
|
||||
|
|
|
@ -26,7 +26,7 @@ from .stroption import StrOption
|
|||
|
||||
|
||||
class PasswordOption(StrOption):
|
||||
"""represents the choice of a password
|
||||
"""
|
||||
"""represents the choice of a password"""
|
||||
|
||||
__slots__ = tuple()
|
||||
_type = 'password'
|
||||
_type = "password"
|
||||
|
|
|
@ -33,27 +33,25 @@ class PermissionsOption(IntOption):
|
|||
If a fourth digit is present to the setuid bit, the setgid bit and the sticky bit attributes.
|
||||
This option is an integer value.
|
||||
"""
|
||||
|
||||
__slots__ = tuple()
|
||||
perm_re = re.compile(r"^[0-7]{3,4}$")
|
||||
_type = 'unix file permissions'
|
||||
_type = "unix file permissions"
|
||||
|
||||
def __init__(self,
|
||||
def __init__(
|
||||
self,
|
||||
*args,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
#do not display intoption attributs
|
||||
super().__init__(*args,
|
||||
**kwargs)
|
||||
# do not display intoption attributs
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def validate(self,
|
||||
value: str) -> None:
|
||||
def validate(self, value: str) -> None:
|
||||
super().validate(value)
|
||||
if not self.perm_re.search(str(value)):
|
||||
raise ValueError(_('only 3 or 4 octal digits are allowed'))
|
||||
raise ValueError(_("only 3 or 4 octal digits are allowed"))
|
||||
|
||||
def second_level_validation(self,
|
||||
value: str,
|
||||
warnings_only: bool) -> None:
|
||||
def second_level_validation(self, value: str, warnings_only: bool) -> None:
|
||||
old_digit = 7
|
||||
str_value = str(value)
|
||||
if len(str_value) == 4:
|
||||
|
@ -62,12 +60,12 @@ class PermissionsOption(IntOption):
|
|||
new_digit = int(digit)
|
||||
if old_digit < new_digit:
|
||||
if idx == 1:
|
||||
old = _('user')
|
||||
new = _('group')
|
||||
old = _("user")
|
||||
new = _("group")
|
||||
else:
|
||||
old = _('group')
|
||||
new = _('other')
|
||||
raise ValueError(_(f'{new} has more right than {old}'))
|
||||
old = _("group")
|
||||
new = _("other")
|
||||
raise ValueError(_("{0} has more right than {1}").format(new, old))
|
||||
old_digit = new_digit
|
||||
if str_value == '777':
|
||||
raise ValueError(_('too weak'))
|
||||
if str_value == "777":
|
||||
raise ValueError(_("too weak"))
|
||||
|
|
|
@ -36,62 +36,64 @@ class PortOption(StrOption):
|
|||
Port number 0 is reserved and can't be used.
|
||||
see: http://en.wikipedia.org/wiki/Port_numbers
|
||||
"""
|
||||
|
||||
__slots__ = tuple()
|
||||
port_re = re.compile(r"^[0-9]*$")
|
||||
_type = 'port'
|
||||
_type = "port"
|
||||
|
||||
def __init__(self,
|
||||
def __init__(
|
||||
self,
|
||||
*args,
|
||||
allow_range: bool=False,
|
||||
allow_zero: bool=False,
|
||||
allow_wellknown: bool=True,
|
||||
allow_registred: bool=True,
|
||||
allow_protocol: bool=False,
|
||||
allow_private: bool=False,
|
||||
**kwargs) -> None:
|
||||
allow_range: bool = False,
|
||||
allow_zero: bool = False,
|
||||
allow_wellknown: bool = True,
|
||||
allow_registred: bool = True,
|
||||
allow_protocol: bool = False,
|
||||
allow_private: bool = False,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
|
||||
extra = {'_allow_range': allow_range,
|
||||
'_allow_protocol': allow_protocol,
|
||||
'_min_value': None,
|
||||
'_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
|
||||
for index, allowed in enumerate([allow_zero,
|
||||
allow_wellknown,
|
||||
allow_registred,
|
||||
allow_private]):
|
||||
if extra['_min_value'] is None:
|
||||
for index, allowed in enumerate(
|
||||
[allow_zero, allow_wellknown, allow_registred, allow_private]
|
||||
):
|
||||
if extra["_min_value"] is None:
|
||||
if allowed:
|
||||
extra['_min_value'] = ports_min[index]
|
||||
extra["_min_value"] = ports_min[index]
|
||||
elif not allowed:
|
||||
is_finally = True
|
||||
elif allowed and is_finally:
|
||||
raise ValueError(_('inconsistency in allowed range'))
|
||||
raise ValueError(_("inconsistency in allowed range"))
|
||||
if allowed:
|
||||
extra['_max_value'] = ports_max[index]
|
||||
extra["_max_value"] = ports_max[index]
|
||||
|
||||
if extra['_max_value'] is None:
|
||||
raise ValueError(_('max value is empty'))
|
||||
if extra["_max_value"] is None:
|
||||
raise ValueError(_("max value is empty"))
|
||||
|
||||
super().__init__(*args,
|
||||
extra=extra,
|
||||
**kwargs)
|
||||
super().__init__(*args, extra=extra, **kwargs)
|
||||
|
||||
def validate(self,
|
||||
value: str) -> None:
|
||||
def validate(self, value: str) -> None:
|
||||
super().validate(value)
|
||||
if self.impl_get_extra('_allow_protocol') and (value.startswith('tcp:') or
|
||||
value.startswith('udp:')):
|
||||
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):
|
||||
value = value.split(':')
|
||||
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'))
|
||||
raise ValueError(_("range must have two values only"))
|
||||
if not value[0] < value[1]:
|
||||
raise ValueError(_('first port in range must be'
|
||||
' smaller than the second one'))
|
||||
raise ValueError(
|
||||
_("first port in range must be" " smaller than the second one")
|
||||
)
|
||||
else:
|
||||
value = [value]
|
||||
|
||||
|
@ -99,22 +101,29 @@ class PortOption(StrOption):
|
|||
if not self.port_re.search(val):
|
||||
raise ValueError()
|
||||
|
||||
def second_level_validation(self,
|
||||
value: str,
|
||||
warnings_only: bool) -> None:
|
||||
if self.impl_get_extra('_allow_protocol') and (value.startswith('tcp:') or
|
||||
value.startswith('udp:')):
|
||||
def second_level_validation(self, value: str, warnings_only: bool) -> None:
|
||||
if self.impl_get_extra("_allow_protocol") and (
|
||||
value.startswith("tcp:") or value.startswith("udp:")
|
||||
):
|
||||
value = [value[4:]]
|
||||
elif ':' in value:
|
||||
value = value.split(':')
|
||||
elif ":" in value:
|
||||
value = value.split(":")
|
||||
else:
|
||||
value = [value]
|
||||
for val in value:
|
||||
val = int(val)
|
||||
if not self.impl_get_extra('_min_value') <= val <= self.impl_get_extra('_max_value'):
|
||||
if (
|
||||
not self.impl_get_extra("_min_value")
|
||||
<= val
|
||||
<= self.impl_get_extra("_max_value")
|
||||
):
|
||||
if warnings_only:
|
||||
msg = 'should be between {0} and {1}'
|
||||
msg = _("should be between {0} and {1}")
|
||||
else:
|
||||
msg = 'must be between {0} and {1}'
|
||||
raise ValueError(_(msg).format(self.impl_get_extra('_min_value'),
|
||||
self.impl_get_extra('_max_value')))
|
||||
msg = _("must be between {0} and {1}")
|
||||
raise ValueError(
|
||||
msg.format(
|
||||
self.impl_get_extra("_min_value"),
|
||||
self.impl_get_extra("_max_value"),
|
||||
)
|
||||
)
|
||||
|
|
|
@ -27,31 +27,31 @@ from .option import Option
|
|||
|
||||
|
||||
class StrOption(Option):
|
||||
"""represents a string
|
||||
"""
|
||||
__slots__ = tuple()
|
||||
_type = 'string'
|
||||
"""represents a string"""
|
||||
|
||||
def validate(self,
|
||||
__slots__ = tuple()
|
||||
_type = "string"
|
||||
|
||||
def validate(
|
||||
self,
|
||||
value: str,
|
||||
) -> None:
|
||||
"""validation
|
||||
"""
|
||||
"""validation"""
|
||||
if not isinstance(value, str):
|
||||
raise ValueError()
|
||||
|
||||
|
||||
class RegexpOption(StrOption):
|
||||
"""regexp validation, this is base option use to do a custom's one
|
||||
"""
|
||||
"""regexp validation, this is base option use to do a custom's one"""
|
||||
|
||||
__slots__ = tuple()
|
||||
|
||||
def validate(self,
|
||||
def validate(
|
||||
self,
|
||||
value: Any,
|
||||
) -> None:
|
||||
# pylint: disable=no-member
|
||||
"""validation
|
||||
"""
|
||||
"""validation"""
|
||||
super().validate(value)
|
||||
match = self._regexp.search(value)
|
||||
if not match:
|
||||
|
|
|
@ -27,61 +27,66 @@ from ..i18n import _
|
|||
|
||||
|
||||
class SymLinkOption(BaseOption):
|
||||
"""SymLinkOption link to an other option
|
||||
"""
|
||||
__slots__ = ('_opt',
|
||||
'_leadership',
|
||||
"""SymLinkOption link to an other option"""
|
||||
|
||||
__slots__ = (
|
||||
"_opt",
|
||||
"_leadership",
|
||||
)
|
||||
|
||||
def __init__(self,
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
opt: BaseOption,
|
||||
) -> None:
|
||||
# pylint: disable=super-init-not-called
|
||||
if not valid_name(name):
|
||||
raise ValueError(_('"{0}" is an invalid name for an option').format(name))
|
||||
if not isinstance(opt, BaseOption) or \
|
||||
opt.impl_is_optiondescription() or \
|
||||
opt.impl_is_symlinkoption():
|
||||
raise ValueError(_(f'malformed symlink second parameters must be an option for "{name}", not {opt}'))
|
||||
if (
|
||||
not isinstance(opt, BaseOption)
|
||||
or opt.impl_is_optiondescription()
|
||||
or opt.impl_is_symlinkoption()
|
||||
):
|
||||
raise ValueError(
|
||||
_(
|
||||
'malformed symlink second parameters must be an option for "{0}", not {1}'
|
||||
).format(name, opt)
|
||||
)
|
||||
self._name = name
|
||||
self._opt = opt
|
||||
self._leadership = None
|
||||
opt._add_dependency(self)
|
||||
|
||||
def __getattr__(self,
|
||||
def __getattr__(
|
||||
self,
|
||||
name: str,
|
||||
) -> Any:
|
||||
if name == '_subdyns':
|
||||
if name == "_subdyns":
|
||||
return None
|
||||
if name == '_path':
|
||||
if name == "_path":
|
||||
raise AttributeError()
|
||||
return getattr(self._opt, name)
|
||||
|
||||
def impl_is_symlinkoption(self) -> bool:
|
||||
"""it's a symlinkoption
|
||||
"""
|
||||
"""it's a symlinkoption"""
|
||||
return True
|
||||
|
||||
def impl_is_leader(self) -> bool:
|
||||
return False
|
||||
|
||||
def impl_is_follower(self):
|
||||
"""check if option is a leader in a follower
|
||||
"""
|
||||
"""check if option is a leader in a follower"""
|
||||
leadership = self._leadership
|
||||
if leadership is None:
|
||||
return False
|
||||
return not leadership().is_leader(self)
|
||||
|
||||
def impl_getopt(self) -> BaseOption:
|
||||
"""get to linked option
|
||||
"""
|
||||
"""get to linked option"""
|
||||
return self._opt
|
||||
|
||||
def impl_is_multi(self) -> bool:
|
||||
"""is it a multi?
|
||||
"""
|
||||
"""is it a multi?"""
|
||||
if self._opt.impl_is_multi():
|
||||
return True
|
||||
if self._opt.issubdyn() or self.issubdyn():
|
||||
|
@ -91,6 +96,5 @@ class SymLinkOption(BaseOption):
|
|||
return False
|
||||
|
||||
def impl_is_submulti(self) -> bool:
|
||||
"""is it a submulti?
|
||||
"""
|
||||
"""is it a submulti?"""
|
||||
return self._opt.impl_is_submulti()
|
||||
|
|
|
@ -32,93 +32,97 @@ from .portoption import PortOption
|
|||
|
||||
|
||||
class URLOption(StrOption):
|
||||
"""URLOption to check url value
|
||||
"""
|
||||
"""URLOption to check url value"""
|
||||
|
||||
__slots__ = tuple()
|
||||
path_re = re.compile(r"^[A-Za-z0-9\-\._~:/\?#\[\]@!%\$&\'\(\)\*\+,;=]+$")
|
||||
_type = 'URL'
|
||||
_type = "URL"
|
||||
|
||||
def __init__(self,
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
doc: str,
|
||||
*args,
|
||||
allow_ip: bool=False,
|
||||
type: str='domainname',
|
||||
allow_ip: bool = False,
|
||||
type: str = "domainname",
|
||||
allow_without_dot=False,
|
||||
allow_range: bool=False,
|
||||
allow_zero: bool=False,
|
||||
allow_wellknown: bool=True,
|
||||
allow_registred: bool=True,
|
||||
allow_private: bool=False,
|
||||
allow_range: bool = False,
|
||||
allow_zero: bool = False,
|
||||
allow_wellknown: bool = True,
|
||||
allow_registred: bool = True,
|
||||
allow_private: bool = False,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
# pylint: disable=too-many-arguments,too-many-locals,redefined-builtin
|
||||
extra = {'_domainname': DomainnameOption(name,
|
||||
extra = {
|
||||
"_domainname": DomainnameOption(
|
||||
name,
|
||||
doc,
|
||||
allow_ip=allow_ip,
|
||||
type=type,
|
||||
allow_without_dot=allow_without_dot),
|
||||
'_port': PortOption(name,
|
||||
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,
|
||||
allow_private=allow_private,
|
||||
),
|
||||
}
|
||||
super().__init__(
|
||||
name,
|
||||
doc,
|
||||
extra=extra,
|
||||
*args,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
def _get_domain_port_files(self,
|
||||
value: str) -> (str, str):
|
||||
if value.startswith('http://'):
|
||||
type_ = 'http'
|
||||
def _get_domain_port_files(self, value: str) -> (str, str):
|
||||
if value.startswith("http://"):
|
||||
type_ = "http"
|
||||
value = value[7:]
|
||||
elif value.startswith('https://'):
|
||||
type_ = 'https'
|
||||
elif value.startswith("https://"):
|
||||
type_ = "https"
|
||||
value = value[8:]
|
||||
else:
|
||||
raise ValueError(_('must start with http:// or '
|
||||
'https://'))
|
||||
raise ValueError(_("must start with http:// or " "https://"))
|
||||
# get domain/files
|
||||
splitted = value.split('/', 1)
|
||||
splitted = value.split("/", 1)
|
||||
if len(splitted) == 1:
|
||||
domain = value
|
||||
files = None
|
||||
else:
|
||||
domain, files = splitted
|
||||
# if port in domain
|
||||
splitted = domain.split(':', 1)
|
||||
splitted = domain.split(":", 1)
|
||||
if len(splitted) == 1:
|
||||
domain = splitted[0]
|
||||
port = {'http': '80',
|
||||
'https': '443'}[type_]
|
||||
port = {"http": "80", "https": "443"}[type_]
|
||||
else:
|
||||
domain, port = splitted
|
||||
return domain, port, files
|
||||
|
||||
def validate(self,
|
||||
value: str) -> None:
|
||||
def validate(self, value: str) -> None:
|
||||
super().validate(value)
|
||||
domain, port, files = self._get_domain_port_files(value)
|
||||
# validate port
|
||||
portoption = self.impl_get_extra('_port')
|
||||
portoption = self.impl_get_extra("_port")
|
||||
portoption.validate(port)
|
||||
# validate domainname
|
||||
domainnameoption = self.impl_get_extra('_domainname')
|
||||
domainnameoption = self.impl_get_extra("_domainname")
|
||||
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'))
|
||||
if files is not None and files != "" and not self.path_re.search(files):
|
||||
raise ValueError(_("must ends with a valid resource name"))
|
||||
|
||||
def second_level_validation(self, value, warnings_only):
|
||||
domain, port, _ = self._get_domain_port_files(value)
|
||||
# validate port
|
||||
portoption = self.impl_get_extra('_port')
|
||||
portoption = self.impl_get_extra("_port")
|
||||
portoption.second_level_validation(port, warnings_only)
|
||||
# validate domainname
|
||||
domainnameoption = self.impl_get_extra('_domainname')
|
||||
domainnameoption = self.impl_get_extra("_domainname")
|
||||
domainnameoption.second_level_validation(domain, warnings_only)
|
||||
|
|
|
@ -27,16 +27,16 @@ from .stroption import RegexpOption
|
|||
|
||||
|
||||
class UsernameOption(RegexpOption):
|
||||
"""UsernameOption to check unix username value
|
||||
"""
|
||||
"""UsernameOption to check unix username value"""
|
||||
|
||||
__slots__ = tuple()
|
||||
#regexp build with 'man 8 adduser' informations
|
||||
# regexp build with 'man 8 adduser' informations
|
||||
_regexp = re.compile(r"^[a-z_][a-z0-9_-]{0,30}[$a-z0-9_-]{0,1}$")
|
||||
_type = 'unix username'
|
||||
_type = "unix username"
|
||||
|
||||
|
||||
class GroupnameOption(UsernameOption):
|
||||
"""GroupnameOption to check unix group value
|
||||
"""
|
||||
"""GroupnameOption to check unix group value"""
|
||||
|
||||
__slots__ = tuple()
|
||||
_type = 'unix groupname'
|
||||
_type = "unix groupname"
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -26,14 +26,17 @@ class Values:
|
|||
"""This class manage value (default value, stored value or calculated value
|
||||
It's also responsible of a caching utility.
|
||||
"""
|
||||
|
||||
# pylint: disable=too-many-public-methods
|
||||
__slots__ = ('_values',
|
||||
'_informations',
|
||||
'__weakref__',
|
||||
__slots__ = (
|
||||
"_values",
|
||||
"_informations",
|
||||
"__weakref__",
|
||||
)
|
||||
|
||||
def __init__(self,
|
||||
default_values: Union[None, dict]=None,
|
||||
def __init__(
|
||||
self,
|
||||
default_values: Union[None, dict] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initializes the values's dict.
|
||||
|
@ -47,9 +50,10 @@ class Values:
|
|||
default_values = {None: {None: [None, owners.user]}}
|
||||
self._values = default_values
|
||||
|
||||
#______________________________________________________________________
|
||||
# ______________________________________________________________________
|
||||
# get value
|
||||
def get_cached_value(self,
|
||||
def get_cached_value(
|
||||
self,
|
||||
subconfig: "SubConfig",
|
||||
) -> Any:
|
||||
"""get value directly in cache if set
|
||||
|
@ -60,26 +64,30 @@ class Values:
|
|||
# try to retrive value in cache
|
||||
setting_properties = subconfig.config_bag.properties
|
||||
cache = subconfig.config_bag.context.get_values_cache()
|
||||
is_cached, value, validated = cache.getcache(subconfig,
|
||||
'values',
|
||||
is_cached, value, validated = cache.getcache(
|
||||
subconfig,
|
||||
"values",
|
||||
)
|
||||
# no cached value so get value
|
||||
if not is_cached:
|
||||
value, has_calculation = self.get_value(subconfig)
|
||||
# validates and warns value
|
||||
if not validated:
|
||||
validate = subconfig.option.impl_validate(subconfig,
|
||||
validate = subconfig.option.impl_validate(
|
||||
subconfig,
|
||||
value,
|
||||
check_error=True,
|
||||
)
|
||||
if 'warnings' in setting_properties:
|
||||
subconfig.option.impl_validate(subconfig,
|
||||
if "warnings" in setting_properties:
|
||||
subconfig.option.impl_validate(
|
||||
subconfig,
|
||||
value,
|
||||
check_error=False,
|
||||
)
|
||||
# set value to cache
|
||||
if not is_cached and not has_calculation:
|
||||
cache.setcache(subconfig,
|
||||
cache.setcache(
|
||||
subconfig,
|
||||
value,
|
||||
validated=validate,
|
||||
)
|
||||
|
@ -89,7 +97,8 @@ class Values:
|
|||
# and return it
|
||||
return value
|
||||
|
||||
def get_value(self,
|
||||
def get_value(
|
||||
self,
|
||||
subconfig: "SubConfig",
|
||||
) -> Any:
|
||||
"""actually retrieves the stored value or the default value (value modified by user)
|
||||
|
@ -98,20 +107,27 @@ class Values:
|
|||
"""
|
||||
# get owner and value from store
|
||||
default_value = [undefined, owners.default]
|
||||
value, owner = self._values.get(subconfig.path, {}).get(subconfig.index, default_value)
|
||||
if owner == owners.default or \
|
||||
('frozen' in subconfig.properties and \
|
||||
('force_default_on_freeze' in subconfig.properties or \
|
||||
self.check_force_to_metaconfig(subconfig))):
|
||||
value, owner = self._values.get(subconfig.path, {}).get(
|
||||
subconfig.index, default_value
|
||||
)
|
||||
if owner == owners.default or (
|
||||
"frozen" in subconfig.properties
|
||||
and (
|
||||
"force_default_on_freeze" in subconfig.properties
|
||||
or self.check_force_to_metaconfig(subconfig)
|
||||
)
|
||||
):
|
||||
# the value is a default value
|
||||
# get it
|
||||
value = self.get_default_value(subconfig)
|
||||
value, has_calculation = get_calculated_value(subconfig,
|
||||
value, has_calculation = get_calculated_value(
|
||||
subconfig,
|
||||
value,
|
||||
)
|
||||
return value, has_calculation
|
||||
|
||||
def get_default_value(self,
|
||||
def get_default_value(
|
||||
self,
|
||||
subconfig: "SubConfig",
|
||||
) -> Any:
|
||||
"""get default value:
|
||||
|
@ -122,15 +138,24 @@ class Values:
|
|||
msubconfig = self._get_modified_parent(subconfig)
|
||||
if msubconfig is not None:
|
||||
# retrieved value from parent config
|
||||
return msubconfig.config_bag.context.get_values().get_cached_value(msubconfig)
|
||||
return msubconfig.config_bag.context.get_values().get_cached_value(
|
||||
msubconfig
|
||||
)
|
||||
|
||||
# now try to get calculated value:
|
||||
value, _has_calculation = get_calculated_value(subconfig,
|
||||
value, _has_calculation = get_calculated_value(
|
||||
subconfig,
|
||||
subconfig.option.impl_getdefault(),
|
||||
)
|
||||
if subconfig.index is not None and isinstance(value, (list, tuple)) \
|
||||
and (not subconfig.option.impl_is_submulti() or \
|
||||
not value or isinstance(value[0], list)):
|
||||
if (
|
||||
subconfig.index is not None
|
||||
and isinstance(value, (list, tuple))
|
||||
and (
|
||||
not subconfig.option.impl_is_submulti()
|
||||
or not value
|
||||
or isinstance(value[0], list)
|
||||
)
|
||||
):
|
||||
# if index (so slave), must return good value for this index
|
||||
# for submulti, first index is a list, assume other data are list too
|
||||
index = subconfig.index
|
||||
|
@ -139,44 +164,48 @@ class Values:
|
|||
else:
|
||||
# no value for this index, retrieve default multi value
|
||||
# default_multi is already a list for submulti
|
||||
value, _has_calculation = get_calculated_value(subconfig,
|
||||
value, _has_calculation = get_calculated_value(
|
||||
subconfig,
|
||||
subconfig.option.impl_getdefault_multi(),
|
||||
)
|
||||
self.reset_cache_after_calculation(subconfig,
|
||||
self.reset_cache_after_calculation(
|
||||
subconfig,
|
||||
value,
|
||||
)
|
||||
return value
|
||||
|
||||
#______________________________________________________________________
|
||||
def check_force_to_metaconfig(self,
|
||||
# ______________________________________________________________________
|
||||
def check_force_to_metaconfig(
|
||||
self,
|
||||
subconfig: "OptionBag",
|
||||
) -> bool:
|
||||
"""Check if the value must be retrieve from parent metaconfig or not
|
||||
"""
|
||||
"""Check if the value must be retrieve from parent metaconfig or not"""
|
||||
# force_metaconfig_on_freeze is set to an option and context is a kernelconfig
|
||||
# => to metaconfig
|
||||
# force_metaconfig_on_freeze is set *explicitly* to an option and context is a
|
||||
# kernelmetaconfig => to sub metaconfig
|
||||
if 'force_metaconfig_on_freeze' in subconfig.properties:
|
||||
if "force_metaconfig_on_freeze" in subconfig.properties:
|
||||
settings = subconfig.config_bag.context.get_settings()
|
||||
if subconfig.config_bag.context.impl_type == 'config':
|
||||
if subconfig.config_bag.context.impl_type == "config":
|
||||
return True
|
||||
# it's a not a config, force to metaconfig only in *explicitly* set
|
||||
return 'force_metaconfig_on_freeze' in settings.get_stored_properties(subconfig.path,
|
||||
return "force_metaconfig_on_freeze" in settings.get_stored_properties(
|
||||
subconfig.path,
|
||||
subconfig.index,
|
||||
frozenset(),
|
||||
)
|
||||
return False
|
||||
|
||||
def reset_cache_after_calculation(self,
|
||||
def reset_cache_after_calculation(
|
||||
self,
|
||||
subconfig,
|
||||
value,
|
||||
):
|
||||
"""if value is modification after calculation, invalid cache
|
||||
"""
|
||||
"""if value is modification after calculation, invalid cache"""
|
||||
cache = subconfig.config_bag.context.get_values_cache()
|
||||
is_cache, cache_value, _ = cache.getcache(subconfig,
|
||||
'values',
|
||||
is_cache, cache_value, _ = cache.getcache(
|
||||
subconfig,
|
||||
"values",
|
||||
expiration=False,
|
||||
)
|
||||
if not is_cache or cache_value == value:
|
||||
|
@ -186,17 +215,18 @@ class Values:
|
|||
# calculated value is a new value, so reset cache
|
||||
subconfig.config_bag.context.reset_cache(subconfig)
|
||||
# and manage force_store_value
|
||||
self._set_force_value_identifier(subconfig,
|
||||
self._set_force_value_identifier(
|
||||
subconfig,
|
||||
value,
|
||||
)
|
||||
|
||||
def isempty(self,
|
||||
def isempty(
|
||||
self,
|
||||
subconfig: "SubConfig",
|
||||
value: Any,
|
||||
force_allow_empty_list: bool,
|
||||
) -> bool:
|
||||
"""convenience method to know if an option is empty
|
||||
"""
|
||||
"""convenience method to know if an option is empty"""
|
||||
index = subconfig.index
|
||||
option = subconfig.option
|
||||
if index is None and option.impl_is_submulti():
|
||||
|
@ -206,134 +236,158 @@ class Values:
|
|||
isempty = self._isempty_multi(val, force_allow_empty_list)
|
||||
if isempty:
|
||||
break
|
||||
elif (index is None or \
|
||||
(index is not None and option.impl_is_submulti())) and \
|
||||
option.impl_is_multi():
|
||||
elif (
|
||||
index is None or (index is not None and option.impl_is_submulti())
|
||||
) and option.impl_is_multi():
|
||||
# it's a single list
|
||||
isempty = self._isempty_multi(value, force_allow_empty_list)
|
||||
else:
|
||||
isempty = value is None or value == ''
|
||||
isempty = value is None or value == ""
|
||||
return isempty
|
||||
|
||||
def _isempty_multi(self,
|
||||
def _isempty_multi(
|
||||
self,
|
||||
value: Any,
|
||||
force_allow_empty_list: bool,
|
||||
) -> bool:
|
||||
if not isinstance(value, list):
|
||||
return False
|
||||
return (not force_allow_empty_list and value == []) or None in value or '' in value
|
||||
return (
|
||||
(not force_allow_empty_list and value == []) or None in value or "" in value
|
||||
)
|
||||
|
||||
#______________________________________________________________________
|
||||
# ______________________________________________________________________
|
||||
# set value
|
||||
def set_value(self,
|
||||
def set_value(
|
||||
self,
|
||||
subconfig: "SubConfig",
|
||||
value: Any,
|
||||
) -> None:
|
||||
"""set value to option
|
||||
"""
|
||||
"""set value to option"""
|
||||
owner = self.get_context_owner()
|
||||
setting_properties = subconfig.config_bag.properties
|
||||
ori_value = value
|
||||
if 'validator' in setting_properties:
|
||||
value, has_calculation = self.setvalue_validation(subconfig,
|
||||
if "validator" in setting_properties:
|
||||
value, has_calculation = self.setvalue_validation(
|
||||
subconfig,
|
||||
value,
|
||||
)
|
||||
|
||||
elif isinstance(value, list):
|
||||
# copy
|
||||
value = value.copy()
|
||||
self._setvalue(subconfig,
|
||||
self._setvalue(
|
||||
subconfig,
|
||||
ori_value,
|
||||
owner,
|
||||
)
|
||||
if 'force_store_value' in setting_properties and subconfig.option.impl_is_leader():
|
||||
if (
|
||||
"force_store_value" in setting_properties
|
||||
and subconfig.option.impl_is_leader()
|
||||
):
|
||||
leader = subconfig.option.impl_get_leadership()
|
||||
parent = subconfig.parent
|
||||
parent._length = len(value)
|
||||
leader.follower_force_store_value(value,
|
||||
leader.follower_force_store_value(
|
||||
value,
|
||||
parent,
|
||||
owners.forced,
|
||||
)
|
||||
validator = 'validator' in setting_properties and \
|
||||
'demoting_error_warning' not in setting_properties
|
||||
validator = (
|
||||
"validator" in setting_properties
|
||||
and "demoting_error_warning" not in setting_properties
|
||||
)
|
||||
if validator and not has_calculation:
|
||||
cache = subconfig.config_bag.context.get_values_cache()
|
||||
cache.setcache(subconfig,
|
||||
cache.setcache(
|
||||
subconfig,
|
||||
value,
|
||||
validated=validator,
|
||||
)
|
||||
elif 'validator' in setting_properties and has_calculation:
|
||||
elif "validator" in setting_properties and has_calculation:
|
||||
cache = subconfig.config_bag.context.get_values_cache()
|
||||
cache.delcache(subconfig.path)
|
||||
|
||||
def setvalue_validation(self,
|
||||
def setvalue_validation(
|
||||
self,
|
||||
subconfig: "SubConfig",
|
||||
value: Any,
|
||||
):
|
||||
"""validate value before set value
|
||||
"""
|
||||
"""validate value before set value"""
|
||||
settings = subconfig.config_bag.context.get_settings()
|
||||
# First validate properties with this value
|
||||
opt = subconfig.option
|
||||
settings.validate_frozen(subconfig)
|
||||
val, has_calculation = get_calculated_value(subconfig,
|
||||
val, has_calculation = get_calculated_value(
|
||||
subconfig,
|
||||
value,
|
||||
)
|
||||
settings.validate_mandatory(subconfig,
|
||||
settings.validate_mandatory(
|
||||
subconfig,
|
||||
val,
|
||||
)
|
||||
# Value must be valid for option
|
||||
opt.impl_validate(subconfig,
|
||||
opt.impl_validate(
|
||||
subconfig,
|
||||
val,
|
||||
check_error=True,
|
||||
)
|
||||
if 'warnings' in subconfig.config_bag.properties:
|
||||
if "warnings" in subconfig.config_bag.properties:
|
||||
# No error found so emit warnings
|
||||
opt.impl_validate(subconfig,
|
||||
opt.impl_validate(
|
||||
subconfig,
|
||||
val,
|
||||
check_error=False,
|
||||
)
|
||||
return val, has_calculation
|
||||
|
||||
def _setvalue(self,
|
||||
def _setvalue(
|
||||
self,
|
||||
subconfig: "SubConfig",
|
||||
value: Any,
|
||||
owner: str,
|
||||
) -> None:
|
||||
subconfig.config_bag.context.reset_cache(subconfig)
|
||||
self.set_storage_value(subconfig.path,
|
||||
self.set_storage_value(
|
||||
subconfig.path,
|
||||
subconfig.index,
|
||||
value,
|
||||
owner,
|
||||
)
|
||||
self._set_force_value_identifier(subconfig,
|
||||
self._set_force_value_identifier(
|
||||
subconfig,
|
||||
value,
|
||||
)
|
||||
|
||||
def set_storage_value(self,
|
||||
def set_storage_value(
|
||||
self,
|
||||
path,
|
||||
index,
|
||||
value,
|
||||
owner,
|
||||
):
|
||||
"""set a value
|
||||
"""
|
||||
"""set a value"""
|
||||
self._values.setdefault(path, {})[index] = [value, owner]
|
||||
|
||||
def _set_force_value_identifier(self,
|
||||
subconfig: 'SubConfig',
|
||||
def _set_force_value_identifier(
|
||||
self,
|
||||
subconfig: "SubConfig",
|
||||
identifier_values,
|
||||
) -> None:
|
||||
""" force store value for an option for identifiers
|
||||
"""
|
||||
"""force store value for an option for identifiers"""
|
||||
# pylint: disable=too-many-locals
|
||||
if 'force_store_value' not in subconfig.config_bag.properties:
|
||||
if "force_store_value" not in subconfig.config_bag.properties:
|
||||
return
|
||||
|
||||
config_bag = subconfig.config_bag
|
||||
context = config_bag.context
|
||||
for woption in subconfig.option._get_identifiers_dependencies(): # pylint: disable=protected-access
|
||||
options = subconfig.get_common_child(woption(),
|
||||
for (
|
||||
woption
|
||||
) in (
|
||||
subconfig.option._get_identifiers_dependencies()
|
||||
): # pylint: disable=protected-access
|
||||
options = subconfig.get_common_child(
|
||||
woption(),
|
||||
true_path=subconfig.path,
|
||||
validate_properties=False,
|
||||
)
|
||||
|
@ -343,29 +397,38 @@ class Values:
|
|||
parent = option.parent
|
||||
for identifier in identifier_values:
|
||||
name = option.option.impl_getname(identifier)
|
||||
opt_subconfig = parent.get_child(option.option,
|
||||
opt_subconfig = parent.get_child(
|
||||
option.option,
|
||||
None,
|
||||
False,
|
||||
identifier=identifier,
|
||||
name=name,
|
||||
)
|
||||
|
||||
for walk_subconfig in context.walk(opt_subconfig,
|
||||
for walk_subconfig in context.walk(
|
||||
opt_subconfig,
|
||||
no_value=True,
|
||||
validate_properties=False,
|
||||
):
|
||||
if 'force_store_value' not in walk_subconfig.properties:
|
||||
if "force_store_value" not in walk_subconfig.properties:
|
||||
continue
|
||||
default_value = [self.get_value(walk_subconfig)[0], owners.forced]
|
||||
self._values.setdefault(walk_subconfig.path, {})[walk_subconfig.index] = default_value
|
||||
default_value = [
|
||||
self.get_value(walk_subconfig)[0],
|
||||
owners.forced,
|
||||
]
|
||||
self._values.setdefault(walk_subconfig.path, {})[
|
||||
walk_subconfig.index
|
||||
] = default_value
|
||||
|
||||
def _get_modified_parent(self,
|
||||
def _get_modified_parent(
|
||||
self,
|
||||
subconfig: "SubConfig",
|
||||
) -> Optional["SubConfig"]:
|
||||
""" Search in differents parents a Config with a modified value
|
||||
"""Search in differents parents a Config with a modified value
|
||||
If not found, return None
|
||||
For follower option, return the Config where leader is modified
|
||||
"""
|
||||
|
||||
def build_option_bag(subconfig, parent):
|
||||
doption_bag = subconfig.copy()
|
||||
config_bag = subconfig.config_bag.copy()
|
||||
|
@ -376,17 +439,20 @@ class Values:
|
|||
|
||||
for parent in subconfig.config_bag.context.get_parents():
|
||||
doption_bag = build_option_bag(subconfig, parent)
|
||||
if 'force_metaconfig_on_freeze' in subconfig.properties:
|
||||
if "force_metaconfig_on_freeze" in subconfig.properties:
|
||||
# remove force_metaconfig_on_freeze only if option in metaconfig
|
||||
# hasn't force_metaconfig_on_freeze properties
|
||||
ori_properties = doption_bag.properties
|
||||
settings = doption_bag.config_bag.context.get_settings()
|
||||
doption_bag.properties = settings.getproperties(doption_bag)
|
||||
if not self.check_force_to_metaconfig(doption_bag):
|
||||
doption_bag.properties = ori_properties - {'force_metaconfig_on_freeze'}
|
||||
doption_bag.properties = ori_properties - {
|
||||
"force_metaconfig_on_freeze"
|
||||
}
|
||||
else:
|
||||
doption_bag.properties = ori_properties
|
||||
parent_owner = parent.get_values().getowner(doption_bag,
|
||||
parent_owner = parent.get_values().getowner(
|
||||
doption_bag,
|
||||
parent,
|
||||
only_default=True,
|
||||
)
|
||||
|
@ -395,23 +461,27 @@ class Values:
|
|||
|
||||
return None
|
||||
|
||||
|
||||
#______________________________________________________________________
|
||||
# ______________________________________________________________________
|
||||
# owner
|
||||
|
||||
def is_default_owner(self,
|
||||
def is_default_owner(
|
||||
self,
|
||||
subconfig: "SubConfig",
|
||||
*,
|
||||
validate_meta: bool=True,
|
||||
validate_meta: bool = True,
|
||||
) -> bool:
|
||||
"""is default owner for an option
|
||||
"""
|
||||
return self.getowner(subconfig,
|
||||
"""is default owner for an option"""
|
||||
return (
|
||||
self.getowner(
|
||||
subconfig,
|
||||
validate_meta=validate_meta,
|
||||
only_default=True,
|
||||
) == owners.default
|
||||
)
|
||||
== owners.default
|
||||
)
|
||||
|
||||
def hasvalue(self,
|
||||
def hasvalue(
|
||||
self,
|
||||
path,
|
||||
*,
|
||||
index=None,
|
||||
|
@ -426,7 +496,8 @@ class Values:
|
|||
return index in self._values[path]
|
||||
return False
|
||||
|
||||
def getowner(self,
|
||||
def getowner(
|
||||
self,
|
||||
subconfig: "SubConfig",
|
||||
*,
|
||||
validate_meta=True,
|
||||
|
@ -440,38 +511,46 @@ class Values:
|
|||
was present
|
||||
:returns: a `setting.owners.Owner` object
|
||||
"""
|
||||
# context = subconfig.config_bag.context
|
||||
# settings = context.get_settings()
|
||||
# settings.validate_properties(subconfig)
|
||||
if 'frozen' in subconfig.properties and \
|
||||
'force_default_on_freeze' in subconfig.properties:
|
||||
# context = subconfig.config_bag.context
|
||||
# settings = context.get_settings()
|
||||
# settings.validate_properties(subconfig)
|
||||
if (
|
||||
"frozen" in subconfig.properties
|
||||
and "force_default_on_freeze" in subconfig.properties
|
||||
):
|
||||
return owners.default
|
||||
if only_default:
|
||||
if self.hasvalue(subconfig.path,
|
||||
if self.hasvalue(
|
||||
subconfig.path,
|
||||
index=subconfig.index,
|
||||
):
|
||||
owner = 'not_default'
|
||||
owner = "not_default"
|
||||
else:
|
||||
owner = owners.default
|
||||
else:
|
||||
owner = self._values.get(subconfig.path, {}).get(subconfig.index,
|
||||
owner = self._values.get(subconfig.path, {}).get(
|
||||
subconfig.index,
|
||||
[undefined, owners.default],
|
||||
)[1]
|
||||
if validate_meta is not False and (owner is owners.default or
|
||||
'frozen' in subconfig.properties and
|
||||
'force_metaconfig_on_freeze' in subconfig.properties):
|
||||
if validate_meta is not False and (
|
||||
owner is owners.default
|
||||
or "frozen" in subconfig.properties
|
||||
and "force_metaconfig_on_freeze" in subconfig.properties
|
||||
):
|
||||
msubconfig = self._get_modified_parent(subconfig)
|
||||
if msubconfig is not None:
|
||||
values = msubconfig.config_bag.context.get_values()
|
||||
owner = values.getowner(msubconfig,
|
||||
owner = values.getowner(
|
||||
msubconfig,
|
||||
parent,
|
||||
only_default=only_default,
|
||||
)
|
||||
elif 'force_metaconfig_on_freeze' in subconfig.properties:
|
||||
elif "force_metaconfig_on_freeze" in subconfig.properties:
|
||||
return owners.default
|
||||
return owner
|
||||
|
||||
def set_owner(self,
|
||||
def set_owner(
|
||||
self,
|
||||
subconfig,
|
||||
owner,
|
||||
):
|
||||
|
@ -484,33 +563,40 @@ class Values:
|
|||
if owner in forbidden_owners:
|
||||
raise ValueError(_('set owner "{0}" is forbidden').format(str(owner)))
|
||||
|
||||
if not self.hasvalue(subconfig.path,
|
||||
if not self.hasvalue(
|
||||
subconfig.path,
|
||||
index=subconfig.index,
|
||||
):
|
||||
raise ConfigError(_(f'"{subconfig.path}" is a default value, so we cannot change owner to "{owner}"'))
|
||||
raise ConfigError(
|
||||
_(
|
||||
'"{0}" is a default value, so we cannot change owner to "{1}"'
|
||||
).format(subconfig.path, owner)
|
||||
)
|
||||
subconfig.config_bag.context.get_settings().validate_frozen(subconfig)
|
||||
self._values[subconfig.path][subconfig.index][1] = owner
|
||||
#______________________________________________________________________
|
||||
|
||||
# ______________________________________________________________________
|
||||
# reset
|
||||
|
||||
def reset(self,
|
||||
def reset(
|
||||
self,
|
||||
subconfig: "SubConfig",
|
||||
*,
|
||||
validate: bool=True,
|
||||
validate: bool = True,
|
||||
) -> None:
|
||||
"""reset value for an option
|
||||
"""
|
||||
"""reset value for an option"""
|
||||
config_bag = subconfig.config_bag
|
||||
hasvalue = self.hasvalue(subconfig.path)
|
||||
context = config_bag.context
|
||||
setting_properties = config_bag.properties
|
||||
if validate:
|
||||
if hasvalue and 'validator' in setting_properties:
|
||||
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,
|
||||
fake_subconfig = fake_context.get_sub_config(
|
||||
fake_config_bag,
|
||||
subconfig.path,
|
||||
subconfig.index,
|
||||
validate_properties=False,
|
||||
|
@ -519,18 +605,22 @@ class 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,
|
||||
fake_values.setvalue_validation(
|
||||
fake_subconfig,
|
||||
value,
|
||||
)
|
||||
# if hasvalue:
|
||||
# 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 subconfig.properties:
|
||||
if (
|
||||
"force_store_value" in setting_properties
|
||||
and "force_store_value" in subconfig.properties
|
||||
):
|
||||
value = self.get_default_value(subconfig)
|
||||
|
||||
self._setvalue(subconfig,
|
||||
self._setvalue(
|
||||
subconfig,
|
||||
value,
|
||||
owners.forced,
|
||||
)
|
||||
|
@ -538,44 +628,50 @@ class Values:
|
|||
value = None
|
||||
if subconfig.path in self._values:
|
||||
del self._values[subconfig.path]
|
||||
if 'force_store_value' in setting_properties and subconfig.option.impl_is_leader():
|
||||
if (
|
||||
"force_store_value" in setting_properties
|
||||
and subconfig.option.impl_is_leader()
|
||||
):
|
||||
if value is None:
|
||||
value = self.get_default_value(subconfig)
|
||||
leader = subconfig.option.impl_get_leadership()
|
||||
leader.follower_force_store_value(value,
|
||||
leader.follower_force_store_value(
|
||||
value,
|
||||
subconfig.parent,
|
||||
owners.forced,
|
||||
)
|
||||
context.reset_cache(subconfig)
|
||||
#______________________________________________________________________
|
||||
|
||||
# ______________________________________________________________________
|
||||
# Follower
|
||||
|
||||
def get_max_length(self, path: str) -> int:
|
||||
"""get max index for a follower and determine the length of the follower
|
||||
"""
|
||||
"""get max index for a follower and determine the length of the follower"""
|
||||
values = self._values.get(path, {})
|
||||
if values:
|
||||
return max(values) + 1
|
||||
return 0
|
||||
|
||||
def reset_follower(self,
|
||||
def reset_follower(
|
||||
self,
|
||||
subconfig: "SubConfig",
|
||||
) -> None:
|
||||
"""reset value for a follower
|
||||
"""
|
||||
if not self.hasvalue(subconfig.path,
|
||||
"""reset value for a follower"""
|
||||
if not self.hasvalue(
|
||||
subconfig.path,
|
||||
index=subconfig.index,
|
||||
):
|
||||
return
|
||||
config_bag = subconfig.config_bag
|
||||
context = config_bag.context
|
||||
setting_properties = config_bag.properties
|
||||
if 'validator' in setting_properties:
|
||||
if "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,
|
||||
fake_subconfig = fake_context.get_sub_config(
|
||||
fake_config_bag,
|
||||
subconfig.path,
|
||||
subconfig.index,
|
||||
validate_properties=False,
|
||||
|
@ -584,15 +680,20 @@ class Values:
|
|||
fake_values.reset_follower(fake_subconfig)
|
||||
fake_subconfig.config_bag.properties = setting_properties
|
||||
value = fake_values.get_default_value(fake_subconfig)
|
||||
fake_values.setvalue_validation(fake_subconfig,
|
||||
fake_values.setvalue_validation(
|
||||
fake_subconfig,
|
||||
value,
|
||||
)
|
||||
if 'force_store_value' in setting_properties and \
|
||||
'force_store_value' in subconfig.properties:
|
||||
value = self.get_default_value(subconfig,
|
||||
if (
|
||||
"force_store_value" in setting_properties
|
||||
and "force_store_value" in subconfig.properties
|
||||
):
|
||||
value = self.get_default_value(
|
||||
subconfig,
|
||||
)
|
||||
|
||||
self._setvalue(subconfig,
|
||||
self._setvalue(
|
||||
subconfig,
|
||||
value,
|
||||
owners.forced,
|
||||
)
|
||||
|
@ -600,50 +701,63 @@ class Values:
|
|||
self.resetvalue_index(subconfig)
|
||||
context.reset_cache(subconfig)
|
||||
|
||||
def resetvalue_index(self,
|
||||
def resetvalue_index(
|
||||
self,
|
||||
subconfig: "SubConfig",
|
||||
) -> None:
|
||||
"""reset a value for a follower at an index
|
||||
"""
|
||||
if subconfig.path in self._values and subconfig.index in self._values[subconfig.path]:
|
||||
"""reset a value for a follower at an index"""
|
||||
if (
|
||||
subconfig.path in self._values
|
||||
and subconfig.index in self._values[subconfig.path]
|
||||
):
|
||||
del self._values[subconfig.path][subconfig.index]
|
||||
|
||||
def reduce_index(self,
|
||||
def reduce_index(
|
||||
self,
|
||||
subconfig: "SubConfig",
|
||||
) -> None:
|
||||
"""reduce follower's value from a specified index
|
||||
"""
|
||||
"""reduce follower's value from a specified index"""
|
||||
self.resetvalue_index(subconfig)
|
||||
for index in range(subconfig.index + 1, self.get_max_length(subconfig.path)):
|
||||
if self.hasvalue(subconfig.path,
|
||||
if self.hasvalue(
|
||||
subconfig.path,
|
||||
index=index,
|
||||
):
|
||||
self._values[subconfig.path][index - 1] = self._values[subconfig.path].pop(index)
|
||||
self._values[subconfig.path][index - 1] = self._values[
|
||||
subconfig.path
|
||||
].pop(index)
|
||||
|
||||
def reset_leadership(self,
|
||||
def reset_leadership(
|
||||
self,
|
||||
subconfig: "SubConfig",
|
||||
index: int,
|
||||
) -> None:
|
||||
"""reset leadership from an index
|
||||
"""
|
||||
"""reset leadership from an index"""
|
||||
current_value = self.get_cached_value(subconfig)
|
||||
length = len(current_value)
|
||||
if index >= length:
|
||||
raise IndexError(_('index {index} is greater than the length {length} '
|
||||
'for option {subconfig.option.impl_get_display_name(with_quote=True)}'))
|
||||
raise IndexError(
|
||||
_(
|
||||
"index {index} is greater than the length {length} "
|
||||
"for option {subconfig.option.impl_get_display_name(with_quote=True)}"
|
||||
)
|
||||
)
|
||||
current_value.pop(index)
|
||||
leadership_subconfig = subconfig.parent
|
||||
leadership_subconfig.option.pop(subconfig,
|
||||
leadership_subconfig.option.pop(
|
||||
subconfig,
|
||||
index,
|
||||
)
|
||||
self.set_value(subconfig,
|
||||
self.set_value(
|
||||
subconfig,
|
||||
current_value,
|
||||
)
|
||||
|
||||
#______________________________________________________________________
|
||||
# ______________________________________________________________________
|
||||
# information
|
||||
|
||||
def set_information(self,
|
||||
def set_information(
|
||||
self,
|
||||
subconfig,
|
||||
key,
|
||||
value,
|
||||
|
@ -670,21 +784,26 @@ class Values:
|
|||
continue
|
||||
option = woption()
|
||||
if option.issubdyn():
|
||||
option_subconfigs = subconfig.get_common_child(option,
|
||||
option_subconfigs = subconfig.get_common_child(
|
||||
option,
|
||||
validate_properties=False,
|
||||
)
|
||||
if not isinstance(option_subconfigs, list):
|
||||
option_subconfigs = [option_subconfigs]
|
||||
else:
|
||||
option_subconfigs = [context.get_sub_config(config_bag,
|
||||
option_subconfigs = [
|
||||
context.get_sub_config(
|
||||
config_bag,
|
||||
option.impl_getpath(),
|
||||
None,
|
||||
validate_properties=False,
|
||||
)]
|
||||
)
|
||||
]
|
||||
for option_subconfig in option_subconfigs:
|
||||
context.reset_cache(option_subconfig)
|
||||
|
||||
def get_information(self,
|
||||
def get_information(
|
||||
self,
|
||||
subconfig,
|
||||
name,
|
||||
default,
|
||||
|
@ -704,44 +823,44 @@ class Values:
|
|||
except KeyError as err:
|
||||
pass
|
||||
if option is not None:
|
||||
return option._get_information(subconfig,
|
||||
return option._get_information(
|
||||
subconfig,
|
||||
name,
|
||||
default,
|
||||
)
|
||||
return subconfig.config_bag.context.get_description()._get_information(subconfig,
|
||||
return subconfig.config_bag.context.get_description()._get_information(
|
||||
subconfig,
|
||||
name,
|
||||
default,
|
||||
)
|
||||
|
||||
def del_information(self,
|
||||
def del_information(
|
||||
self,
|
||||
key: Any,
|
||||
raises: bool=True,
|
||||
path: str=None,
|
||||
raises: bool = True,
|
||||
path: str = None,
|
||||
):
|
||||
"""delete information for a specified key
|
||||
"""
|
||||
"""delete information for a specified key"""
|
||||
if path in self._informations and key in self._informations[path]:
|
||||
del self._informations[path][key]
|
||||
elif raises:
|
||||
raise ValueError(_(f"information's item not found \"{key}\""))
|
||||
raise ValueError(_('information\'s item not found "{}"').format(key))
|
||||
|
||||
def list_information(self,
|
||||
path: str=None,
|
||||
def list_information(
|
||||
self,
|
||||
path: str = None,
|
||||
) -> List[str]:
|
||||
"""list all informations keys for a specified path
|
||||
"""
|
||||
"""list all informations keys for a specified path"""
|
||||
return list(self._informations.get(path, {}).keys())
|
||||
|
||||
#____________________________________________________________
|
||||
# ____________________________________________________________
|
||||
# default owner methods
|
||||
def set_context_owner(self, owner: str) -> None:
|
||||
"""set the context owner
|
||||
"""
|
||||
"""set the context owner"""
|
||||
if owner in forbidden_owners:
|
||||
raise ValueError(_('set owner "{0}" is forbidden').format(str(owner)))
|
||||
self._values[None][None][1] = owner
|
||||
|
||||
def get_context_owner(self) -> str:
|
||||
"""get the context owner
|
||||
"""
|
||||
"""get the context owner"""
|
||||
return self._values[None][None][1]
|
||||
|
|
Loading…
Reference in a new issue