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
|
*.pyc
|
||||||
*.mo
|
|
||||||
*.swp
|
*.swp
|
||||||
build/
|
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")
|
![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)
|
[Documentations](doc/README.md)
|
||||||
|
|
||||||
|
|
||||||
# LICENSES
|
# 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:
|
if hidden:
|
||||||
base_name += 'hidden_'
|
base_name += 'hidden_'
|
||||||
#str_mandatory_multi_hidden_information_deps
|
#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',
|
str1 = StrOption(base_name + 'information_deps',
|
||||||
'',
|
'',
|
||||||
multi=multi,
|
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}'))
|
assert isinstance(option.path(), str) and (option.path() == name or option.path().endswith(f'.{name}'))
|
||||||
if '_deps' in name:
|
if '_deps' in name:
|
||||||
assert option.has_dependency(False)
|
assert option.has_dependency(False)
|
||||||
print(option.path())
|
|
||||||
assert option.dependencies()
|
assert option.dependencies()
|
||||||
else:
|
else:
|
||||||
assert not option.has_dependency(False)
|
assert not option.has_dependency(False)
|
||||||
|
|
|
@ -1046,12 +1046,12 @@ def test_validator_error_prefix():
|
||||||
try:
|
try:
|
||||||
cfg.option('b').value.set(1)
|
cfg.option('b').value.set(1)
|
||||||
except Exception as err:
|
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:
|
try:
|
||||||
cfg.option('b').value.set(1)
|
cfg.option('b').value.set(1)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
err.prefix = ''
|
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()
|
# assert not list_sessions()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -14,11 +14,29 @@
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
"""Configuration management library written in python
|
"""Configuration management library written in python
|
||||||
"""
|
"""
|
||||||
from .function import calc_value, calc_value_property_help, valid_ip_netmask, \
|
from .function import (
|
||||||
valid_network_netmask, valid_in_network, valid_broadcast, \
|
calc_value,
|
||||||
valid_not_equal, function_waiting_for_dict, function_waiting_for_error
|
calc_value_property_help,
|
||||||
from .autolib import Calculation, Params, ParamOption, ParamDynOption, ParamSelfOption, \
|
valid_ip_netmask,
|
||||||
ParamValue, ParamIndex, ParamIdentifier, ParamInformation, ParamSelfInformation
|
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 .option import *
|
||||||
from .error import ConfigError
|
from .error import ConfigError
|
||||||
from .api import Config, MetaConfig, GroupConfig, MixConfig
|
from .api import Config, MetaConfig, GroupConfig, MixConfig
|
||||||
|
@ -26,35 +44,36 @@ from .option import __all__ as all_options
|
||||||
from .setting import owners, groups, undefined
|
from .setting import owners, groups, undefined
|
||||||
|
|
||||||
|
|
||||||
allfuncs = ['Calculation',
|
allfuncs = [
|
||||||
'Params',
|
"Calculation",
|
||||||
'ParamOption',
|
"Params",
|
||||||
'ParamDynOption',
|
"ParamOption",
|
||||||
'ParamSelfOption',
|
"ParamDynOption",
|
||||||
'ParamValue',
|
"ParamSelfOption",
|
||||||
'ParamIndex',
|
"ParamValue",
|
||||||
'ParamIdentifier',
|
"ParamIndex",
|
||||||
'ParamInformation',
|
"ParamIdentifier",
|
||||||
'ParamSelfInformation',
|
"ParamInformation",
|
||||||
'MetaConfig',
|
"ParamSelfInformation",
|
||||||
'MixConfig',
|
"MetaConfig",
|
||||||
'GroupConfig',
|
"MixConfig",
|
||||||
'Config',
|
"GroupConfig",
|
||||||
'ConfigError',
|
"Config",
|
||||||
'undefined',
|
"ConfigError",
|
||||||
'owners',
|
"undefined",
|
||||||
'groups',
|
"owners",
|
||||||
'calc_value',
|
"groups",
|
||||||
'calc_value_property_help',
|
"calc_value",
|
||||||
'valid_ip_netmask',
|
"calc_value_property_help",
|
||||||
'valid_network_netmask',
|
"valid_ip_netmask",
|
||||||
'valid_in_network',
|
"valid_network_netmask",
|
||||||
'valid_broadcast',
|
"valid_in_network",
|
||||||
'function_waiting_for_dict',
|
"valid_broadcast",
|
||||||
'function_waiting_for_error',
|
"function_waiting_for_dict",
|
||||||
]
|
"function_waiting_for_error",
|
||||||
|
]
|
||||||
allfuncs.extend(all_options)
|
allfuncs.extend(all_options)
|
||||||
del(all_options)
|
del all_options
|
||||||
__all__ = tuple(allfuncs)
|
__all__ = tuple(allfuncs)
|
||||||
del(allfuncs)
|
del allfuncs
|
||||||
__version__ = "4.1.0"
|
__version__ = "4.1.0"
|
||||||
|
|
1682
tiramisu/api.py
1682
tiramisu/api.py
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -19,9 +19,9 @@ from time import time
|
||||||
|
|
||||||
|
|
||||||
class Cache:
|
class Cache:
|
||||||
"""cache object
|
"""cache object"""
|
||||||
"""
|
|
||||||
__slots__ = ('_cache',)
|
__slots__ = ("_cache",)
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._cache = {}
|
self._cache = {}
|
||||||
|
@ -35,29 +35,30 @@ class Cache:
|
||||||
index = subconfig.index
|
index = subconfig.index
|
||||||
return path, index
|
return path, index
|
||||||
|
|
||||||
def getcache(self,
|
def getcache(
|
||||||
subconfig,
|
self,
|
||||||
type_,
|
subconfig,
|
||||||
expiration=True,
|
type_,
|
||||||
):
|
expiration=True,
|
||||||
"""get the cache value fot a specified path
|
):
|
||||||
"""
|
"""get the cache value fot a specified path"""
|
||||||
no_cache = False, None, False
|
no_cache = False, None, False
|
||||||
path, index = self._get_path_index(subconfig)
|
path, index = self._get_path_index(subconfig)
|
||||||
if path not in self._cache or index not in self._cache[path]:
|
if path not in self._cache or index not in self._cache[path]:
|
||||||
return no_cache
|
return no_cache
|
||||||
value, timestamp, validated = self._cache[path][index]
|
value, timestamp, validated = self._cache[path][index]
|
||||||
props = subconfig.config_bag.properties
|
props = subconfig.config_bag.properties
|
||||||
if type_ == 'self_props':
|
if type_ == "self_props":
|
||||||
# cached value is self_props
|
# cached value is self_props
|
||||||
self_props = value
|
self_props = value
|
||||||
else:
|
else:
|
||||||
self_props = subconfig.properties
|
self_props = subconfig.properties
|
||||||
if 'cache' in props or \
|
if "cache" in props or "cache" in self_props:
|
||||||
'cache' in self_props:
|
if (
|
||||||
if expiration and timestamp and \
|
expiration
|
||||||
('expire' in props or \
|
and timestamp
|
||||||
'expire' in self_props):
|
and ("expire" in props or "expire" in self_props)
|
||||||
|
):
|
||||||
ntime = int(time())
|
ntime = int(time())
|
||||||
if timestamp + subconfig.config_bag.expiration_time >= ntime:
|
if timestamp + subconfig.config_bag.expiration_time >= ntime:
|
||||||
return True, value, validated
|
return True, value, validated
|
||||||
|
@ -65,37 +66,38 @@ class Cache:
|
||||||
return True, value, validated
|
return True, value, validated
|
||||||
return no_cache
|
return no_cache
|
||||||
|
|
||||||
def setcache(self,
|
def setcache(
|
||||||
subconfig,
|
self,
|
||||||
val,
|
subconfig,
|
||||||
type_='values',
|
val,
|
||||||
validated=True,
|
type_="values",
|
||||||
):
|
validated=True,
|
||||||
|
):
|
||||||
"""add val in cache for a specified path
|
"""add val in cache for a specified path
|
||||||
if follower, add index
|
if follower, add index
|
||||||
"""
|
"""
|
||||||
if type_ == 'values':
|
if type_ == "values":
|
||||||
if 'cache' not in subconfig.config_bag.properties and \
|
if (
|
||||||
'cache' not in subconfig.properties:
|
"cache" not in subconfig.config_bag.properties
|
||||||
|
and "cache" not in subconfig.properties
|
||||||
|
):
|
||||||
return
|
return
|
||||||
elif (subconfig is None or 'cache' not in subconfig.config_bag.properties) and \
|
elif (
|
||||||
'cache' not in val:
|
subconfig is None or "cache" not in subconfig.config_bag.properties
|
||||||
|
) and "cache" not in val:
|
||||||
return
|
return
|
||||||
path, index = self._get_path_index(subconfig)
|
path, index = self._get_path_index(subconfig)
|
||||||
self._cache.setdefault(path, {})[index] = (val, int(time()), validated)
|
self._cache.setdefault(path, {})[index] = (val, int(time()), validated)
|
||||||
|
|
||||||
def delcache(self, path):
|
def delcache(self, path):
|
||||||
"""reset cache a a specified path
|
"""reset cache a a specified path"""
|
||||||
"""
|
if path in self._cache:
|
||||||
if path in self._cache:
|
|
||||||
del self._cache[path]
|
del self._cache[path]
|
||||||
|
|
||||||
def get_cached(self):
|
def get_cached(self):
|
||||||
"""get cache values
|
"""get cache values"""
|
||||||
"""
|
|
||||||
return self._cache
|
return self._cache
|
||||||
|
|
||||||
def reset_all_cache(self):
|
def reset_all_cache(self):
|
||||||
"""reset all cache values
|
"""reset all cache values"""
|
||||||
"""
|
|
||||||
self._cache.clear()
|
self._cache.clear()
|
||||||
|
|
1874
tiramisu/config.py
1874
tiramisu/config.py
File diff suppressed because it is too large
Load diff
|
@ -19,17 +19,18 @@ import weakref
|
||||||
from .i18n import _
|
from .i18n import _
|
||||||
|
|
||||||
|
|
||||||
def display_list(lst,
|
def display_list(
|
||||||
*,
|
lst,
|
||||||
separator='and',
|
*,
|
||||||
add_quote=False,
|
separator="and",
|
||||||
) -> str():
|
add_quote=False,
|
||||||
|
) -> str():
|
||||||
if not lst:
|
if not lst:
|
||||||
return '""'
|
return '""'
|
||||||
if separator == 'and':
|
if separator == "and":
|
||||||
separator = _('and')
|
separator = _("and")
|
||||||
elif separator == 'or':
|
elif separator == "or":
|
||||||
separator = _('or')
|
separator = _("or")
|
||||||
if isinstance(lst, tuple) or isinstance(lst, frozenset):
|
if isinstance(lst, tuple) or isinstance(lst, frozenset):
|
||||||
lst = list(lst)
|
lst = list(lst)
|
||||||
if len(lst) == 1:
|
if len(lst) == 1:
|
||||||
|
@ -51,30 +52,35 @@ def display_list(lst,
|
||||||
lst__.append(l)
|
lst__.append(l)
|
||||||
lst__.sort()
|
lst__.sort()
|
||||||
last = lst__[-1]
|
last = lst__[-1]
|
||||||
return ', '.join(lst__[:-1]) + _(' {} ').format(separator) + '{}'.format(last)
|
return ", ".join(lst__[:-1]) + _(" {} ").format(separator) + "{}".format(last)
|
||||||
|
|
||||||
|
|
||||||
# Exceptions for an Option
|
# Exceptions for an Option
|
||||||
class PropertiesOptionError(AttributeError):
|
class PropertiesOptionError(AttributeError):
|
||||||
"attempt to access to an option with a property that is not allowed"
|
"attempt to access to an option with a property that is not allowed"
|
||||||
def __init__(self,
|
|
||||||
subconfig,
|
def __init__(
|
||||||
proptype,
|
self,
|
||||||
settings,
|
subconfig,
|
||||||
opt_type=None,
|
proptype,
|
||||||
name=None,
|
settings,
|
||||||
orig_opt=None,
|
opt_type=None,
|
||||||
help_properties=None):
|
name=None,
|
||||||
|
orig_opt=None,
|
||||||
|
help_properties=None,
|
||||||
|
):
|
||||||
if opt_type:
|
if opt_type:
|
||||||
self._opt_type = opt_type
|
self._opt_type = opt_type
|
||||||
self._name = name
|
self._name = name
|
||||||
self._orig_opt = orig_opt
|
self._orig_opt = orig_opt
|
||||||
else:
|
else:
|
||||||
if subconfig.option.impl_is_optiondescription():
|
if subconfig.option.impl_is_optiondescription():
|
||||||
self._opt_type = 'optiondescription'
|
self._opt_type = "optiondescription"
|
||||||
else:
|
else:
|
||||||
self._opt_type = 'option'
|
self._opt_type = "option"
|
||||||
self._name = subconfig.option.impl_get_display_name(subconfig, with_quote=True)
|
self._name = subconfig.option.impl_get_display_name(
|
||||||
|
subconfig, with_quote=True
|
||||||
|
)
|
||||||
self._orig_opt = None
|
self._orig_opt = None
|
||||||
self._subconfig = subconfig
|
self._subconfig = subconfig
|
||||||
self.proptype = proptype
|
self.proptype = proptype
|
||||||
|
@ -91,7 +97,7 @@ class PropertiesOptionError(AttributeError):
|
||||||
if self.msg is not None:
|
if self.msg is not None:
|
||||||
return self.msg
|
return self.msg
|
||||||
if self._settings is None:
|
if self._settings is None:
|
||||||
return 'error'
|
return "error"
|
||||||
if self.help_properties:
|
if self.help_properties:
|
||||||
properties = list(self.help_properties)
|
properties = list(self.help_properties)
|
||||||
else:
|
else:
|
||||||
|
@ -99,46 +105,47 @@ class PropertiesOptionError(AttributeError):
|
||||||
only_one = len(properties) == 1
|
only_one = len(properties) == 1
|
||||||
properties_msg = display_list(properties, add_quote=True)
|
properties_msg = display_list(properties, add_quote=True)
|
||||||
if only_one:
|
if only_one:
|
||||||
prop_msg = _('property')
|
prop_msg = _("property")
|
||||||
else:
|
else:
|
||||||
prop_msg = _('properties')
|
prop_msg = _("properties")
|
||||||
if properties == ['frozen']:
|
if properties == ["frozen"]:
|
||||||
if self._orig_opt:
|
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:
|
else:
|
||||||
msg = 'cannot modify the {0} {1} because has {2} {3}'
|
msg = _("cannot modify the {0} {1} because has {2} {3}")
|
||||||
else:
|
else:
|
||||||
if self._orig_opt:
|
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:
|
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:
|
if self._orig_opt:
|
||||||
# FIXME _orig_opt ?
|
# FIXME _orig_opt ?
|
||||||
self.msg = _(msg).format(self._opt_type,
|
self.msg = msg.format(
|
||||||
self._orig_opt.impl_get_display_name(subconfig, with_quote=True),
|
self._opt_type,
|
||||||
self._name,
|
self._orig_opt.impl_get_display_name(subconfig, with_quote=True),
|
||||||
prop_msg,
|
self._name,
|
||||||
properties_msg)
|
prop_msg,
|
||||||
|
properties_msg,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
self.msg = _(msg).format(self._opt_type,
|
self.msg = msg.format(self._opt_type, self._name, prop_msg, properties_msg)
|
||||||
self._name,
|
|
||||||
prop_msg,
|
|
||||||
properties_msg)
|
|
||||||
del self._opt_type, self._name
|
del self._opt_type, self._name
|
||||||
del self._settings, self._orig_opt
|
del self._settings, self._orig_opt
|
||||||
return self.msg
|
return self.msg
|
||||||
|
|
||||||
|
|
||||||
#____________________________________________________________
|
# ____________________________________________________________
|
||||||
# Exceptions for a Config
|
# Exceptions for a Config
|
||||||
class ConfigError(Exception):
|
class ConfigError(Exception):
|
||||||
"""attempt to change an option's owner without a value
|
"""attempt to change an option's owner without a value
|
||||||
or in case of `_descr` is None
|
or in case of `_descr` is None
|
||||||
or if a calculation cannot be carried out"""
|
or if a calculation cannot be carried out"""
|
||||||
def __init__(self,
|
|
||||||
exp,
|
def __init__(
|
||||||
ori_err=None,
|
self,
|
||||||
):
|
exp,
|
||||||
|
ori_err=None,
|
||||||
|
):
|
||||||
super().__init__(exp)
|
super().__init__(exp)
|
||||||
self.ori_err = ori_err
|
self.ori_err = ori_err
|
||||||
|
|
||||||
|
@ -148,8 +155,8 @@ class ConflictError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
#____________________________________________________________
|
# ____________________________________________________________
|
||||||
# miscellaneous exceptions
|
# miscellaneous exceptions
|
||||||
class LeadershipError(Exception):
|
class LeadershipError(Exception):
|
||||||
"problem with a leadership's value length"
|
"problem with a leadership's value length"
|
||||||
pass
|
pass
|
||||||
|
@ -161,13 +168,7 @@ class ConstError(TypeError):
|
||||||
|
|
||||||
|
|
||||||
class _CommonError:
|
class _CommonError:
|
||||||
def __init__(self,
|
def __init__(self, subconfig, val, display_type, opt, err_msg, index):
|
||||||
subconfig,
|
|
||||||
val,
|
|
||||||
display_type,
|
|
||||||
opt,
|
|
||||||
err_msg,
|
|
||||||
index):
|
|
||||||
self.val = val
|
self.val = val
|
||||||
self.display_type = display_type
|
self.display_type = display_type
|
||||||
self.opt = weakref.ref(opt)
|
self.opt = weakref.ref(opt)
|
||||||
|
@ -180,24 +181,24 @@ class _CommonError:
|
||||||
try:
|
try:
|
||||||
msg = self.prefix
|
msg = self.prefix
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
self.prefix = self.tmpl.format(self.val,
|
self.prefix = self.tmpl.format(self.val, _(self.display_type), self.name)
|
||||||
_(self.display_type),
|
|
||||||
self.name)
|
|
||||||
msg = self.prefix
|
msg = self.prefix
|
||||||
if self.err_msg:
|
if self.err_msg:
|
||||||
if msg:
|
if msg:
|
||||||
msg += ', {}'.format(self.err_msg)
|
msg += ", {}".format(self.err_msg)
|
||||||
else:
|
else:
|
||||||
msg = self.err_msg
|
msg = self.err_msg
|
||||||
if not msg:
|
if not msg:
|
||||||
msg = _('invalid value')
|
msg = _("invalid value")
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
|
|
||||||
class ValueWarning(_CommonError, UserWarning):
|
class ValueWarning(_CommonError, UserWarning):
|
||||||
tmpl = _('attention, "{0}" could be an invalid {1} for "{2}"')
|
tmpl = None
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
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:
|
if len(args) == 1 and not kwargs:
|
||||||
self.msg = args[0]
|
self.msg = args[0]
|
||||||
else:
|
else:
|
||||||
|
@ -211,8 +212,18 @@ class ValueWarning(_CommonError, UserWarning):
|
||||||
|
|
||||||
|
|
||||||
class ValueOptionError(_CommonError, ValueError):
|
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):
|
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
|
@function_waiting_for_dict
|
||||||
def valid_network_netmask(network: dict,
|
def valid_network_netmask(
|
||||||
netmask: dict,
|
network: dict,
|
||||||
):
|
netmask: dict,
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
validates if network and netmask are coherent
|
validates if network and netmask are coherent
|
||||||
this validator must be set to netmask option
|
this validator must be set to netmask option
|
||||||
"""
|
"""
|
||||||
if None in [network['value'], netmask['value']]:
|
if None in [network["value"], netmask["value"]]:
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
ip_network(f'{network["value"]}/{netmask["value"]}')
|
ip_network(f'{network["value"]}/{netmask["value"]}')
|
||||||
except ValueError as err:
|
except ValueError as err:
|
||||||
raise ValueError(_(f'network "{network["value"]}" ({network["name"]}) does not match '
|
raise ValueError(
|
||||||
'with this netmask')) from err
|
_('network "{0}" ({1}) does not match with this netmask').format(
|
||||||
|
network["value"], network["name"]
|
||||||
|
)
|
||||||
|
) from err
|
||||||
|
|
||||||
|
|
||||||
@function_waiting_for_dict
|
@function_waiting_for_dict
|
||||||
def valid_ip_netmask(ip: dict, # pylint: disable=invalid-name
|
def valid_ip_netmask(
|
||||||
netmask: dict,
|
ip: dict, # pylint: disable=invalid-name
|
||||||
):
|
netmask: dict,
|
||||||
|
):
|
||||||
"""validates if ip and netmask are coherent
|
"""validates if ip and netmask are coherent
|
||||||
this validator must be set to netmask option
|
this validator must be set to netmask option
|
||||||
"""
|
"""
|
||||||
if None in [ip['value'], netmask['value']]:
|
if None in [ip["value"], netmask["value"]]:
|
||||||
return
|
return
|
||||||
ip_netmask = ip_interface(f'{ip["value"]}/{netmask["value"]}')
|
ip_netmask = ip_interface(f'{ip["value"]}/{netmask["value"]}')
|
||||||
if ip_netmask.ip == ip_netmask.network.network_address:
|
if ip_netmask.ip == ip_netmask.network.network_address:
|
||||||
msg = _(f'IP "{ip["value"]}" ({ip["name"]}) with this netmask is '
|
msg = _('IP "{0}" ({1}) with this netmask is in fact a network address').format(
|
||||||
'in fact a network address')
|
ip["value"], ip["name"]
|
||||||
|
)
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
if ip_netmask.ip == ip_netmask.network.broadcast_address:
|
if ip_netmask.ip == ip_netmask.network.broadcast_address:
|
||||||
msg = _(f'IP "{ip["value"]}" ({ip["name"]}) with this netmask is '
|
msg = _(
|
||||||
'in fact a broacast address')
|
'IP "{0}" ({1}) with this netmask is in fact a broadcast address'
|
||||||
|
).format(ip["value"], ip["name"])
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
|
|
||||||
|
|
||||||
@function_waiting_for_dict
|
@function_waiting_for_dict
|
||||||
def valid_broadcast(network: dict,
|
def valid_broadcast(
|
||||||
netmask: dict,
|
network: dict,
|
||||||
broadcast: dict,
|
netmask: dict,
|
||||||
):
|
broadcast: dict,
|
||||||
"""validates if the broadcast is coherent with network and netmask
|
):
|
||||||
"""
|
"""validates if the broadcast is coherent with network and netmask"""
|
||||||
if None in [network['value'], netmask['value'], broadcast['value']]:
|
if None in [network["value"], netmask["value"], broadcast["value"]]:
|
||||||
return
|
return
|
||||||
if ip_network(f'{network["value"]}/{netmask["value"]}').broadcast_address != \
|
if ip_network(
|
||||||
ip_address(broadcast['value']):
|
f'{network["value"]}/{netmask["value"]}'
|
||||||
msg = _(f'broadcast invalid with network {network["value"]} ({network["name"]}) '
|
).broadcast_address != ip_address(broadcast["value"]):
|
||||||
f'and netmask {netmask["value"]} ({netmask["name"]})')
|
msg = _(
|
||||||
|
"broadcast invalid with network {0} ({1}) and netmask {2} ({3})"
|
||||||
|
).format(network["value"], network["name"], netmask["value"], netmask["name"])
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
|
|
||||||
|
|
||||||
@function_waiting_for_dict
|
@function_waiting_for_dict
|
||||||
def valid_in_network(ip: dict, # pylint: disable=invalid-name
|
def valid_in_network(
|
||||||
network: dict,
|
ip: dict, # pylint: disable=invalid-name
|
||||||
netmask=Optional[dict],
|
network: dict,
|
||||||
):
|
netmask=Optional[dict],
|
||||||
|
):
|
||||||
"""validates if an IP is in a network
|
"""validates if an IP is in a network
|
||||||
this validator must be set to ip option
|
this validator must be set to ip option
|
||||||
"""
|
"""
|
||||||
if None in [ip['value'], network['value']]:
|
if None in [ip["value"], network["value"]]:
|
||||||
return
|
return
|
||||||
if '/' in network['value']:
|
if "/" in network["value"]:
|
||||||
# it's a CIDR network
|
# it's a CIDR network
|
||||||
network_value = network['value']
|
network_value = network["value"]
|
||||||
else:
|
else:
|
||||||
if netmask is None or netmask['value'] is None:
|
if netmask is None or netmask["value"] is None:
|
||||||
return
|
return
|
||||||
network_value = f'{network["value"]}/{netmask["value"]}'
|
network_value = f'{network["value"]}/{netmask["value"]}'
|
||||||
network_obj = ip_network(network_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:
|
if netmask is None:
|
||||||
msg = _('this IP is not in network {network["value"]} ({network["name"]})')
|
msg = _('this IP is not in network {network["value"]} ({network["name"]})')
|
||||||
else:
|
else:
|
||||||
msg = _('this IP is not in network {network["value"]} ({network["name"]}) '
|
msg = _(
|
||||||
'with netmask {netmask["value"]} ({netmask["name"]})')
|
'this IP is not in network {network["value"]} ({network["name"]}) '
|
||||||
|
'with netmask {netmask["value"]} ({netmask["name"]})'
|
||||||
|
)
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
# test if ip is not network/broadcast IP
|
# test if ip is not network/broadcast IP
|
||||||
if ip_netmask.ip == ip_netmask.network.network_address:
|
if ip_netmask.ip == ip_netmask.network.network_address:
|
||||||
msg = _(f'this IP with the network {network["value"]} ({network["value"]} '
|
msg = _(
|
||||||
'is in fact a network address')
|
"this IP with the network {0} ({1}) is in fact a network address"
|
||||||
|
).format(network["value"], network["name"])
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
if ip_netmask.ip == ip_netmask.network.broadcast_address:
|
if ip_netmask.ip == ip_netmask.network.broadcast_address:
|
||||||
msg = _(f'this IP with the network {network["value"]} ({network["value"]} '
|
msg = _(
|
||||||
'is in fact a broadcast address')
|
"this IP with the network {0} ({1}) is in fact a broadcast address"
|
||||||
|
).format(network["value"], network["value"])
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
|
|
||||||
|
|
||||||
@function_waiting_for_dict
|
@function_waiting_for_dict
|
||||||
def valid_not_equal(*values):
|
def valid_not_equal(*values):
|
||||||
"""valid that two options have not same value
|
"""valid that two options have not same value"""
|
||||||
"""
|
|
||||||
equal = set()
|
equal = set()
|
||||||
for val in values[1:]:
|
for val in values[1:]:
|
||||||
if 'propertyerror' in val:
|
if "propertyerror" in val:
|
||||||
continue
|
continue
|
||||||
if values[0]['value'] == val['value'] is not None:
|
if values[0]["value"] == val["value"] is not None:
|
||||||
equal.add(val['name'])
|
equal.add(val["name"])
|
||||||
if not equal:
|
if not equal:
|
||||||
return
|
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)
|
raise ValueError(msg)
|
||||||
|
|
||||||
|
|
||||||
class CalcValue:
|
class CalcValue:
|
||||||
"""class to calc_value with different functions
|
"""class to calc_value with different functions"""
|
||||||
"""
|
|
||||||
# pylint: disable=too-many-instance-attributes
|
# pylint: disable=too-many-instance-attributes
|
||||||
def __call__(self,
|
def __call__(
|
||||||
*args: List[Any],
|
self,
|
||||||
multi: bool=False,
|
*args: List[Any],
|
||||||
default: Any=undefined,
|
multi: bool = False,
|
||||||
condition: Any=undefined,
|
default: Any = undefined,
|
||||||
no_condition_is_invalid: bool=False,
|
condition: Any = undefined,
|
||||||
expected: Any=undefined,
|
no_condition_is_invalid: bool = False,
|
||||||
condition_operator: str='AND',
|
expected: Any = undefined,
|
||||||
reverse_condition: bool=False,
|
condition_operator: str = "AND",
|
||||||
allow_none: bool=False,
|
reverse_condition: bool = False,
|
||||||
remove_duplicate_value: bool=False,
|
allow_none: bool = False,
|
||||||
join: Optional[str]=None,
|
remove_duplicate_value: bool = False,
|
||||||
min_args_len: Optional[int]=None,
|
join: Optional[str] = None,
|
||||||
operator: Optional[str]=None,
|
min_args_len: Optional[int] = None,
|
||||||
index: Optional[int]=None,
|
operator: Optional[str] = None,
|
||||||
**kwargs) -> Any:
|
index: Optional[int] = None,
|
||||||
|
**kwargs,
|
||||||
|
) -> Any:
|
||||||
# pylint: disable=too-many-statements,too-many-branches,too-many-nested-blocks,too-many-locals
|
# pylint: disable=too-many-statements,too-many-branches,too-many-nested-blocks,too-many-locals
|
||||||
"""calculate value
|
"""calculate value
|
||||||
:param args: list of value
|
:param args: list of value
|
||||||
|
@ -336,10 +353,13 @@ class CalcValue:
|
||||||
self.condition_operator = condition_operator
|
self.condition_operator = condition_operator
|
||||||
self.reverse_condition = reverse_condition
|
self.reverse_condition = reverse_condition
|
||||||
self.kwargs = kwargs
|
self.kwargs = kwargs
|
||||||
self.no_condition_is_invalid = no_condition_is_invalid # pylint: disable=attribute-defined-outside-init
|
self.no_condition_is_invalid = (
|
||||||
value = self.get_value(default,
|
no_condition_is_invalid # pylint: disable=attribute-defined-outside-init
|
||||||
min_args_len,
|
)
|
||||||
)
|
value = self.get_value(
|
||||||
|
default,
|
||||||
|
min_args_len,
|
||||||
|
)
|
||||||
if not multi:
|
if not multi:
|
||||||
if join is not None:
|
if join is not None:
|
||||||
if None not in value:
|
if None not in value:
|
||||||
|
@ -348,11 +368,12 @@ class CalcValue:
|
||||||
value = None
|
value = None
|
||||||
elif value and operator:
|
elif value and operator:
|
||||||
new_value = value[0]
|
new_value = value[0]
|
||||||
oper = {'mul': mul,
|
oper = {
|
||||||
'add': add,
|
"mul": mul,
|
||||||
'div': truediv,
|
"add": add,
|
||||||
'sub': sub,
|
"div": truediv,
|
||||||
}[operator]
|
"sub": sub,
|
||||||
|
}[operator]
|
||||||
for val in value[1:]:
|
for val in value[1:]:
|
||||||
new_value = oper(new_value, val)
|
new_value = oper(new_value, val)
|
||||||
value = new_value
|
value = new_value
|
||||||
|
@ -376,8 +397,9 @@ class CalcValue:
|
||||||
break
|
break
|
||||||
lval = len(val)
|
lval = len(val)
|
||||||
if length_val is not None and length_val != lval:
|
if length_val is not None and length_val != lval:
|
||||||
msg = _('unexpected value in calc_value with join attribute '
|
msg = _(
|
||||||
f'"{val}" with invalid length "{length_val}"')
|
'unexpected value in calc_value with join attribute "{0}" with invalid length "{1}"'
|
||||||
|
).format(val, length_val)
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
length_val = lval
|
length_val = lval
|
||||||
new_value = []
|
new_value = []
|
||||||
|
@ -403,19 +425,16 @@ class CalcValue:
|
||||||
value = new_value
|
value = new_value
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def value_from_kwargs(self,
|
def value_from_kwargs(
|
||||||
value: Any,
|
self, value: Any, pattern: str, to_dict: bool = False, empty_test=undefined
|
||||||
pattern: str,
|
) -> Any:
|
||||||
to_dict: bool=False,
|
"""get value from kwargs"""
|
||||||
empty_test=undefined) -> Any:
|
|
||||||
"""get value from kwargs
|
|
||||||
"""
|
|
||||||
# pylint: disable=too-many-branches
|
# pylint: disable=too-many-branches
|
||||||
# if value attribute exist return it's value
|
# if value attribute exist return it's value
|
||||||
# otherwise pattern_0, pattern_1, ...
|
# otherwise pattern_0, pattern_1, ...
|
||||||
# otherwise undefined
|
# otherwise undefined
|
||||||
if value is not empty_test:
|
if value is not empty_test:
|
||||||
if to_dict == 'all':
|
if to_dict == "all":
|
||||||
returns = {None: value}
|
returns = {None: value}
|
||||||
else:
|
else:
|
||||||
returns = value
|
returns = value
|
||||||
|
@ -426,7 +445,7 @@ class CalcValue:
|
||||||
if key.startswith(pattern):
|
if key.startswith(pattern):
|
||||||
index = int(key[len_pattern:])
|
index = int(key[len_pattern:])
|
||||||
if isinstance(pattern_value, dict):
|
if isinstance(pattern_value, dict):
|
||||||
pattern_value = pattern_value['value']
|
pattern_value = pattern_value["value"]
|
||||||
kwargs_matches[index] = pattern_value
|
kwargs_matches[index] = pattern_value
|
||||||
if not kwargs_matches:
|
if not kwargs_matches:
|
||||||
returns = undefined
|
returns = undefined
|
||||||
|
@ -443,38 +462,47 @@ class CalcValue:
|
||||||
returns.append(kwargs_matches[key])
|
returns.append(kwargs_matches[key])
|
||||||
return returns
|
return returns
|
||||||
|
|
||||||
def is_condition_matches(self,
|
def is_condition_matches(
|
||||||
condition_value,
|
self,
|
||||||
):
|
condition_value,
|
||||||
"""verify the condition
|
):
|
||||||
"""
|
"""verify the condition"""
|
||||||
# pylint: disable=too-many-branches
|
# pylint: disable=too-many-branches
|
||||||
calculated_conditions = self.value_from_kwargs(condition_value,
|
calculated_conditions = self.value_from_kwargs(
|
||||||
'condition_',
|
condition_value,
|
||||||
to_dict='all',
|
"condition_",
|
||||||
)
|
to_dict="all",
|
||||||
|
)
|
||||||
if calculated_conditions is undefined:
|
if calculated_conditions is undefined:
|
||||||
is_matches = not self.no_condition_is_invalid
|
is_matches = not self.no_condition_is_invalid
|
||||||
else:
|
else:
|
||||||
is_matches = None
|
is_matches = None
|
||||||
calculated_expected = self.value_from_kwargs(self.expected,
|
calculated_expected = self.value_from_kwargs(
|
||||||
'expected_',
|
self.expected,
|
||||||
to_dict=True,
|
"expected_",
|
||||||
)
|
to_dict=True,
|
||||||
calculated_reverse = self.value_from_kwargs(self.reverse_condition,
|
)
|
||||||
'reverse_condition_',
|
calculated_reverse = self.value_from_kwargs(
|
||||||
to_dict=True,
|
self.reverse_condition,
|
||||||
empty_test=False,
|
"reverse_condition_",
|
||||||
)
|
to_dict=True,
|
||||||
|
empty_test=False,
|
||||||
|
)
|
||||||
for idx, calculated_condition in calculated_conditions.items():
|
for idx, calculated_condition in calculated_conditions.items():
|
||||||
if isinstance(calculated_expected, dict):
|
if isinstance(calculated_expected, dict):
|
||||||
if idx is not None:
|
if idx is not None:
|
||||||
if isinstance(calculated_expected[idx], list):
|
if isinstance(calculated_expected[idx], list):
|
||||||
current_matches = calculated_condition in calculated_expected[idx]
|
current_matches = (
|
||||||
|
calculated_condition in calculated_expected[idx]
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
current_matches = calculated_condition == calculated_expected[idx]
|
current_matches = (
|
||||||
|
calculated_condition == calculated_expected[idx]
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
current_matches = calculated_condition in calculated_expected.values()
|
current_matches = (
|
||||||
|
calculated_condition in calculated_expected.values()
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
current_matches = calculated_condition == calculated_expected
|
current_matches = calculated_condition == calculated_expected
|
||||||
if isinstance(calculated_reverse, dict) and idx in calculated_reverse:
|
if isinstance(calculated_reverse, dict) and idx in calculated_reverse:
|
||||||
|
@ -483,36 +511,41 @@ class CalcValue:
|
||||||
reverse_condition = False
|
reverse_condition = False
|
||||||
if is_matches is None:
|
if is_matches is None:
|
||||||
is_matches = current_matches
|
is_matches = current_matches
|
||||||
if self.condition_operator == 'AND':
|
if self.condition_operator == "AND":
|
||||||
is_matches = is_matches and current_matches
|
is_matches = is_matches and current_matches
|
||||||
if reverse_condition:
|
if reverse_condition:
|
||||||
is_matches = not is_matches
|
is_matches = not is_matches
|
||||||
if not is_matches:
|
if not is_matches:
|
||||||
break
|
break
|
||||||
elif self.condition_operator == 'OR':
|
elif self.condition_operator == "OR":
|
||||||
is_matches = is_matches or current_matches
|
is_matches = is_matches or current_matches
|
||||||
if reverse_condition:
|
if reverse_condition:
|
||||||
is_matches = not is_matches
|
is_matches = not is_matches
|
||||||
if is_matches:
|
if is_matches:
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
msg = _(f'unexpected {self.condition_operator} condition_operator '
|
msg = _(
|
||||||
'in calc_value')
|
"unexpected {0} condition_operator " "in calc_value"
|
||||||
|
).format(self.condition_operator)
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
is_matches = is_matches and not self.reverse_condition \
|
is_matches = (
|
||||||
or not is_matches and self.reverse_condition
|
is_matches
|
||||||
|
and not self.reverse_condition
|
||||||
|
or not is_matches
|
||||||
|
and self.reverse_condition
|
||||||
|
)
|
||||||
return is_matches
|
return is_matches
|
||||||
|
|
||||||
def get_value(self,
|
def get_value(
|
||||||
default,
|
self,
|
||||||
min_args_len,
|
default,
|
||||||
):
|
min_args_len,
|
||||||
"""get the value from arguments
|
):
|
||||||
"""
|
"""get the value from arguments"""
|
||||||
# retrieve the condition
|
# retrieve the condition
|
||||||
if isinstance(self.condition, dict):
|
if isinstance(self.condition, dict):
|
||||||
if 'value' in self.condition:
|
if "value" in self.condition:
|
||||||
condition_value = self.condition['value']
|
condition_value = self.condition["value"]
|
||||||
else:
|
else:
|
||||||
condition_value = undefined
|
condition_value = undefined
|
||||||
else:
|
else:
|
||||||
|
@ -527,9 +560,10 @@ class CalcValue:
|
||||||
value = []
|
value = []
|
||||||
if not value:
|
if not value:
|
||||||
# default value
|
# default value
|
||||||
new_default = self.value_from_kwargs(default,
|
new_default = self.value_from_kwargs(
|
||||||
'default_',
|
default,
|
||||||
)
|
"default_",
|
||||||
|
)
|
||||||
if new_default is not undefined:
|
if new_default is not undefined:
|
||||||
if not isinstance(new_default, list):
|
if not isinstance(new_default, list):
|
||||||
value = [new_default]
|
value = [new_default]
|
||||||
|
@ -538,34 +572,32 @@ class CalcValue:
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def get_args(self):
|
def get_args(self):
|
||||||
"""get all arguments
|
"""get all arguments"""
|
||||||
"""
|
|
||||||
return list(self.args)
|
return list(self.args)
|
||||||
|
|
||||||
|
|
||||||
class CalcValuePropertyHelp(CalcValue):
|
class CalcValuePropertyHelp(CalcValue):
|
||||||
"""special class to display property error
|
"""special class to display property error"""
|
||||||
"""
|
|
||||||
def get_name(self):
|
def get_name(self):
|
||||||
"""get the condition name
|
"""get the condition name"""
|
||||||
"""
|
return self.condition["name"]
|
||||||
return self.condition['name']
|
|
||||||
|
|
||||||
def get_indexed_name(self, index: int) -> str:
|
def get_indexed_name(self, index: int) -> str:
|
||||||
"""get name for a specified index
|
"""get name for a specified index"""
|
||||||
"""
|
condition_index = self.kwargs.get(f"condition_{index}")
|
||||||
condition_index = self.kwargs.get(f'condition_{index}')
|
|
||||||
if condition_index is not None and not isinstance(condition_index, dict):
|
if condition_index is not None and not isinstance(condition_index, dict):
|
||||||
raise ValueError(_(f'unexpected condition_{index} must have "todict" argument'))
|
raise ValueError(
|
||||||
return condition_index['name']
|
_('unexpected condition_{0} must have "todict" argument').format(index)
|
||||||
|
)
|
||||||
|
return condition_index["name"]
|
||||||
|
|
||||||
|
def build_property_message(
|
||||||
def build_property_message(self,
|
self,
|
||||||
name: str,
|
name: str,
|
||||||
value: Any,
|
value: Any,
|
||||||
) -> str:
|
) -> str:
|
||||||
"""prepare message to display error message if needed
|
"""prepare message to display error message if needed"""
|
||||||
"""
|
|
||||||
if not self.reverse_condition:
|
if not self.reverse_condition:
|
||||||
msg = _('the value of "{0}" is {1}').format(name, value)
|
msg = _('the value of "{0}" is {1}').format(name, value)
|
||||||
else:
|
else:
|
||||||
|
@ -575,21 +607,21 @@ class CalcValuePropertyHelp(CalcValue):
|
||||||
def get_args(self):
|
def get_args(self):
|
||||||
args = super().get_args()
|
args = super().get_args()
|
||||||
action = args[0]
|
action = args[0]
|
||||||
calculated_expected = self.value_from_kwargs(self.expected,
|
calculated_expected = self.value_from_kwargs(
|
||||||
'expected_',
|
self.expected, "expected_", to_dict=True
|
||||||
to_dict=True)
|
)
|
||||||
if self.condition is not undefined:
|
if self.condition is not undefined:
|
||||||
if 'propertyerror' in self.condition:
|
if "propertyerror" in self.condition:
|
||||||
msg = self.condition['propertyerror']
|
msg = self.condition["propertyerror"]
|
||||||
else:
|
else:
|
||||||
name = self.get_name()
|
name = self.get_name()
|
||||||
if isinstance(calculated_expected, dict):
|
if isinstance(calculated_expected, dict):
|
||||||
calc_values = calculated_expected.values()
|
calc_values = calculated_expected.values()
|
||||||
else:
|
else:
|
||||||
calc_values = [calculated_expected]
|
calc_values = [calculated_expected]
|
||||||
display_value = display_list([str(val) for val in calc_values],
|
display_value = display_list(
|
||||||
separator='or',
|
[str(val) for val in calc_values], separator="or", add_quote=True
|
||||||
add_quote=True)
|
)
|
||||||
msg = self.build_property_message(name, display_value)
|
msg = self.build_property_message(name, display_value)
|
||||||
else:
|
else:
|
||||||
msgs = []
|
msgs = []
|
||||||
|
@ -601,8 +633,10 @@ class CalcValuePropertyHelp(CalcValue):
|
||||||
|
|
||||||
|
|
||||||
calc_value = 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)
|
# function_waiting_for_dict(calc_value)
|
||||||
calc_value_property_help = CalcValuePropertyHelp()
|
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)
|
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 rough gus of pypy: pypy: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||||
# the whole pypy projet is under MIT licence
|
# the whole pypy projet is under MIT licence
|
||||||
"internationalisation utilities"
|
"internationalisation utilities"
|
||||||
from .log import log
|
from gettext import translation
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from gettext import translation, NullTranslations
|
t = translation('tiramisu', str(Path(__file__).parent / 'locale'), fallback=True)
|
||||||
from platform import system
|
|
||||||
from pkg_resources import resource_filename
|
|
||||||
from os import environ
|
|
||||||
|
|
||||||
|
_ = t.gettext
|
||||||
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()
|
|
||||||
|
|
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
|
import os
|
||||||
|
|
||||||
|
|
||||||
log = getLogger('tiramisu')
|
log = getLogger("tiramisu")
|
||||||
if os.environ.get('TIRAMISU_DEBUG') == 'True': # pragma: no cover
|
if os.environ.get("TIRAMISU_DEBUG") == "True": # pragma: no cover
|
||||||
log.setLevel(DEBUG)
|
log.setLevel(DEBUG)
|
||||||
handler = StreamHandler()
|
handler = StreamHandler()
|
||||||
handler.setLevel(DEBUG)
|
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)
|
handler.setFormatter(formatter)
|
||||||
|
|
||||||
log.addHandler(handler)
|
log.addHandler(handler)
|
||||||
|
|
|
@ -25,7 +25,8 @@ from .dynoptiondescription import DynOptionDescription
|
||||||
from .leadership import Leadership
|
from .leadership import Leadership
|
||||||
from .baseoption import submulti
|
from .baseoption import submulti
|
||||||
from .symlinkoption import SymLinkOption
|
from .symlinkoption import SymLinkOption
|
||||||
#from .syndynoption import SynDynOption, SynDynOptionDescription, SynDynLeadership
|
|
||||||
|
# from .syndynoption import SynDynOption, SynDynOptionDescription, SynDynLeadership
|
||||||
from .option import Option
|
from .option import Option
|
||||||
from .choiceoption import ChoiceOption
|
from .choiceoption import ChoiceOption
|
||||||
from .booloption import BoolOption
|
from .booloption import BoolOption
|
||||||
|
@ -48,12 +49,33 @@ from .macoption import MACOption
|
||||||
from .permissionsoption import PermissionsOption
|
from .permissionsoption import PermissionsOption
|
||||||
|
|
||||||
|
|
||||||
__all__ = ('Leadership', 'OptionDescription', 'DynOptionDescription',
|
__all__ = (
|
||||||
# 'SynDynOptionDescription', 'SynDynLeadership','SynDynOption',
|
"Leadership",
|
||||||
'Option', 'SymLinkOption',
|
"OptionDescription",
|
||||||
'ChoiceOption', 'BoolOption', 'DateOption',
|
"DynOptionDescription",
|
||||||
'IntOption', 'FloatOption', 'StrOption',
|
# 'SynDynOptionDescription', 'SynDynLeadership','SynDynOption',
|
||||||
'IPOption', 'PortOption', 'NetworkOption', 'NetmaskOption',
|
"Option",
|
||||||
'BroadcastOption', 'DomainnameOption', 'EmailOption', 'URLOption',
|
"SymLinkOption",
|
||||||
'UsernameOption', 'GroupnameOption', 'FilenameOption', 'PasswordOption', 'submulti',
|
"ChoiceOption",
|
||||||
'RegexpOption', 'MACOption', 'PermissionsOption')
|
"BoolOption",
|
||||||
|
"DateOption",
|
||||||
|
"IntOption",
|
||||||
|
"FloatOption",
|
||||||
|
"StrOption",
|
||||||
|
"IPOption",
|
||||||
|
"PortOption",
|
||||||
|
"NetworkOption",
|
||||||
|
"NetmaskOption",
|
||||||
|
"BroadcastOption",
|
||||||
|
"DomainnameOption",
|
||||||
|
"EmailOption",
|
||||||
|
"URLOption",
|
||||||
|
"UsernameOption",
|
||||||
|
"GroupnameOption",
|
||||||
|
"FilenameOption",
|
||||||
|
"PasswordOption",
|
||||||
|
"submulti",
|
||||||
|
"RegexpOption",
|
||||||
|
"MACOption",
|
||||||
|
"PermissionsOption",
|
||||||
|
)
|
||||||
|
|
|
@ -36,40 +36,41 @@ submulti = 2
|
||||||
|
|
||||||
|
|
||||||
def valid_name(name):
|
def valid_name(name):
|
||||||
"""valid option name
|
"""valid option name"""
|
||||||
"""
|
|
||||||
if not isinstance(name, str):
|
if not isinstance(name, str):
|
||||||
return False
|
return False
|
||||||
if '.' in name:
|
if "." in name:
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
#____________________________________________________________
|
# ____________________________________________________________
|
||||||
#
|
#
|
||||||
class Base:
|
class Base:
|
||||||
"""Base use by all *Option* classes (Option, OptionDescription, SymLinkOption, ...)
|
"""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,
|
__slots__ = (
|
||||||
name: str,
|
"_name",
|
||||||
doc: str,
|
"_path",
|
||||||
informations: Optional[Dict],
|
"_informations",
|
||||||
*,
|
"_subdyns",
|
||||||
properties=None,
|
"_properties",
|
||||||
is_multi: bool=False,
|
"_has_dependency",
|
||||||
) -> None:
|
"_dependencies",
|
||||||
|
"_dependencies_information",
|
||||||
|
"_identifiers_dependencies",
|
||||||
|
"__weakref__",
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
name: str,
|
||||||
|
doc: str,
|
||||||
|
informations: Optional[Dict],
|
||||||
|
*,
|
||||||
|
properties=None,
|
||||||
|
is_multi: bool = False,
|
||||||
|
) -> None:
|
||||||
if not valid_name(name):
|
if not valid_name(name):
|
||||||
raise ValueError(_('"{0}" is an invalid name for an option').format(name))
|
raise ValueError(_('"{0}" is an invalid name for an option').format(name))
|
||||||
if properties is None:
|
if properties is None:
|
||||||
|
@ -80,88 +81,99 @@ class Base:
|
||||||
# if option is a multi, it cannot be 'empty' (None not allowed in the list)
|
# if option is a multi, it cannot be 'empty' (None not allowed in the list)
|
||||||
# and cannot have multiple time the same value
|
# and cannot have multiple time the same value
|
||||||
# 'empty' and 'unique' are removed for follower's option
|
# 'empty' and 'unique' are removed for follower's option
|
||||||
if 'notunique' not in properties:
|
if "notunique" not in properties:
|
||||||
properties = properties | {'unique'}
|
properties = properties | {"unique"}
|
||||||
if 'notempty' not in properties:
|
if "notempty" not in properties:
|
||||||
properties = properties | {'empty'}
|
properties = properties | {"empty"}
|
||||||
assert isinstance(properties, frozenset), _('invalid properties type {0} for {1},'
|
assert isinstance(properties, frozenset), _(
|
||||||
' must be a frozenset').format(type(properties),
|
"invalid properties type {0} for {1}," " must be a frozenset"
|
||||||
name)
|
).format(type(properties), name)
|
||||||
_setattr = object.__setattr__
|
_setattr = object.__setattr__
|
||||||
_setattr(self, '_name', name)
|
_setattr(self, "_name", name)
|
||||||
_setattr(self, '_informations', {'doc': doc})
|
_setattr(self, "_informations", {"doc": doc})
|
||||||
for prop in properties:
|
for prop in properties:
|
||||||
if not isinstance(prop, str):
|
if not isinstance(prop, str):
|
||||||
if not isinstance(prop, Calculation):
|
if not isinstance(prop, Calculation):
|
||||||
raise ValueError(_('invalid property type {0} for {1}, must be a string or a '
|
raise ValueError(
|
||||||
'Calculation').format(type(prop), name))
|
_(
|
||||||
|
"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()):
|
for param in chain(prop.params.args, prop.params.kwargs.values()):
|
||||||
if isinstance(param, ParamOption):
|
if isinstance(param, ParamOption):
|
||||||
param.option._add_dependency(self)
|
param.option._add_dependency(self)
|
||||||
if properties:
|
if properties:
|
||||||
_setattr(self, '_properties', properties)
|
_setattr(self, "_properties", properties)
|
||||||
self.set_informations(informations)
|
self.set_informations(informations)
|
||||||
|
|
||||||
def set_informations(self,
|
def set_informations(
|
||||||
informations: Optional[Dict],
|
self,
|
||||||
) -> None:
|
informations: Optional[Dict],
|
||||||
|
) -> None:
|
||||||
if not informations:
|
if not informations:
|
||||||
return
|
return
|
||||||
for key, value in informations.items():
|
for key, value in informations.items():
|
||||||
self._set_information(key,
|
self._set_information(
|
||||||
value,
|
key,
|
||||||
)
|
value,
|
||||||
|
)
|
||||||
|
|
||||||
def impl_has_dependency(self,
|
def impl_has_dependency(
|
||||||
self_is_dep: bool=True,
|
self,
|
||||||
) -> bool:
|
self_is_dep: bool = True,
|
||||||
"""this has dependency
|
) -> bool:
|
||||||
"""
|
"""this has dependency"""
|
||||||
if self_is_dep is True:
|
if self_is_dep is True:
|
||||||
return getattr(self, '_has_dependency', False)
|
return getattr(self, "_has_dependency", False)
|
||||||
return hasattr(self, '_dependencies')
|
return hasattr(self, "_dependencies")
|
||||||
|
|
||||||
def get_dependencies(self,
|
def get_dependencies(
|
||||||
context_od,
|
self,
|
||||||
) -> Set[str]:
|
context_od,
|
||||||
ret = set(getattr(self, '_dependencies', STATIC_TUPLE))
|
) -> Set[str]:
|
||||||
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
|
# 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
|
return ret
|
||||||
|
|
||||||
def _get_identifiers_dependencies(self) -> Set[str]:
|
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(
|
||||||
option,
|
self,
|
||||||
is_identifier: bool=False,
|
option,
|
||||||
) -> None:
|
is_identifier: bool = False,
|
||||||
|
) -> None:
|
||||||
woption = weakref.ref(option)
|
woption = weakref.ref(option)
|
||||||
options = self.get_dependencies(None)
|
options = self.get_dependencies(None)
|
||||||
options.add(woption)
|
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:
|
if is_identifier:
|
||||||
options = list(self._get_identifiers_dependencies())
|
options = list(self._get_identifiers_dependencies())
|
||||||
options.append(woption)
|
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:
|
def impl_is_optiondescription(self) -> bool:
|
||||||
"""option is an option description
|
"""option is an option description"""
|
||||||
"""
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def impl_is_dynoptiondescription(self) -> bool:
|
def impl_is_dynoptiondescription(self) -> bool:
|
||||||
"""option is not a dyn option description
|
"""option is not a dyn option description"""
|
||||||
"""
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def impl_is_sub_dyn_optiondescription(self):
|
def impl_is_sub_dyn_optiondescription(self):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def impl_getname(self) -> str:
|
def impl_getname(self) -> str:
|
||||||
"""get name
|
"""get name"""
|
||||||
"""
|
|
||||||
return self._name # pylint: disable=no-member
|
return self._name # pylint: disable=no-member
|
||||||
|
|
||||||
def _set_readonly(self) -> None:
|
def _set_readonly(self) -> None:
|
||||||
|
@ -170,40 +182,39 @@ class Base:
|
||||||
dico = self._informations # pylint: disable=no-member
|
dico = self._informations # pylint: disable=no-member
|
||||||
keys = tuple(dico.keys())
|
keys = tuple(dico.keys())
|
||||||
if len(keys) == 1:
|
if len(keys) == 1:
|
||||||
dico = dico['doc']
|
dico = dico["doc"]
|
||||||
else:
|
else:
|
||||||
dico = tuple([keys, tuple(dico.values())])
|
dico = tuple([keys, tuple(dico.values())])
|
||||||
_setattr(self, '_informations', dico)
|
_setattr(self, "_informations", dico)
|
||||||
extra = getattr(self, '_extra', None)
|
extra = getattr(self, "_extra", None)
|
||||||
if extra is not 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:
|
def impl_is_readonly(self) -> str:
|
||||||
"""the option is readonly
|
"""the option is readonly"""
|
||||||
"""
|
return hasattr(self, "_path")
|
||||||
return hasattr(self, '_path')
|
|
||||||
|
|
||||||
def impl_getproperties(self) -> FrozenSet[str]:
|
def impl_getproperties(self) -> FrozenSet[str]:
|
||||||
"""get properties
|
"""get properties"""
|
||||||
"""
|
return getattr(self, "_properties", frozenset())
|
||||||
return getattr(self, '_properties', frozenset())
|
|
||||||
|
|
||||||
def _setsubdyn(self,
|
def _setsubdyn(
|
||||||
subdyn,
|
self,
|
||||||
) -> None:
|
subdyn,
|
||||||
|
) -> None:
|
||||||
# pylint: disable=attribute-defined-outside-init
|
# pylint: disable=attribute-defined-outside-init
|
||||||
if getattr(self, '_subdyns', None) is None:
|
if getattr(self, "_subdyns", None) is None:
|
||||||
self._subdyns = []
|
self._subdyns = []
|
||||||
self._subdyns.append(subdyn)
|
self._subdyns.append(subdyn)
|
||||||
|
|
||||||
def issubdyn(self) -> bool:
|
def issubdyn(self) -> bool:
|
||||||
"""is sub dynoption
|
"""is sub dynoption"""
|
||||||
"""
|
return getattr(self, "_subdyns", None) is not None
|
||||||
return getattr(self, '_subdyns', None) is not None
|
|
||||||
|
|
||||||
def getsubdyn(self):
|
def getsubdyn(self):
|
||||||
"""get sub dynoption
|
"""get sub dynoption"""
|
||||||
"""
|
|
||||||
return self._subdyns[0]()
|
return self._subdyns[0]()
|
||||||
|
|
||||||
def get_sub_dyns(self):
|
def get_sub_dyns(self):
|
||||||
|
@ -211,11 +222,12 @@ class Base:
|
||||||
|
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
# information
|
# information
|
||||||
def _get_information(self,
|
def _get_information(
|
||||||
subconfig: "SubConfig",
|
self,
|
||||||
key: str,
|
subconfig: "SubConfig",
|
||||||
default: Any=undefined,
|
key: str,
|
||||||
) -> Any:
|
default: Any = undefined,
|
||||||
|
) -> Any:
|
||||||
"""retrieves one information's item
|
"""retrieves one information's item
|
||||||
|
|
||||||
:param key: the item string (ex: "help")
|
:param key: the item string (ex: "help")
|
||||||
|
@ -225,7 +237,7 @@ class Base:
|
||||||
if key in dico[0]:
|
if key in dico[0]:
|
||||||
return dico[1][dico[0].index(key)]
|
return dico[1][dico[0].index(key)]
|
||||||
elif isinstance(dico, str):
|
elif isinstance(dico, str):
|
||||||
if key == 'doc':
|
if key == "doc":
|
||||||
return dico
|
return dico
|
||||||
elif isinstance(dico, dict):
|
elif isinstance(dico, dict):
|
||||||
if key in dico:
|
if key in dico:
|
||||||
|
@ -233,13 +245,17 @@ class Base:
|
||||||
if default is not undefined:
|
if default is not undefined:
|
||||||
return default
|
return default
|
||||||
# pylint: disable=no-member
|
# pylint: disable=no-member
|
||||||
raise ValueError(_(f'information\'s item for {self.impl_get_display_name(subconfig, with_quote=True)} '
|
raise ValueError(
|
||||||
f'not found: "{key}"'))
|
_('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(
|
||||||
key: str,
|
self,
|
||||||
value: Any,
|
key: str,
|
||||||
) -> None:
|
value: Any,
|
||||||
|
) -> None:
|
||||||
"""updates the information's attribute
|
"""updates the information's attribute
|
||||||
(which is a dictionary)
|
(which is a dictionary)
|
||||||
|
|
||||||
|
@ -247,20 +263,20 @@ class Base:
|
||||||
:param value: information's value (ex: "the help string")
|
:param value: information's value (ex: "the help string")
|
||||||
"""
|
"""
|
||||||
if self.impl_is_readonly():
|
if self.impl_is_readonly():
|
||||||
raise AttributeError(_("'{0}' ({1}) object attribute '{2}' is"
|
raise AttributeError(
|
||||||
" read-only").format(self.__class__.__name__,
|
_("'{0}' ({1}) object attribute '{2}' is" " read-only").format(
|
||||||
self,
|
self.__class__.__name__, self, key
|
||||||
key))
|
)
|
||||||
|
)
|
||||||
self._informations[key] = value # pylint: disable=no-member
|
self._informations[key] = value # pylint: disable=no-member
|
||||||
|
|
||||||
def _list_information(self) -> Any:
|
def _list_information(self) -> Any:
|
||||||
"""get the list of information keys
|
"""get the list of information keys"""
|
||||||
"""
|
|
||||||
dico = self._informations # pylint: disable=no-member
|
dico = self._informations # pylint: disable=no-member
|
||||||
if isinstance(dico, tuple):
|
if isinstance(dico, tuple):
|
||||||
return list(dico[0])
|
return list(dico[0])
|
||||||
if not isinstance(dico, dict):
|
if not isinstance(dico, dict):
|
||||||
return ['doc']
|
return ["doc"]
|
||||||
# it's a dict
|
# it's a dict
|
||||||
return list(dico.keys())
|
return list(dico.keys())
|
||||||
|
|
||||||
|
@ -270,12 +286,14 @@ class BaseOption(Base):
|
||||||
in options that have to be set only once, it is of course done in the
|
in options that have to be set only once, it is of course done in the
|
||||||
__setattr__ method
|
__setattr__ method
|
||||||
"""
|
"""
|
||||||
__slots__ = ('_display_name_function',)
|
|
||||||
|
|
||||||
def __setattr__(self,
|
__slots__ = ("_display_name_function",)
|
||||||
name: str,
|
|
||||||
value: Any,
|
def __setattr__(
|
||||||
) -> Any:
|
self,
|
||||||
|
name: str,
|
||||||
|
value: Any,
|
||||||
|
) -> Any:
|
||||||
"""set once and only once some attributes in the option,
|
"""set once and only once some attributes in the option,
|
||||||
like `_name`. `_name` cannot be changed once the option is
|
like `_name`. `_name` cannot be changed once the option is
|
||||||
pushed in the :class:`tiramisu.option.OptionDescription`.
|
pushed in the :class:`tiramisu.option.OptionDescription`.
|
||||||
|
@ -286,72 +304,78 @@ class BaseOption(Base):
|
||||||
"""
|
"""
|
||||||
# never change _name in an option or attribute when object is readonly
|
# never change _name in an option or attribute when object is readonly
|
||||||
if self.impl_is_readonly():
|
if self.impl_is_readonly():
|
||||||
raise AttributeError(_('"{}" ({}) object attribute "{}" is'
|
raise AttributeError(
|
||||||
' read-only').format(self.__class__.__name__,
|
_('"{}" ({}) object attribute "{}" is' " read-only").format(
|
||||||
self.impl_get_display_name(None),
|
self.__class__.__name__, self.impl_get_display_name(None), name
|
||||||
name))
|
)
|
||||||
|
)
|
||||||
super().__setattr__(name, value)
|
super().__setattr__(name, value)
|
||||||
|
|
||||||
def impl_getpath(self) -> str:
|
def impl_getpath(self) -> str:
|
||||||
"""get the path of the option
|
"""get the path of the option"""
|
||||||
"""
|
|
||||||
try:
|
try:
|
||||||
return self._path
|
return self._path
|
||||||
except AttributeError as err:
|
except AttributeError as err:
|
||||||
raise AttributeError(_(f'{self.impl_get_display_name(None, with_quote=True)} not part of any Config')) \
|
raise AttributeError(
|
||||||
from err
|
_("{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(
|
||||||
subconfig: "SubConfig",
|
self,
|
||||||
*,
|
subconfig: "SubConfig",
|
||||||
with_quote: bool=False,
|
*,
|
||||||
) -> str:
|
with_quote: bool = False,
|
||||||
"""get display name
|
) -> str:
|
||||||
"""
|
"""get display name"""
|
||||||
if hasattr(self, '_display_name_function'):
|
if hasattr(self, "_display_name_function"):
|
||||||
return self._display_name_function(self,
|
return self._display_name_function(
|
||||||
subconfig,
|
self,
|
||||||
with_quote=with_quote,
|
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:
|
if subconfig and subconfig.path:
|
||||||
name = subconfig.path.rsplit('.', 1)[-1]
|
name = subconfig.path.rsplit(".", 1)[-1]
|
||||||
else:
|
else:
|
||||||
name = self._name
|
name = self._name
|
||||||
if with_quote:
|
if with_quote:
|
||||||
return f'"{name}"'
|
return f'"{name}"'
|
||||||
return name
|
return name
|
||||||
|
|
||||||
def reset_cache(self,
|
def reset_cache(
|
||||||
path: str,
|
self,
|
||||||
config_bag: 'OptionBag',
|
path: str,
|
||||||
resetted_opts: List[Base], # pylint: disable=unused-argument
|
config_bag: "OptionBag",
|
||||||
) -> None:
|
resetted_opts: List[Base], # pylint: disable=unused-argument
|
||||||
"""reset cache
|
) -> None:
|
||||||
"""
|
"""reset cache"""
|
||||||
context = config_bag.context
|
context = config_bag.context
|
||||||
context.properties_cache.delcache(path)
|
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():
|
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:
|
def impl_is_symlinkoption(self) -> bool:
|
||||||
"""the option is not a symlinkoption
|
"""the option is not a symlinkoption"""
|
||||||
"""
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_dependencies_information(self) -> List[str]:
|
def get_dependencies_information(self) -> List[str]:
|
||||||
"""get dependencies information
|
"""get dependencies information"""
|
||||||
"""
|
return getattr(self, "_dependencies_information", {})
|
||||||
return getattr(self, '_dependencies_information', {})
|
|
||||||
|
|
||||||
def value_dependencies(self,
|
def value_dependencies(
|
||||||
value: Any,
|
self,
|
||||||
is_identifier: bool=False,
|
value: Any,
|
||||||
) -> Any:
|
is_identifier: bool = False,
|
||||||
"""parse dependancies to add dependencies
|
) -> Any:
|
||||||
"""
|
"""parse dependancies to add dependencies"""
|
||||||
if isinstance(value, list):
|
if isinstance(value, list):
|
||||||
for val in value:
|
for val in value:
|
||||||
if isinstance(value, list):
|
if isinstance(value, list):
|
||||||
|
@ -361,12 +385,12 @@ class BaseOption(Base):
|
||||||
elif isinstance(value, Calculation):
|
elif isinstance(value, Calculation):
|
||||||
self.value_dependency(value, is_identifier)
|
self.value_dependency(value, is_identifier)
|
||||||
|
|
||||||
def value_dependency(self,
|
def value_dependency(
|
||||||
value: Any,
|
self,
|
||||||
is_identifier: bool=False,
|
value: Any,
|
||||||
) -> Any:
|
is_identifier: bool = False,
|
||||||
"""parse dependancy to add dependencies
|
) -> Any:
|
||||||
"""
|
"""parse dependancy to add dependencies"""
|
||||||
for param in chain(value.params.args, value.params.kwargs.values()):
|
for param in chain(value.params.args, value.params.kwargs.values()):
|
||||||
if isinstance(param, ParamOption):
|
if isinstance(param, ParamOption):
|
||||||
# pylint: disable=protected-access
|
# pylint: disable=protected-access
|
||||||
|
@ -382,7 +406,9 @@ class BaseOption(Base):
|
||||||
else:
|
else:
|
||||||
param.set_self_option(self)
|
param.set_self_option(self)
|
||||||
opt = None
|
opt = None
|
||||||
if not getattr(dest, '_dependencies_information', {}):
|
if not getattr(dest, "_dependencies_information", {}):
|
||||||
dest._dependencies_information = {None: []}
|
dest._dependencies_information = {None: []}
|
||||||
dest._dependencies_information[None].append(param)
|
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):
|
class BoolOption(Option):
|
||||||
"""represents a choice between ``True`` and ``False``
|
"""represents a choice between ``True`` and ``False``"""
|
||||||
"""
|
|
||||||
__slots__ = tuple()
|
|
||||||
_type = 'boolean'
|
|
||||||
|
|
||||||
def validate(self,
|
__slots__ = tuple()
|
||||||
value: bool,
|
_type = "boolean"
|
||||||
) -> None:
|
|
||||||
"""validate value
|
def validate(
|
||||||
"""
|
self,
|
||||||
|
value: bool,
|
||||||
|
) -> None:
|
||||||
|
"""validate value"""
|
||||||
if not isinstance(value, bool):
|
if not isinstance(value, bool):
|
||||||
raise ValueError()
|
raise ValueError()
|
||||||
|
|
|
@ -27,21 +27,21 @@ from .option import Option
|
||||||
|
|
||||||
|
|
||||||
class BroadcastOption(Option):
|
class BroadcastOption(Option):
|
||||||
"""represents the choice of a broadcast
|
"""represents the choice of a broadcast"""
|
||||||
"""
|
|
||||||
__slots__ = tuple()
|
|
||||||
_type = 'broadcast address'
|
|
||||||
|
|
||||||
def validate(self,
|
__slots__ = tuple()
|
||||||
value: str,
|
_type = "broadcast address"
|
||||||
) -> None:
|
|
||||||
"""validate
|
def validate(
|
||||||
"""
|
self,
|
||||||
|
value: str,
|
||||||
|
) -> None:
|
||||||
|
"""validate"""
|
||||||
if not isinstance(value, str):
|
if not isinstance(value, str):
|
||||||
raise ValueError(_('invalid string'))
|
raise ValueError(_("invalid string"))
|
||||||
if value.count('.') != 3:
|
if value.count(".") != 3:
|
||||||
raise ValueError()
|
raise ValueError()
|
||||||
for val in value.split('.'):
|
for val in value.split("."):
|
||||||
if val.startswith("0") and len(val) > 1:
|
if val.startswith("0") and len(val) > 1:
|
||||||
raise ValueError()
|
raise ValueError()
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -34,73 +34,73 @@ class ChoiceOption(Option):
|
||||||
|
|
||||||
The option can also have the value ``None``
|
The option can also have the value ``None``
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = tuple()
|
__slots__ = tuple()
|
||||||
_type = 'choice'
|
_type = "choice"
|
||||||
|
|
||||||
def __init__(self,
|
|
||||||
name,
|
|
||||||
doc,
|
|
||||||
values,
|
|
||||||
*args,
|
|
||||||
**kwargs):
|
|
||||||
|
|
||||||
|
def __init__(self, name, doc, values, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
:param values: is a list of values the option can possibly take
|
:param values: is a list of values the option can possibly take
|
||||||
"""
|
"""
|
||||||
if not isinstance(values, (Calculation, tuple)):
|
if not isinstance(values, (Calculation, tuple)):
|
||||||
raise TypeError(_('values must be a tuple or a calculation for {0}'
|
raise TypeError(
|
||||||
).format(name))
|
_("values must be a tuple or a calculation for {0}").format(name)
|
||||||
|
)
|
||||||
self._choice_values = values
|
self._choice_values = values
|
||||||
super().__init__(name,
|
super().__init__(name, doc, *args, **kwargs)
|
||||||
doc,
|
|
||||||
*args,
|
|
||||||
**kwargs)
|
|
||||||
|
|
||||||
def impl_get_values(self,
|
def impl_get_values(
|
||||||
subconfig: "SubConfig",
|
self,
|
||||||
uncalculated: bool=False,
|
subconfig: "SubConfig",
|
||||||
):
|
uncalculated: bool = False,
|
||||||
"""get values allowed by option
|
):
|
||||||
"""
|
"""get values allowed by option"""
|
||||||
choices = self._choice_values
|
choices = self._choice_values
|
||||||
if isinstance(choices, tuple):
|
if isinstance(choices, tuple):
|
||||||
choices = list(choices)
|
choices = list(choices)
|
||||||
if uncalculated:
|
if uncalculated:
|
||||||
return choices
|
return choices
|
||||||
values = get_calculated_value(subconfig,
|
values = get_calculated_value(
|
||||||
choices,
|
subconfig,
|
||||||
)[0]
|
choices,
|
||||||
|
)[0]
|
||||||
|
|
||||||
if values != undefined and not isinstance(values, (list, tuple)):
|
if values != undefined and not isinstance(values, (list, tuple)):
|
||||||
raise ConfigError(_('the calculated values "{0}" for "{1}" is not a list'
|
raise ConfigError(
|
||||||
'').format(values, self.impl_getname()))
|
_('the calculated values "{0}" for "{1}" is not a list' "").format(
|
||||||
|
values, self.impl_getname()
|
||||||
|
)
|
||||||
|
)
|
||||||
return values
|
return values
|
||||||
|
|
||||||
def validate(self,
|
def validate(
|
||||||
value: Any,
|
self,
|
||||||
) -> None:
|
value: Any,
|
||||||
"""nothing to valide
|
) -> None:
|
||||||
"""
|
"""nothing to valide"""
|
||||||
|
|
||||||
def validate_with_option(self,
|
def validate_with_option(
|
||||||
value: Any,
|
self,
|
||||||
subconfig: "SubConfig",
|
value: Any,
|
||||||
loaded: bool,
|
subconfig: "SubConfig",
|
||||||
) -> None:
|
loaded: bool,
|
||||||
|
) -> None:
|
||||||
if loaded and isinstance(self._choice_values, Calculation):
|
if loaded and isinstance(self._choice_values, Calculation):
|
||||||
return
|
return
|
||||||
values = self.impl_get_values(subconfig)
|
values = self.impl_get_values(subconfig)
|
||||||
self.validate_values(value, values)
|
self.validate_values(value, values)
|
||||||
|
|
||||||
def validate_values(self,
|
def validate_values(
|
||||||
value,
|
self,
|
||||||
values,
|
value,
|
||||||
) -> None:
|
values,
|
||||||
"""validate values
|
) -> None:
|
||||||
"""
|
"""validate values"""
|
||||||
if values is not undefined and value not in values:
|
if values is not undefined and value not in values:
|
||||||
if len(values) == 1:
|
if len(values) == 1:
|
||||||
raise ValueError(_('only "{0}" is allowed'
|
raise ValueError(_('only "{0}" is allowed' "").format(values[0]))
|
||||||
'').format(values[0]))
|
raise ValueError(
|
||||||
raise ValueError(_('only {0} are allowed'
|
_("only {0} are allowed" "").format(
|
||||||
'').format(display_list(values, add_quote=True)))
|
display_list(values, add_quote=True)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
|
@ -27,13 +27,12 @@ from .stroption import StrOption
|
||||||
|
|
||||||
|
|
||||||
class DateOption(StrOption):
|
class DateOption(StrOption):
|
||||||
"""represents the choice of a date
|
"""represents the choice of a date"""
|
||||||
"""
|
|
||||||
__slots__ = tuple()
|
|
||||||
_type = 'date'
|
|
||||||
|
|
||||||
def validate(self,
|
__slots__ = tuple()
|
||||||
value: str) -> None:
|
_type = "date"
|
||||||
|
|
||||||
|
def validate(self, value: str) -> None:
|
||||||
super().validate(value)
|
super().validate(value)
|
||||||
try:
|
try:
|
||||||
datetime.strptime(value, "%Y-%m-%d")
|
datetime.strptime(value, "%Y-%m-%d")
|
||||||
|
|
|
@ -39,126 +39,139 @@ class DomainnameOption(StrOption):
|
||||||
domainname:
|
domainname:
|
||||||
fqdn: with tld, not supported yet
|
fqdn: with tld, not supported yet
|
||||||
"""
|
"""
|
||||||
__slots__ = tuple()
|
|
||||||
_type = 'domain name'
|
|
||||||
|
|
||||||
def __init__(self,
|
__slots__ = tuple()
|
||||||
name: str,
|
_type = "domain name"
|
||||||
doc: str,
|
|
||||||
*args,
|
def __init__(
|
||||||
allow_ip: bool=False,
|
self,
|
||||||
allow_cidr_network: bool=False,
|
name: str,
|
||||||
type: str='domainname',
|
doc: str,
|
||||||
allow_without_dot: bool=False,
|
*args,
|
||||||
allow_startswith_dot: bool=False,
|
allow_ip: bool = False,
|
||||||
**kwargs,
|
allow_cidr_network: bool = False,
|
||||||
) -> None:
|
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
|
# pylint: disable=too-many-branches,too-many-locals,too-many-arguments
|
||||||
if type not in ['netbios', 'hostname', 'domainname']:
|
if type not in ["netbios", "hostname", "domainname"]:
|
||||||
raise ValueError(_('unknown type {0} for hostname').format(type))
|
raise ValueError(_("unknown type {0} for hostname").format(type))
|
||||||
extra = {'_dom_type': type}
|
extra = {"_dom_type": type}
|
||||||
if not isinstance(allow_ip, bool):
|
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):
|
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):
|
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):
|
if not isinstance(allow_startswith_dot, bool):
|
||||||
raise ValueError(_('allow_startswith_dot must be a boolean'))
|
raise ValueError(_("allow_startswith_dot must be a boolean"))
|
||||||
extra['_allow_without_dot'] = allow_without_dot
|
extra["_allow_without_dot"] = allow_without_dot
|
||||||
if type == 'domainname':
|
if type == "domainname":
|
||||||
if allow_without_dot:
|
if allow_without_dot:
|
||||||
min_time = 0
|
min_time = 0
|
||||||
else:
|
else:
|
||||||
min_time = 1
|
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:
|
else:
|
||||||
regexp = r'((?!-)[a-z0-9-]{{1,{0}}})'.format(self._get_len(type))
|
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 = _(
|
||||||
msg_warning = _('must start with lowercase characters followed by lowercase characters, number, "-" and "." characters are recommanded')
|
'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:
|
if allow_ip:
|
||||||
msg = _('could be a IP, otherwise {}').format(msg)
|
msg = _("could be a IP, otherwise {}").format(msg)
|
||||||
msg_warning = _('could be a IP, otherwise {}').format(msg_warning)
|
msg_warning = _("could be a IP, otherwise {}").format(msg_warning)
|
||||||
if not allow_cidr_network:
|
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:
|
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}|(?:(?:(?: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 = r'^{0}$'.format(regexp)
|
regexp
|
||||||
extra['_domain_re'] = re.compile(regexp)
|
)
|
||||||
extra['_domain_re_message'] = msg
|
regexp = r"^{0}$".format(regexp)
|
||||||
extra['_domain_re_message_warning'] = msg_warning
|
extra["_domain_re"] = re.compile(regexp)
|
||||||
extra['_has_upper'] = re.compile('[A-Z]')
|
extra["_domain_re_message"] = msg
|
||||||
|
extra["_domain_re_message_warning"] = msg_warning
|
||||||
|
extra["_has_upper"] = re.compile("[A-Z]")
|
||||||
if allow_ip:
|
if allow_ip:
|
||||||
extra['_ip'] = IPOption(name,
|
extra["_ip"] = IPOption(
|
||||||
doc,
|
name,
|
||||||
)
|
doc,
|
||||||
extra['_allow_ip'] = allow_ip
|
)
|
||||||
|
extra["_allow_ip"] = allow_ip
|
||||||
if allow_cidr_network:
|
if allow_cidr_network:
|
||||||
extra['_network'] = NetworkOption(name,
|
extra["_network"] = NetworkOption(
|
||||||
doc,
|
name,
|
||||||
cidr=True,
|
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__(
|
||||||
doc,
|
name,
|
||||||
*args,
|
doc,
|
||||||
extra=extra,
|
*args,
|
||||||
**kwargs,
|
extra=extra,
|
||||||
)
|
**kwargs,
|
||||||
|
)
|
||||||
|
|
||||||
def _get_len(self, type_):
|
def _get_len(self, type_):
|
||||||
if type_ == 'netbios':
|
if type_ == "netbios":
|
||||||
return 15
|
return 15
|
||||||
return 63
|
return 63
|
||||||
|
|
||||||
def _validate_domain(self,
|
def _validate_domain(self, value: str) -> None:
|
||||||
value: str) -> None:
|
|
||||||
def _valid_length(val):
|
def _valid_length(val):
|
||||||
if len(val) < 1:
|
if len(val) < 1:
|
||||||
raise ValueError(_("invalid length (min 1)"))
|
raise ValueError(_("invalid length (min 1)"))
|
||||||
if len(val) > part_name_length:
|
if len(val) > part_name_length:
|
||||||
raise ValueError(_("invalid length (max {0})"
|
raise ValueError(
|
||||||
"").format(part_name_length))
|
_("invalid length (max {0})" "").format(part_name_length)
|
||||||
|
)
|
||||||
|
|
||||||
part_name_length = self._get_len(self.impl_get_extra('_dom_type'))
|
part_name_length = self._get_len(self.impl_get_extra("_dom_type"))
|
||||||
if self.impl_get_extra('_dom_type') == 'domainname':
|
if self.impl_get_extra("_dom_type") == "domainname":
|
||||||
if not self.impl_get_extra('_allow_without_dot') and not "." in value:
|
if not self.impl_get_extra("_allow_without_dot") and not "." in value:
|
||||||
raise ValueError(_("must have dot"))
|
raise ValueError(_("must have dot"))
|
||||||
if len(value) > 255:
|
if len(value) > 255:
|
||||||
raise ValueError(_("invalid length (max 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:]
|
val = value[1:]
|
||||||
else:
|
else:
|
||||||
val = value
|
val = value
|
||||||
if val.endswith('.'):
|
if val.endswith("."):
|
||||||
nval = val[:-1]
|
nval = val[:-1]
|
||||||
else:
|
else:
|
||||||
nval = val
|
nval = val
|
||||||
for dom in nval.split('.'):
|
for dom in nval.split("."):
|
||||||
_valid_length(dom)
|
_valid_length(dom)
|
||||||
else:
|
else:
|
||||||
_valid_length(value)
|
_valid_length(value)
|
||||||
|
|
||||||
def _validate_ip_network(self,
|
def _validate_ip_network(self, value: str) -> None:
|
||||||
value: str) -> None:
|
allow_ip = self.impl_get_extra("_allow_ip")
|
||||||
allow_ip = self.impl_get_extra('_allow_ip')
|
allow_cidr_network = self.impl_get_extra("_allow_cidr_network")
|
||||||
allow_cidr_network = self.impl_get_extra('_allow_cidr_network')
|
|
||||||
if allow_ip is False and allow_cidr_network is False:
|
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:
|
if allow_ip is True:
|
||||||
try:
|
try:
|
||||||
self.impl_get_extra('_ip').validate(value)
|
self.impl_get_extra("_ip").validate(value)
|
||||||
return
|
return
|
||||||
except ValueError as err:
|
except ValueError as err:
|
||||||
if allow_cidr_network is False:
|
if allow_cidr_network is False:
|
||||||
raise err
|
raise err
|
||||||
if allow_cidr_network is True:
|
if allow_cidr_network is True:
|
||||||
self.impl_get_extra('_network').validate(value)
|
self.impl_get_extra("_network").validate(value)
|
||||||
|
|
||||||
def validate(self,
|
def validate(self, value: str) -> None:
|
||||||
value: str) -> None:
|
|
||||||
super().validate(value)
|
super().validate(value)
|
||||||
try:
|
try:
|
||||||
# check if it's an IP or network
|
# check if it's an IP or network
|
||||||
|
@ -168,42 +181,40 @@ class DomainnameOption(StrOption):
|
||||||
else:
|
else:
|
||||||
self._validate_ip_network(value)
|
self._validate_ip_network(value)
|
||||||
|
|
||||||
def _second_level_validation_domain(self,
|
def _second_level_validation_domain(self, value: str, warnings_only: bool) -> None:
|
||||||
value: str,
|
if self.impl_get_extra("_has_upper").search(value):
|
||||||
warnings_only: bool) -> None:
|
raise ValueError(_("some characters are uppercase"))
|
||||||
if self.impl_get_extra('_has_upper').search(value):
|
if self.impl_get_extra("_allow_startswith_dot") and value.startswith("."):
|
||||||
raise ValueError(_('some characters are uppercase'))
|
|
||||||
if self.impl_get_extra('_allow_startswith_dot') and value.startswith('.'):
|
|
||||||
val = value[1:]
|
val = value[1:]
|
||||||
else:
|
else:
|
||||||
val = value
|
val = value
|
||||||
if val.endswith('.'):
|
if val.endswith("."):
|
||||||
nval = val[:-1]
|
nval = val[:-1]
|
||||||
else:
|
else:
|
||||||
nval = val
|
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:
|
if warnings_only:
|
||||||
raise ValueError(self.impl_get_extra('_domain_re_message_warning'))
|
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"))
|
||||||
|
|
||||||
def _second_level_validation_ip_network(self,
|
def _second_level_validation_ip_network(
|
||||||
value: str,
|
self, value: str, warnings_only: bool
|
||||||
warnings_only: bool) -> None:
|
) -> None:
|
||||||
allow_ip = self.impl_get_extra('_allow_ip')
|
allow_ip = self.impl_get_extra("_allow_ip")
|
||||||
allow_cidr_network = self.impl_get_extra('_allow_cidr_network')
|
allow_cidr_network = self.impl_get_extra("_allow_cidr_network")
|
||||||
# it's an IP so validate with IPOption
|
# it's an IP so validate with IPOption
|
||||||
if allow_ip is True and allow_cidr_network is False:
|
if allow_ip is True and allow_cidr_network is False:
|
||||||
try:
|
try:
|
||||||
self.impl_get_extra('_ip').second_level_validation(value, warnings_only)
|
self.impl_get_extra("_ip").second_level_validation(value, warnings_only)
|
||||||
return
|
return
|
||||||
except ValueError as err:
|
except ValueError as err:
|
||||||
raise err
|
raise err
|
||||||
if allow_cidr_network is True:
|
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,
|
def second_level_validation(self, value: str, warnings_only: bool) -> None:
|
||||||
value: str,
|
|
||||||
warnings_only: bool) -> None:
|
|
||||||
try:
|
try:
|
||||||
# check if it's an IP or network
|
# check if it's an IP or network
|
||||||
ip_interface(value)
|
ip_interface(value)
|
||||||
|
|
|
@ -35,27 +35,32 @@ from ..error import ConfigError
|
||||||
from ..autolib import Calculation, get_calculated_value
|
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',
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(self,
|
|
||||||
name: str,
|
class DynOptionDescription(OptionDescription):
|
||||||
doc: str,
|
"""dyn option description"""
|
||||||
children: List[BaseOption],
|
|
||||||
identifiers: Calculation,
|
__slots__ = (
|
||||||
**kwargs,
|
"_identifiers",
|
||||||
) -> None:
|
"_subdyns",
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
name: str,
|
||||||
|
doc: str,
|
||||||
|
children: List[BaseOption],
|
||||||
|
identifiers: Calculation,
|
||||||
|
**kwargs,
|
||||||
|
) -> None:
|
||||||
# pylint: disable=too-many-arguments
|
# pylint: disable=too-many-arguments
|
||||||
super().__init__(name,
|
super().__init__(
|
||||||
doc,
|
name,
|
||||||
children,
|
doc,
|
||||||
**kwargs,
|
children,
|
||||||
)
|
**kwargs,
|
||||||
|
)
|
||||||
# check children + set relation to this dynoptiondescription
|
# check children + set relation to this dynoptiondescription
|
||||||
wself = weakref.ref(self)
|
wself = weakref.ref(self)
|
||||||
for child in children:
|
for child in children:
|
||||||
|
@ -64,75 +69,86 @@ class DynOptionDescription(OptionDescription):
|
||||||
self.value_dependencies(identifiers, is_identifier=True)
|
self.value_dependencies(identifiers, is_identifier=True)
|
||||||
self._identifiers = identifiers
|
self._identifiers = identifiers
|
||||||
|
|
||||||
def convert_identifier_to_path(self,
|
def convert_identifier_to_path(
|
||||||
identifier: Any,
|
self,
|
||||||
) -> str:
|
identifier: Any,
|
||||||
"""convert identifier to use it to a path
|
) -> str:
|
||||||
"""
|
"""convert identifier to use it to a path"""
|
||||||
if identifier is None:
|
if identifier is None:
|
||||||
return None
|
return None
|
||||||
if not isinstance(identifier, str):
|
if not isinstance(identifier, str):
|
||||||
identifier = str(identifier)
|
identifier = str(identifier)
|
||||||
if '.' in identifier:
|
if "." in identifier:
|
||||||
identifier = identifier.replace('.', '_')
|
identifier = identifier.replace(".", "_")
|
||||||
return identifier
|
return identifier
|
||||||
|
|
||||||
def impl_is_dynoptiondescription(self) -> bool:
|
def impl_is_dynoptiondescription(self) -> bool:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def option_is_self(self,
|
def option_is_self(
|
||||||
option,
|
self,
|
||||||
) -> bool:
|
option,
|
||||||
|
) -> bool:
|
||||||
return option == self
|
return option == self
|
||||||
|
|
||||||
def impl_getname(self, identifier=None) -> str:
|
def impl_getname(self, identifier=None) -> str:
|
||||||
"""get name
|
"""get name"""
|
||||||
"""
|
|
||||||
name = super().impl_getname()
|
name = super().impl_getname()
|
||||||
if identifier is None:
|
if identifier is None:
|
||||||
return name
|
return name
|
||||||
path_identifier = self.convert_identifier_to_path(identifier)
|
path_identifier = self.convert_identifier_to_path(identifier)
|
||||||
return name + path_identifier
|
return name + path_identifier
|
||||||
|
|
||||||
def get_identifiers(self,
|
def get_identifiers(
|
||||||
parent: 'SubConfig',
|
self,
|
||||||
*,
|
parent: "SubConfig",
|
||||||
uncalculated: bool=False,
|
*,
|
||||||
) -> List[str]:
|
uncalculated: bool = False,
|
||||||
"""get dynamic identifiers
|
) -> List[str]:
|
||||||
"""
|
"""get dynamic identifiers"""
|
||||||
subconfig = parent.get_child(self,
|
subconfig = parent.get_child(
|
||||||
None,
|
self,
|
||||||
False,
|
None,
|
||||||
properties=None,
|
False,
|
||||||
)
|
properties=None,
|
||||||
|
)
|
||||||
identifiers = self._identifiers
|
identifiers = self._identifiers
|
||||||
if isinstance(identifiers, list):
|
if isinstance(identifiers, list):
|
||||||
identifiers = identifiers.copy()
|
identifiers = identifiers.copy()
|
||||||
if uncalculated:
|
if uncalculated:
|
||||||
return identifiers
|
return identifiers
|
||||||
values = get_calculated_value(subconfig,
|
values = get_calculated_value(
|
||||||
identifiers,
|
subconfig,
|
||||||
validate_properties=False,
|
identifiers,
|
||||||
)[0]
|
validate_properties=False,
|
||||||
|
)[0]
|
||||||
if values is None:
|
if values is None:
|
||||||
values = []
|
values = []
|
||||||
values_ = []
|
values_ = []
|
||||||
if __debug__:
|
if __debug__:
|
||||||
if not isinstance(values, list):
|
if not isinstance(values, list):
|
||||||
raise ValueError(_('DynOptionDescription identifiers for '
|
raise ValueError(
|
||||||
f'option {self.impl_get_display_name(subconfig, with_quote=True)}, is not '
|
_(
|
||||||
f'a list ({values})'))
|
"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:
|
for val in values:
|
||||||
cval = self.convert_identifier_to_path(val)
|
cval = self.convert_identifier_to_path(val)
|
||||||
if not isinstance(cval, str) or re.match(NAME_REGEXP, cval) is None:
|
if not isinstance(cval, str) or re.match(NAME_REGEXP, cval) is None:
|
||||||
if __debug__ and cval is not None:
|
if __debug__ and cval is not None:
|
||||||
raise ValueError(_('invalid identifier "{}" for option {}'
|
raise ValueError(
|
||||||
'').format(cval,
|
_('invalid identifier "{}" for option {}' "").format(
|
||||||
self.impl_get_display_name(subconfig, with_quote=True)))
|
cval, self.impl_get_display_name(subconfig, with_quote=True)
|
||||||
|
)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
values_.append(val)
|
values_.append(val)
|
||||||
if __debug__ and len(values_) > len(set(values_)):
|
if __debug__ and len(values_) > len(set(values_)):
|
||||||
raise ValueError(_(f'DynOptionDescription "{self._name}" identifiers return a list with '
|
raise ValueError(
|
||||||
f'same values "{values_}"'''))
|
_(
|
||||||
|
'DynOptionDescription "{0}" identifiers return a list with same values "{1}"'
|
||||||
|
).format(self._name, values_)
|
||||||
|
)
|
||||||
return values_
|
return values_
|
||||||
|
|
|
@ -27,8 +27,10 @@ from .stroption import RegexpOption
|
||||||
|
|
||||||
|
|
||||||
class EmailOption(RegexpOption):
|
class EmailOption(RegexpOption):
|
||||||
"""represents a choice of an email
|
"""represents a choice of an email"""
|
||||||
"""
|
|
||||||
__slots__ = tuple()
|
__slots__ = tuple()
|
||||||
_regexp = re.compile(r"^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$")
|
_regexp = re.compile(
|
||||||
_type = 'email address'
|
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):
|
class FilenameOption(StrOption):
|
||||||
"""validate file or directory name
|
"""validate file or directory name"""
|
||||||
"""
|
|
||||||
__slots__ = tuple()
|
__slots__ = tuple()
|
||||||
_type = 'file name'
|
_type = "file name"
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
name: str,
|
self,
|
||||||
*args,
|
name: str,
|
||||||
allow_relative=False,
|
*args,
|
||||||
test_existence=False,
|
allow_relative=False,
|
||||||
types=['file', 'directory'],
|
test_existence=False,
|
||||||
**kwargs):
|
types=["file", "directory"],
|
||||||
|
**kwargs,
|
||||||
|
):
|
||||||
if not isinstance(types, list):
|
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:
|
for typ in types:
|
||||||
if typ not in ['file', 'directory']:
|
if typ not in ["file", "directory"]:
|
||||||
raise ValueError(f'unknown type "{typ}" for "{name}"')
|
raise ValueError(f'unknown type "{typ}" for "{name}"')
|
||||||
extra = {'_allow_relative': allow_relative,
|
extra = {
|
||||||
'_test_existence': test_existence,
|
"_allow_relative": allow_relative,
|
||||||
'_types': types,
|
"_test_existence": test_existence,
|
||||||
}
|
"_types": types,
|
||||||
super().__init__(name,
|
}
|
||||||
*args,
|
super().__init__(name, *args, extra=extra, **kwargs)
|
||||||
extra=extra,
|
|
||||||
**kwargs)
|
|
||||||
|
|
||||||
def validate(self,
|
def validate(
|
||||||
value: str,
|
self,
|
||||||
) -> None:
|
value: str,
|
||||||
|
) -> None:
|
||||||
super().validate(value)
|
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 "/"'))
|
raise ValueError(_('must starts with "/"'))
|
||||||
if value is not None and self.impl_get_extra('_test_existence'):
|
if value is not None and self.impl_get_extra("_test_existence"):
|
||||||
types = self.impl_get_extra('_types')
|
types = self.impl_get_extra("_types")
|
||||||
file = Path(value)
|
file = Path(value)
|
||||||
found = False
|
found = False
|
||||||
if 'file' in types and file.is_file():
|
if "file" in types and file.is_file():
|
||||||
found = True
|
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
|
found = True
|
||||||
if not found:
|
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):
|
class FloatOption(Option):
|
||||||
"""represents a choice of a floating point number
|
"""represents a choice of a floating point number"""
|
||||||
"""
|
|
||||||
__slots__ = tuple()
|
|
||||||
_type = 'float'
|
|
||||||
|
|
||||||
def validate(self,
|
__slots__ = tuple()
|
||||||
value: float) -> None:
|
_type = "float"
|
||||||
|
|
||||||
|
def validate(self, value: float) -> None:
|
||||||
if not isinstance(value, float):
|
if not isinstance(value, float):
|
||||||
raise ValueError()
|
raise ValueError()
|
||||||
|
|
|
@ -28,40 +28,35 @@ from .option import Option
|
||||||
class IntOption(Option):
|
class IntOption(Option):
|
||||||
"represents a choice of an integer"
|
"represents a choice of an integer"
|
||||||
__slots__ = tuple()
|
__slots__ = tuple()
|
||||||
_type = 'integer'
|
_type = "integer"
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self, *args, min_number=None, max_number=None, **kwargs):
|
||||||
*args,
|
|
||||||
min_number=None,
|
|
||||||
max_number=None,
|
|
||||||
**kwargs):
|
|
||||||
extra = {}
|
extra = {}
|
||||||
if min_number is not None:
|
if min_number is not None:
|
||||||
extra['min_number'] = min_number
|
extra["min_number"] = min_number
|
||||||
if max_number is not None:
|
if max_number is not None:
|
||||||
extra['max_number'] = max_number
|
extra["max_number"] = max_number
|
||||||
super().__init__(*args, extra=extra, **kwargs)
|
super().__init__(*args, extra=extra, **kwargs)
|
||||||
|
|
||||||
def validate(self,
|
def validate(
|
||||||
value: int,
|
self,
|
||||||
) -> None:
|
value: int,
|
||||||
|
) -> None:
|
||||||
if not isinstance(value, int):
|
if not isinstance(value, int):
|
||||||
raise ValueError()
|
raise ValueError()
|
||||||
|
|
||||||
def second_level_validation(self,
|
def second_level_validation(self, value, warnings_only):
|
||||||
value,
|
min_number = self.impl_get_extra("min_number")
|
||||||
warnings_only):
|
|
||||||
min_number = self.impl_get_extra('min_number')
|
|
||||||
if min_number is not None and value < min_number:
|
if min_number is not None and value < min_number:
|
||||||
if warnings_only:
|
if warnings_only:
|
||||||
msg = 'value should be equal or greater than "{0}"'
|
msg = _('value should be equal or greater than "{0}"')
|
||||||
else:
|
else:
|
||||||
msg = 'value must be equal or greater than "{0}"'
|
msg = _('value must be equal or greater than "{0}"')
|
||||||
raise ValueError(_(msg).format(min_number))
|
raise ValueError(msg.format(min_number))
|
||||||
max_number = self.impl_get_extra('max_number')
|
max_number = self.impl_get_extra("max_number")
|
||||||
if max_number is not None and value > max_number:
|
if max_number is not None and value > max_number:
|
||||||
if warnings_only:
|
if warnings_only:
|
||||||
msg = 'value should be less than "{0}"'
|
msg = _('value should be less than "{0}"')
|
||||||
else:
|
else:
|
||||||
msg = 'value must be less than "{0}"'
|
msg = _('value must be less than "{0}"')
|
||||||
raise ValueError(_(msg).format(max_number))
|
raise ValueError(msg.format(max_number))
|
||||||
|
|
|
@ -27,26 +27,26 @@ from .stroption import StrOption
|
||||||
|
|
||||||
|
|
||||||
class IPOption(StrOption):
|
class IPOption(StrOption):
|
||||||
"""represents the choice of an ip
|
"""represents the choice of an ip"""
|
||||||
"""
|
|
||||||
__slots__ = tuple()
|
|
||||||
_type = 'IP'
|
|
||||||
|
|
||||||
def __init__(self,
|
__slots__ = tuple()
|
||||||
*args,
|
_type = "IP"
|
||||||
private_only=False,
|
|
||||||
allow_reserved=False,
|
def __init__(
|
||||||
cidr=False,
|
self,
|
||||||
extra=None,
|
*args,
|
||||||
**kwargs):
|
private_only=False,
|
||||||
|
allow_reserved=False,
|
||||||
|
cidr=False,
|
||||||
|
extra=None,
|
||||||
|
**kwargs,
|
||||||
|
):
|
||||||
if extra is None:
|
if extra is None:
|
||||||
extra = {}
|
extra = {}
|
||||||
extra['_private_only'] = private_only
|
extra["_private_only"] = private_only
|
||||||
extra['_allow_reserved'] = allow_reserved
|
extra["_allow_reserved"] = allow_reserved
|
||||||
extra['_cidr'] = cidr
|
extra["_cidr"] = cidr
|
||||||
super().__init__(*args,
|
super().__init__(*args, extra=extra, **kwargs)
|
||||||
extra=extra,
|
|
||||||
**kwargs)
|
|
||||||
|
|
||||||
def _validate_cidr(self, value):
|
def _validate_cidr(self, value):
|
||||||
try:
|
try:
|
||||||
|
@ -64,27 +64,24 @@ class IPOption(StrOption):
|
||||||
except ValueError as err:
|
except ValueError as err:
|
||||||
raise ValueError() from err
|
raise ValueError() from err
|
||||||
|
|
||||||
def validate(self,
|
def validate(self, value: str) -> None:
|
||||||
value: str) -> None:
|
|
||||||
super().validate(value)
|
super().validate(value)
|
||||||
if self.impl_get_extra('_cidr'):
|
if self.impl_get_extra("_cidr"):
|
||||||
if '/' not in value:
|
if "/" not in value:
|
||||||
raise ValueError(_('CIDR address must have a "/"'))
|
raise ValueError(_('CIDR address must have a "/"'))
|
||||||
self._validate_cidr(value)
|
self._validate_cidr(value)
|
||||||
else:
|
else:
|
||||||
self._validate_ip(value)
|
self._validate_ip(value)
|
||||||
|
|
||||||
def second_level_validation(self,
|
def second_level_validation(self, value: str, warnings_only: bool) -> None:
|
||||||
value: str,
|
|
||||||
warnings_only: bool) -> None:
|
|
||||||
ip_obj = ip_interface(value)
|
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:
|
if warnings_only:
|
||||||
msg = _("shouldn't be reserved IP")
|
msg = _("shouldn't be reserved IP")
|
||||||
else:
|
else:
|
||||||
msg = _("mustn't be reserved IP")
|
msg = _("mustn't be reserved IP")
|
||||||
raise ValueError(msg)
|
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:
|
if warnings_only:
|
||||||
msg = _("should be private IP")
|
msg = _("should be private IP")
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -26,6 +26,7 @@ from typing import List, Iterator, Optional
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from ..setting import groups, undefined, ALLOWED_LEADER_PROPERTIES
|
from ..setting import groups, undefined, ALLOWED_LEADER_PROPERTIES
|
||||||
from .optiondescription import OptionDescription
|
from .optiondescription import OptionDescription
|
||||||
|
|
||||||
# from .syndynoption import SynDynLeadership
|
# from .syndynoption import SynDynLeadership
|
||||||
from .baseoption import BaseOption
|
from .baseoption import BaseOption
|
||||||
from .option import Option
|
from .option import Option
|
||||||
|
@ -34,31 +35,39 @@ from ..autolib import Calculation
|
||||||
|
|
||||||
|
|
||||||
class Leadership(OptionDescription):
|
class Leadership(OptionDescription):
|
||||||
"""Leadership
|
"""Leadership"""
|
||||||
"""
|
|
||||||
# pylint: disable=too-many-arguments
|
|
||||||
__slots__ = ('leader',
|
|
||||||
'followers',
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(self,
|
# pylint: disable=too-many-arguments
|
||||||
name: str,
|
__slots__ = (
|
||||||
doc,
|
"leader",
|
||||||
children: List[BaseOption],
|
"followers",
|
||||||
**kwargs,
|
)
|
||||||
) -> None:
|
|
||||||
if 'group_type' in kwargs:
|
def __init__(
|
||||||
raise LeadershipError(_('cannot set "group_type" attribute for a Leadership'))
|
self,
|
||||||
super().__init__(name,
|
name: str,
|
||||||
doc,
|
doc,
|
||||||
children,
|
children: List[BaseOption],
|
||||||
**kwargs,
|
**kwargs,
|
||||||
)
|
) -> None:
|
||||||
|
if "group_type" in kwargs:
|
||||||
|
raise LeadershipError(
|
||||||
|
_('cannot set "group_type" attribute for a Leadership')
|
||||||
|
)
|
||||||
|
super().__init__(
|
||||||
|
name,
|
||||||
|
doc,
|
||||||
|
children,
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
self._group_type = groups.leadership
|
self._group_type = groups.leadership
|
||||||
followers = []
|
followers = []
|
||||||
if len(children) < 2:
|
if len(children) < 2:
|
||||||
raise ValueError(_('a leader and a follower are mandatories in leadership "{}"'
|
raise ValueError(
|
||||||
'').format(name))
|
_(
|
||||||
|
'a leader and a follower are mandatories in leadership "{}"' ""
|
||||||
|
).format(name)
|
||||||
|
)
|
||||||
for idx, child in enumerate(children):
|
for idx, child in enumerate(children):
|
||||||
if __debug__:
|
if __debug__:
|
||||||
self._check_child_is_valid(child, idx, children)
|
self._check_child_is_valid(child, idx, children)
|
||||||
|
@ -66,34 +75,51 @@ class Leadership(OptionDescription):
|
||||||
if __debug__:
|
if __debug__:
|
||||||
self._check_default_value(child)
|
self._check_default_value(child)
|
||||||
# remove empty property for follower
|
# remove empty property for follower
|
||||||
child._properties = frozenset(child._properties - {'empty', 'unique'})
|
child._properties = frozenset(child._properties - {"empty", "unique"})
|
||||||
followers.append(child)
|
followers.append(child)
|
||||||
child._add_dependency(self)
|
child._add_dependency(self)
|
||||||
child._leadership = weakref.ref(self)
|
child._leadership = weakref.ref(self)
|
||||||
if __debug__:
|
if __debug__:
|
||||||
leader = children[0]
|
leader = children[0]
|
||||||
for prop in leader.impl_getproperties():
|
for prop in leader.impl_getproperties():
|
||||||
if prop not in ALLOWED_LEADER_PROPERTIES and not isinstance(prop, Calculation):
|
if prop not in ALLOWED_LEADER_PROPERTIES and not isinstance(
|
||||||
raise LeadershipError(_('leader cannot have "{}" property').format(prop))
|
prop, Calculation
|
||||||
|
):
|
||||||
|
raise LeadershipError(
|
||||||
|
_('leader cannot have "{}" property').format(prop)
|
||||||
|
)
|
||||||
|
|
||||||
def _check_child_is_valid(self,
|
def _check_child_is_valid(
|
||||||
child: BaseOption,
|
self,
|
||||||
index: int,
|
child: BaseOption,
|
||||||
children: [BaseOption],
|
index: int,
|
||||||
) -> None:
|
children: [BaseOption],
|
||||||
|
) -> None:
|
||||||
if child.impl_is_symlinkoption():
|
if child.impl_is_symlinkoption():
|
||||||
if not index:
|
if not index:
|
||||||
raise ValueError(_('leadership {0} shall not have '
|
raise ValueError(
|
||||||
"a symlinkoption").format(self.impl_get_display_name(None, with_quote=True)))
|
_("leadership {0} shall not have " "a symlinkoption").format(
|
||||||
|
self.impl_get_display_name(None, with_quote=True)
|
||||||
|
)
|
||||||
|
)
|
||||||
return
|
return
|
||||||
if not isinstance(child, Option):
|
if not isinstance(child, Option):
|
||||||
raise ValueError(_('leadership {0} shall not have '
|
raise ValueError(
|
||||||
'a subgroup').format(self.impl_get_display_name(None, with_quote=True)))
|
_("leadership {0} shall not have " "a subgroup").format(
|
||||||
|
self.impl_get_display_name(None, with_quote=True)
|
||||||
|
)
|
||||||
|
)
|
||||||
if not child.impl_is_multi():
|
if not child.impl_is_multi():
|
||||||
raise ValueError(_('only multi option allowed in leadership {0} but option '
|
raise ValueError(
|
||||||
'{1} is not a multi'
|
_(
|
||||||
'').format(self.impl_get_display_name(None, with_quote=True),
|
"only multi option allowed in leadership {0} but option "
|
||||||
child.impl_get_display_name(None, with_quote=True)))
|
"{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):
|
def _check_default_value(self, child: BaseOption):
|
||||||
if child.impl_is_symlinkoption():
|
if child.impl_is_symlinkoption():
|
||||||
|
@ -111,78 +137,84 @@ class Leadership(OptionDescription):
|
||||||
else:
|
else:
|
||||||
calculation = isinstance(default, Calculation)
|
calculation = isinstance(default, Calculation)
|
||||||
if not calculation:
|
if not calculation:
|
||||||
raise ValueError(_('not allowed default value for follower option '
|
raise ValueError(
|
||||||
f'{child.impl_get_display_name(None, with_quote=True)} in leadership '
|
_(
|
||||||
f'{self.impl_get_display_name(None, with_quote=True)}'))
|
"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(
|
||||||
subdyn,
|
self,
|
||||||
) -> None:
|
subdyn,
|
||||||
|
) -> None:
|
||||||
for chld in self._children[1]:
|
for chld in self._children[1]:
|
||||||
chld._setsubdyn(subdyn)
|
chld._setsubdyn(subdyn)
|
||||||
super()._setsubdyn(subdyn)
|
super()._setsubdyn(subdyn)
|
||||||
|
|
||||||
def is_leader(self,
|
def is_leader(
|
||||||
opt: Option,
|
self,
|
||||||
) -> bool:
|
opt: Option,
|
||||||
"""the option is the leader
|
) -> bool:
|
||||||
"""
|
"""the option is the leader"""
|
||||||
leader = self.get_leader()
|
leader = self.get_leader()
|
||||||
if opt.impl_is_dynsymlinkoption():
|
if opt.impl_is_dynsymlinkoption():
|
||||||
opt = opt.opt
|
opt = opt.opt
|
||||||
return opt == leader
|
return opt == leader
|
||||||
|
|
||||||
def get_leader(self) -> Option:
|
def get_leader(self) -> Option:
|
||||||
"""get leader
|
"""get leader"""
|
||||||
"""
|
|
||||||
return self._children[1][0]
|
return self._children[1][0]
|
||||||
|
|
||||||
def get_followers(self) -> Iterator[Option]:
|
def get_followers(self) -> Iterator[Option]:
|
||||||
"""get all followers
|
"""get all followers"""
|
||||||
"""
|
|
||||||
for follower in self._children[1][1:]:
|
for follower in self._children[1][1:]:
|
||||||
yield follower
|
yield follower
|
||||||
|
|
||||||
def in_same_leadership(self,
|
def in_same_leadership(
|
||||||
opt: Option,
|
self,
|
||||||
) -> bool:
|
opt: Option,
|
||||||
"""check if followers are in same leadership
|
) -> bool:
|
||||||
"""
|
"""check if followers are in same leadership"""
|
||||||
if opt.impl_is_dynsymlinkoption():
|
if opt.impl_is_dynsymlinkoption():
|
||||||
opt = opt.opt
|
opt = opt.opt
|
||||||
return opt in self._children[1]
|
return opt in self._children[1]
|
||||||
|
|
||||||
def reset(self, parent: "SubConfig") -> None:
|
def reset(self, parent: "SubConfig") -> None:
|
||||||
"""reset follower value
|
"""reset follower value"""
|
||||||
"""
|
|
||||||
values = parent.config_bag.context.get_values()
|
values = parent.config_bag.context.get_values()
|
||||||
for follower in self.get_followers():
|
for follower in self.get_followers():
|
||||||
subconfig_follower = parent.get_child(follower,
|
subconfig_follower = parent.get_child(
|
||||||
None,
|
follower,
|
||||||
False,
|
None,
|
||||||
)
|
False,
|
||||||
values.reset(subconfig_follower,
|
)
|
||||||
validate=False,
|
values.reset(
|
||||||
)
|
subconfig_follower,
|
||||||
|
validate=False,
|
||||||
|
)
|
||||||
|
|
||||||
def follower_force_store_value(self,
|
def follower_force_store_value(
|
||||||
value,
|
self,
|
||||||
subconfig: 'SubConfig',
|
value,
|
||||||
owner,
|
subconfig: "SubConfig",
|
||||||
) -> None:
|
owner,
|
||||||
"""apply force_store_value to follower
|
) -> None:
|
||||||
"""
|
"""apply force_store_value to follower"""
|
||||||
if not value:
|
if not value:
|
||||||
return
|
return
|
||||||
config_bag = subconfig.config_bag
|
config_bag = subconfig.config_bag
|
||||||
values = config_bag.context.get_values()
|
values = config_bag.context.get_values()
|
||||||
for idx, follower in enumerate(self.get_children()):
|
for idx, follower in enumerate(self.get_children()):
|
||||||
sub_subconfig = subconfig.get_child(follower,
|
sub_subconfig = subconfig.get_child(
|
||||||
None,
|
follower,
|
||||||
False,
|
None,
|
||||||
config_bag=config_bag,
|
False,
|
||||||
)
|
config_bag=config_bag,
|
||||||
if 'force_store_value' not in sub_subconfig.properties:
|
)
|
||||||
|
if "force_store_value" not in sub_subconfig.properties:
|
||||||
continue
|
continue
|
||||||
self_path = sub_subconfig.path
|
self_path = sub_subconfig.path
|
||||||
if not idx:
|
if not idx:
|
||||||
|
@ -193,25 +225,27 @@ class Leadership(OptionDescription):
|
||||||
apply_requires = False
|
apply_requires = False
|
||||||
indexes = range(len(value))
|
indexes = range(len(value))
|
||||||
for index in indexes:
|
for index in indexes:
|
||||||
i_sub_subconfig = subconfig.get_child(follower,
|
i_sub_subconfig = subconfig.get_child(
|
||||||
index,
|
follower,
|
||||||
False,
|
index,
|
||||||
config_bag=config_bag,
|
False,
|
||||||
)
|
config_bag=config_bag,
|
||||||
values.set_storage_value(self_path,
|
)
|
||||||
index,
|
values.set_storage_value(
|
||||||
values.get_value(i_sub_subconfig)[0],
|
self_path,
|
||||||
owner,
|
index,
|
||||||
)
|
values.get_value(i_sub_subconfig)[0],
|
||||||
|
owner,
|
||||||
|
)
|
||||||
|
|
||||||
def pop(self,
|
def pop(
|
||||||
subconfig: 'SubConfig',
|
self,
|
||||||
index: int,
|
subconfig: "SubConfig",
|
||||||
*,
|
index: int,
|
||||||
followers: Optional[List[Option]]=undefined,
|
*,
|
||||||
) -> None:
|
followers: Optional[List[Option]] = undefined,
|
||||||
"""pop leader value and follower's one
|
) -> None:
|
||||||
"""
|
"""pop leader value and follower's one"""
|
||||||
if followers is undefined:
|
if followers is undefined:
|
||||||
# followers are not undefined only in SynDynLeadership
|
# followers are not undefined only in SynDynLeadership
|
||||||
followers = self.get_followers()
|
followers = self.get_followers()
|
||||||
|
@ -219,51 +253,58 @@ class Leadership(OptionDescription):
|
||||||
config_bag.remove_validation()
|
config_bag.remove_validation()
|
||||||
values = config_bag.context.get_values()
|
values = config_bag.context.get_values()
|
||||||
for follower in followers:
|
for follower in followers:
|
||||||
sub_subconfig = subconfig.parent.get_child(follower,
|
sub_subconfig = subconfig.parent.get_child(
|
||||||
index,
|
follower,
|
||||||
True,
|
index,
|
||||||
properties=set(), # do not check force_default_on_freeze
|
True,
|
||||||
# or force_metaconfig_on_freeze
|
properties=set(), # do not check force_default_on_freeze
|
||||||
config_bag=config_bag,
|
# or force_metaconfig_on_freeze
|
||||||
)
|
config_bag=config_bag,
|
||||||
|
)
|
||||||
values.reduce_index(sub_subconfig)
|
values.reduce_index(sub_subconfig)
|
||||||
|
|
||||||
def reset_cache(self,
|
def reset_cache(
|
||||||
path: str,
|
self,
|
||||||
config_bag: 'ConfigBag',
|
path: str,
|
||||||
resetted_opts: List[Option],
|
config_bag: "ConfigBag",
|
||||||
) -> None:
|
resetted_opts: List[Option],
|
||||||
self._reset_cache(path,
|
) -> None:
|
||||||
self.get_leader(),
|
self._reset_cache(
|
||||||
self.get_followers(),
|
path,
|
||||||
config_bag,
|
self.get_leader(),
|
||||||
resetted_opts,
|
self.get_followers(),
|
||||||
)
|
config_bag,
|
||||||
|
resetted_opts,
|
||||||
|
)
|
||||||
|
|
||||||
def _reset_cache(self,
|
def _reset_cache(
|
||||||
path: str,
|
self,
|
||||||
leader: Option,
|
path: str,
|
||||||
followers: List[Option],
|
leader: Option,
|
||||||
config_bag: 'ConfigBag',
|
followers: List[Option],
|
||||||
resetted_opts: List[Option],
|
config_bag: "ConfigBag",
|
||||||
) -> None:
|
resetted_opts: List[Option],
|
||||||
super().reset_cache(path,
|
) -> None:
|
||||||
config_bag,
|
super().reset_cache(
|
||||||
resetted_opts,
|
path,
|
||||||
)
|
config_bag,
|
||||||
|
resetted_opts,
|
||||||
|
)
|
||||||
leader_path = leader.impl_getpath()
|
leader_path = leader.impl_getpath()
|
||||||
if leader_path not in resetted_opts:
|
if leader_path not in resetted_opts:
|
||||||
leader.reset_cache(leader_path,
|
leader.reset_cache(
|
||||||
config_bag,
|
leader_path,
|
||||||
resetted_opts,
|
config_bag,
|
||||||
)
|
resetted_opts,
|
||||||
|
)
|
||||||
for follower in followers:
|
for follower in followers:
|
||||||
follower_path = follower.impl_getpath()
|
follower_path = follower.impl_getpath()
|
||||||
if follower_path not in resetted_opts:
|
if follower_path not in resetted_opts:
|
||||||
follower.reset_cache(follower_path,
|
follower.reset_cache(
|
||||||
config_bag,
|
follower_path,
|
||||||
resetted_opts,
|
config_bag,
|
||||||
)
|
resetted_opts,
|
||||||
|
)
|
||||||
|
|
||||||
def impl_is_leadership(self) -> None:
|
def impl_is_leadership(self) -> None:
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -27,8 +27,8 @@ from .stroption import RegexpOption
|
||||||
|
|
||||||
|
|
||||||
class MACOption(RegexpOption):
|
class MACOption(RegexpOption):
|
||||||
"""represents the choice of a mac address
|
"""represents the choice of a mac address"""
|
||||||
"""
|
|
||||||
__slots__ = tuple()
|
__slots__ = tuple()
|
||||||
_regexp = re.compile(r"^([0-9A-Fa-f]{2}[:]){5}([0-9A-Fa-f]{2})$")
|
_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):
|
class NetmaskOption(StrOption):
|
||||||
"""represents the choice of a netmask
|
"""represents the choice of a netmask"""
|
||||||
"""
|
|
||||||
__slots__ = tuple()
|
|
||||||
_type = 'netmask address'
|
|
||||||
|
|
||||||
def validate(self,
|
__slots__ = tuple()
|
||||||
value: str) -> None:
|
_type = "netmask address"
|
||||||
|
|
||||||
|
def validate(self, value: str) -> None:
|
||||||
super().validate(value)
|
super().validate(value)
|
||||||
for val in value.split('.'):
|
for val in value.split("."):
|
||||||
if val.startswith("0") and len(val) > 1:
|
if val.startswith("0") and len(val) > 1:
|
||||||
raise ValueError()
|
raise ValueError()
|
||||||
try:
|
try:
|
||||||
ip_network(f'0.0.0.0/{value}')
|
ip_network(f"0.0.0.0/{value}")
|
||||||
except ValueError as err:
|
except ValueError as err:
|
||||||
raise ValueError() from err
|
raise ValueError() from err
|
||||||
|
|
|
@ -29,30 +29,24 @@ from .stroption import StrOption
|
||||||
class NetworkOption(StrOption):
|
class NetworkOption(StrOption):
|
||||||
"represents the choice of a network"
|
"represents the choice of a network"
|
||||||
__slots__ = tuple()
|
__slots__ = tuple()
|
||||||
_type = 'network address'
|
_type = "network address"
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self, *args, cidr=False, **kwargs):
|
||||||
*args,
|
extra = {"_cidr": cidr}
|
||||||
cidr=False,
|
super().__init__(*args, extra=extra, **kwargs)
|
||||||
**kwargs):
|
|
||||||
extra = {'_cidr': cidr}
|
|
||||||
super().__init__(*args,
|
|
||||||
extra=extra,
|
|
||||||
**kwargs)
|
|
||||||
|
|
||||||
def validate(self,
|
def validate(self, value: str) -> None:
|
||||||
value: str) -> None:
|
|
||||||
super().validate(value)
|
super().validate(value)
|
||||||
if value.count('.') != 3:
|
if value.count(".") != 3:
|
||||||
raise ValueError()
|
raise ValueError()
|
||||||
cidr = self.impl_get_extra('_cidr')
|
cidr = self.impl_get_extra("_cidr")
|
||||||
if cidr:
|
if cidr:
|
||||||
if '/' not in value:
|
if "/" not in value:
|
||||||
raise ValueError(_('must use CIDR notation'))
|
raise ValueError(_("must use CIDR notation"))
|
||||||
value_ = value.split('/')[0]
|
value_ = value.split("/")[0]
|
||||||
else:
|
else:
|
||||||
value_ = value
|
value_ = value
|
||||||
for val in value_.split('.'):
|
for val in value_.split("."):
|
||||||
if val.startswith("0") and len(val) > 1:
|
if val.startswith("0") and len(val) > 1:
|
||||||
raise ValueError()
|
raise ValueError()
|
||||||
try:
|
try:
|
||||||
|
@ -60,9 +54,7 @@ class NetworkOption(StrOption):
|
||||||
except ValueError as err:
|
except ValueError as err:
|
||||||
raise ValueError() from err
|
raise ValueError() from err
|
||||||
|
|
||||||
def second_level_validation(self,
|
def second_level_validation(self, value: str, warnings_only: bool) -> None:
|
||||||
value: str,
|
|
||||||
warnings_only: bool) -> None:
|
|
||||||
if ip_network(value).network_address.is_reserved:
|
if ip_network(value).network_address.is_reserved:
|
||||||
if warnings_only:
|
if warnings_only:
|
||||||
msg = _("shouldn't be reserved network")
|
msg = _("shouldn't be reserved network")
|
||||||
|
|
|
@ -37,37 +37,43 @@ class Option(BaseOption):
|
||||||
|
|
||||||
Reminder: an Option object is **not** a container for the value.
|
Reminder: an Option object is **not** a container for the value.
|
||||||
"""
|
"""
|
||||||
__slots__ = ('_extra',
|
__slots__ = (
|
||||||
'_warnings_only',
|
"_extra",
|
||||||
# multi
|
"_warnings_only",
|
||||||
'_multi',
|
# multi
|
||||||
# value
|
"_multi",
|
||||||
'_default',
|
# value
|
||||||
'_default_multi',
|
"_default",
|
||||||
#
|
"_default_multi",
|
||||||
'_validators',
|
#
|
||||||
#
|
"_validators",
|
||||||
'_leadership',
|
#
|
||||||
'_choice_values',
|
"_leadership",
|
||||||
'_choice_values_params',
|
"_choice_values",
|
||||||
)
|
"_choice_values_params",
|
||||||
|
)
|
||||||
_type = None
|
_type = None
|
||||||
def __init__(self,
|
|
||||||
name: str,
|
def __init__(
|
||||||
doc: str,
|
self,
|
||||||
default: Any=undefined,
|
name: str,
|
||||||
default_multi: Any=None,
|
doc: str,
|
||||||
multi: bool=False,
|
default: Any = undefined,
|
||||||
validators: Optional[List[Calculation]]=None,
|
default_multi: Any = None,
|
||||||
properties: Optional[List[str]]=None,
|
multi: bool = False,
|
||||||
warnings_only: bool=False,
|
validators: Optional[List[Calculation]] = None,
|
||||||
extra: Optional[Dict]=None,
|
properties: Optional[List[str]] = None,
|
||||||
informations: Optional[Dict]=None,
|
warnings_only: bool = False,
|
||||||
):
|
extra: Optional[Dict] = None,
|
||||||
|
informations: Optional[Dict] = None,
|
||||||
|
):
|
||||||
_setattr = object.__setattr__
|
_setattr = object.__setattr__
|
||||||
if not multi and default_multi is not None:
|
if not multi and default_multi is not None:
|
||||||
raise ValueError(_("default_multi is set whereas multi is False"
|
raise ValueError(
|
||||||
" in option: {0}").format(name))
|
_(
|
||||||
|
"default_multi is set whereas multi is False" " in option: {0}"
|
||||||
|
).format(name)
|
||||||
|
)
|
||||||
if default is undefined:
|
if default is undefined:
|
||||||
if multi is False:
|
if multi is False:
|
||||||
default = None
|
default = None
|
||||||
|
@ -83,117 +89,140 @@ class Option(BaseOption):
|
||||||
is_multi = True
|
is_multi = True
|
||||||
_multi = submulti
|
_multi = submulti
|
||||||
else:
|
else:
|
||||||
raise ValueError(_('invalid multi type "{}" for "{}"').format(multi,
|
raise ValueError(
|
||||||
name,
|
_('invalid multi type "{}" for "{}"').format(
|
||||||
))
|
multi,
|
||||||
|
name,
|
||||||
|
)
|
||||||
|
)
|
||||||
if _multi != 1:
|
if _multi != 1:
|
||||||
_setattr(self, '_multi', _multi)
|
_setattr(self, "_multi", _multi)
|
||||||
if multi is not False and default is None:
|
if multi is not False and default is None:
|
||||||
default = []
|
default = []
|
||||||
super().__init__(name,
|
super().__init__(
|
||||||
doc,
|
name,
|
||||||
informations,
|
doc,
|
||||||
properties=properties,
|
informations,
|
||||||
is_multi=is_multi,
|
properties=properties,
|
||||||
)
|
is_multi=is_multi,
|
||||||
|
)
|
||||||
if validators is not None:
|
if validators is not None:
|
||||||
if __debug__ and not isinstance(validators, list):
|
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:
|
for validator in validators:
|
||||||
if __debug__ and not isinstance(validator, Calculation):
|
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.value_dependency(validator)
|
||||||
self._validators = tuple(validators)
|
self._validators = tuple(validators)
|
||||||
if extra is not None and extra != {}:
|
if extra is not None and extra != {}:
|
||||||
_setattr(self, '_extra', extra)
|
_setattr(self, "_extra", extra)
|
||||||
if warnings_only is True:
|
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:
|
if is_multi and default_multi is not None:
|
||||||
|
|
||||||
def test_multi_value(value):
|
def test_multi_value(value):
|
||||||
if isinstance(value, Calculation):
|
if isinstance(value, Calculation):
|
||||||
return
|
return
|
||||||
# option_bag = OptionBag(self,
|
# option_bag = OptionBag(self,
|
||||||
# None,
|
# None,
|
||||||
# undefined,
|
# undefined,
|
||||||
# properties=None,
|
# properties=None,
|
||||||
# )
|
# )
|
||||||
try:
|
try:
|
||||||
self.validate(value)
|
self.validate(value)
|
||||||
self.validate_with_option(value,
|
self.validate_with_option(
|
||||||
None,
|
value,
|
||||||
loaded=True,
|
None,
|
||||||
)
|
loaded=True,
|
||||||
|
)
|
||||||
except ValueError as err:
|
except ValueError as err:
|
||||||
str_err = str(err)
|
str_err = str(err)
|
||||||
if not str_err:
|
if not str_err:
|
||||||
raise ValueError(_('invalid default_multi value "{0}" '
|
raise ValueError(
|
||||||
'for option {1}').format(str(value),
|
_(
|
||||||
self.impl_get_display_name(None, with_quote=True))
|
'invalid default_multi value "{0}" ' "for option {1}"
|
||||||
) from err
|
).format(
|
||||||
raise ValueError(_(f'invalid default_multi value "{value}" for option '
|
str(value),
|
||||||
f'{self.impl_get_display_name(None, with_quote=True)}, {str_err}')
|
self.impl_get_display_name(None, with_quote=True),
|
||||||
) from err
|
)
|
||||||
|
) from 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 _multi is submulti:
|
||||||
if not isinstance(default_multi, Calculation):
|
if not isinstance(default_multi, Calculation):
|
||||||
if not isinstance(default_multi, list):
|
if not isinstance(default_multi, list):
|
||||||
raise ValueError(_('invalid default_multi value "{0}" '
|
raise ValueError(
|
||||||
'for option {1}, must be a list for a submulti'
|
_(
|
||||||
'').format(str(default_multi),
|
'invalid default_multi value "{0}" '
|
||||||
self.impl_get_display_name(None, with_quote=True)))
|
"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:
|
for value in default_multi:
|
||||||
test_multi_value(value)
|
test_multi_value(value)
|
||||||
else:
|
else:
|
||||||
test_multi_value(default_multi)
|
test_multi_value(default_multi)
|
||||||
_setattr(self, '_default_multi', default_multi)
|
_setattr(self, "_default_multi", default_multi)
|
||||||
# option_bag = OptionBag(self,
|
# option_bag = OptionBag(self,
|
||||||
# None,
|
# None,
|
||||||
# undefined,
|
# undefined,
|
||||||
# properties=None,
|
# properties=None,
|
||||||
# )
|
# )
|
||||||
self.impl_validate(None,
|
self.impl_validate(
|
||||||
default,
|
None,
|
||||||
loaded=True,
|
default,
|
||||||
)
|
loaded=True,
|
||||||
self.impl_validate(None,
|
)
|
||||||
default,
|
self.impl_validate(
|
||||||
check_error=False,
|
None,
|
||||||
loaded=True,
|
default,
|
||||||
)
|
check_error=False,
|
||||||
|
loaded=True,
|
||||||
|
)
|
||||||
self.value_dependencies(default)
|
self.value_dependencies(default)
|
||||||
if (is_multi and default != []) or \
|
if (is_multi and default != []) or (not is_multi and default is not None):
|
||||||
(not is_multi and default is not None):
|
|
||||||
if is_multi and isinstance(default, list):
|
if is_multi and isinstance(default, list):
|
||||||
default = tuple(default)
|
default = tuple(default)
|
||||||
_setattr(self, '_default', default)
|
_setattr(self, "_default", default)
|
||||||
|
|
||||||
#__________________________________________________________________________
|
# __________________________________________________________________________
|
||||||
# option's information
|
# option's information
|
||||||
|
|
||||||
def impl_is_multi(self) -> bool:
|
def impl_is_multi(self) -> bool:
|
||||||
"""is it a multi option
|
"""is it a multi option"""
|
||||||
"""
|
return getattr(self, "_multi", 1) != 1
|
||||||
return getattr(self, '_multi', 1) != 1
|
|
||||||
|
|
||||||
def impl_is_submulti(self) -> bool:
|
def impl_is_submulti(self) -> bool:
|
||||||
"""is it a submulti option
|
"""is it a submulti option"""
|
||||||
"""
|
return getattr(self, "_multi", 1) == 2
|
||||||
return getattr(self, '_multi', 1) == 2
|
|
||||||
|
|
||||||
def impl_is_dynsymlinkoption(self) -> bool:
|
def impl_is_dynsymlinkoption(self) -> bool:
|
||||||
"""is a dynsymlinkoption?
|
"""is a dynsymlinkoption?"""
|
||||||
"""
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_type(self) -> str:
|
def get_type(self) -> str:
|
||||||
"""get the type of option
|
"""get the type of option"""
|
||||||
"""
|
|
||||||
return self._type
|
return self._type
|
||||||
|
|
||||||
def impl_getdefault(self) -> Any:
|
def impl_getdefault(self) -> Any:
|
||||||
"""accessing the default value
|
"""accessing the default value"""
|
||||||
"""
|
|
||||||
is_multi = self.impl_is_multi()
|
is_multi = self.impl_is_multi()
|
||||||
default = getattr(self, '_default', undefined)
|
default = getattr(self, "_default", undefined)
|
||||||
if default is undefined:
|
if default is undefined:
|
||||||
if is_multi:
|
if is_multi:
|
||||||
default = []
|
default = []
|
||||||
|
@ -204,162 +233,186 @@ class Option(BaseOption):
|
||||||
return default
|
return default
|
||||||
|
|
||||||
def impl_getdefault_multi(self) -> Any:
|
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():
|
if self.impl_is_submulti():
|
||||||
default_value = []
|
default_value = []
|
||||||
else:
|
else:
|
||||||
default_value = None
|
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(
|
||||||
key: str,
|
self,
|
||||||
) -> Any:
|
key: str,
|
||||||
"""if extra parameters are store get it
|
) -> Any:
|
||||||
"""
|
"""if extra parameters are store get it"""
|
||||||
extra = getattr(self, '_extra', {})
|
extra = getattr(self, "_extra", {})
|
||||||
if isinstance(extra, tuple):
|
if isinstance(extra, tuple):
|
||||||
if key in extra[0]:
|
if key in extra[0]:
|
||||||
return extra[1][extra[0].index(key)]
|
return extra[1][extra[0].index(key)]
|
||||||
return None
|
return None
|
||||||
return extra.get(key)
|
return extra.get(key)
|
||||||
|
|
||||||
#__________________________________________________________________________
|
# __________________________________________________________________________
|
||||||
# validator
|
# validator
|
||||||
def impl_validate(self,
|
def impl_validate(
|
||||||
subconfig: Optional["SubConfig"],
|
self,
|
||||||
value: Any,
|
subconfig: Optional["SubConfig"],
|
||||||
*,
|
value: Any,
|
||||||
check_error: bool=True,
|
*,
|
||||||
loaded: bool=False,
|
check_error: bool = True,
|
||||||
) -> bool:
|
loaded: bool = False,
|
||||||
|
) -> bool:
|
||||||
"""Return True if value is really valid
|
"""Return True if value is really valid
|
||||||
If not validate or invalid return it returns False
|
If not validate or invalid return it returns False
|
||||||
"""
|
"""
|
||||||
if check_error and subconfig and \
|
if (
|
||||||
not 'validator' in subconfig.config_bag.properties:
|
check_error
|
||||||
|
and subconfig
|
||||||
|
and not "validator" in subconfig.config_bag.properties
|
||||||
|
):
|
||||||
return False
|
return False
|
||||||
if subconfig:
|
if subconfig:
|
||||||
force_index = subconfig.index
|
force_index = subconfig.index
|
||||||
else:
|
else:
|
||||||
force_index = None
|
force_index = None
|
||||||
is_warnings_only = getattr(self, '_warnings_only', False)
|
is_warnings_only = getattr(self, "_warnings_only", False)
|
||||||
|
|
||||||
def _is_not_unique(value):
|
def _is_not_unique(value):
|
||||||
# if set(value) has not same length than value
|
# if set(value) has not same length than value
|
||||||
if not subconfig or not check_error or \
|
if not subconfig or not check_error or "unique" not in subconfig.properties:
|
||||||
'unique' not in subconfig.properties:
|
|
||||||
return
|
return
|
||||||
lvalue = [val for val in value if val is not None]
|
lvalue = [val for val in value if val is not None]
|
||||||
if len(set(lvalue)) == len(lvalue):
|
if len(set(lvalue)) == len(lvalue):
|
||||||
return
|
return
|
||||||
for idx, val in enumerate(value):
|
for idx, val in enumerate(value):
|
||||||
if val not in value[idx+1:]:
|
if val not in value[idx + 1 :]:
|
||||||
continue
|
continue
|
||||||
raise ValueError(_('the value "{}" is not unique'
|
raise ValueError(_('the value "{}" is not unique' "").format(val))
|
||||||
'').format(val))
|
|
||||||
|
|
||||||
def calculation_validator(val,
|
def calculation_validator(
|
||||||
_index,
|
val,
|
||||||
):
|
_index,
|
||||||
for validator in getattr(self, '_validators', []):
|
):
|
||||||
calc_is_warnings_only = hasattr(validator, 'warnings_only') and \
|
for validator in getattr(self, "_validators", []):
|
||||||
validator.warnings_only
|
calc_is_warnings_only = (
|
||||||
if ((check_error and not calc_is_warnings_only) or
|
hasattr(validator, "warnings_only") and validator.warnings_only
|
||||||
(not check_error and calc_is_warnings_only)):
|
)
|
||||||
|
if (check_error and not calc_is_warnings_only) or (
|
||||||
|
not check_error and calc_is_warnings_only
|
||||||
|
):
|
||||||
try:
|
try:
|
||||||
kwargs = {'allow_value_error': True,
|
kwargs = {
|
||||||
'force_value_warning': calc_is_warnings_only,
|
"allow_value_error": True,
|
||||||
}
|
"force_value_warning": calc_is_warnings_only,
|
||||||
|
}
|
||||||
if _index is not None and subconfig.index == _index:
|
if _index is not None and subconfig.index == _index:
|
||||||
lsubconfig = subconfig
|
lsubconfig = subconfig
|
||||||
else:
|
else:
|
||||||
identifier = subconfig.identifiers
|
identifier = subconfig.identifiers
|
||||||
if identifier is not None:
|
if identifier is not None:
|
||||||
identifier = identifier[-1]
|
identifier = identifier[-1]
|
||||||
lsubconfig = subconfig.parent.get_child(subconfig.option,
|
lsubconfig = subconfig.parent.get_child(
|
||||||
_index,
|
subconfig.option,
|
||||||
False,
|
_index,
|
||||||
properties=subconfig.properties,
|
False,
|
||||||
identifier=identifier,
|
properties=subconfig.properties,
|
||||||
name=subconfig.path.rsplit('.', 1)[-1],
|
identifier=identifier,
|
||||||
check_index=False,
|
name=subconfig.path.rsplit(".", 1)[-1],
|
||||||
)
|
check_index=False,
|
||||||
kwargs['orig_value'] = value
|
)
|
||||||
|
kwargs["orig_value"] = value
|
||||||
|
|
||||||
validator.execute(lsubconfig,
|
validator.execute(
|
||||||
**kwargs,
|
lsubconfig,
|
||||||
)
|
**kwargs,
|
||||||
|
)
|
||||||
except ValueWarning as warn:
|
except ValueWarning as warn:
|
||||||
warnings.warn_explicit(ValueWarning(subconfig,
|
warnings.warn_explicit(
|
||||||
val,
|
ValueWarning(
|
||||||
_(self.get_type()),
|
subconfig,
|
||||||
self,
|
val,
|
||||||
str(warn),
|
_(self.get_type()),
|
||||||
_index,
|
self,
|
||||||
),
|
str(warn),
|
||||||
ValueWarning,
|
_index,
|
||||||
self.__class__.__name__, 319)
|
),
|
||||||
|
ValueWarning,
|
||||||
|
self.__class__.__name__,
|
||||||
|
319,
|
||||||
|
)
|
||||||
|
|
||||||
def do_validation(_value,
|
def do_validation(
|
||||||
_index,
|
_value,
|
||||||
):
|
_index,
|
||||||
|
):
|
||||||
#
|
#
|
||||||
if _value is None:
|
if _value is None:
|
||||||
return
|
return
|
||||||
if isinstance(_value, list):
|
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:
|
if isinstance(_value, Calculation) and not subconfig:
|
||||||
return
|
return
|
||||||
# option validation
|
# option validation
|
||||||
if check_error:
|
if check_error:
|
||||||
self.validate(_value)
|
self.validate(_value)
|
||||||
self.validate_with_option(_value,
|
self.validate_with_option(
|
||||||
subconfig,
|
_value,
|
||||||
loaded=loaded,
|
subconfig,
|
||||||
)
|
loaded=loaded,
|
||||||
|
)
|
||||||
# second level validation
|
# 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:
|
try:
|
||||||
self.second_level_validation(_value,
|
self.second_level_validation(_value, is_warnings_only)
|
||||||
is_warnings_only)
|
|
||||||
except ValueError as err:
|
except ValueError as err:
|
||||||
if is_warnings_only:
|
if is_warnings_only:
|
||||||
warnings.warn_explicit(ValueWarning(subconfig,
|
warnings.warn_explicit(
|
||||||
_value,
|
ValueWarning(
|
||||||
_(self.get_type()),
|
subconfig,
|
||||||
self,
|
_value,
|
||||||
str(err),
|
_(self.get_type()),
|
||||||
_index),
|
self,
|
||||||
ValueWarning,
|
str(err),
|
||||||
self.__class__.__name__, 0)
|
_index,
|
||||||
|
),
|
||||||
|
ValueWarning,
|
||||||
|
self.__class__.__name__,
|
||||||
|
0,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
raise err from err
|
raise err from err
|
||||||
# ?
|
# ?
|
||||||
if not loaded:
|
if not loaded:
|
||||||
calculation_validator(_value,
|
calculation_validator(
|
||||||
_index,
|
_value,
|
||||||
)
|
_index,
|
||||||
|
)
|
||||||
|
|
||||||
val = value
|
val = value
|
||||||
err_index = force_index
|
err_index = force_index
|
||||||
try:
|
try:
|
||||||
if not self.impl_is_multi():
|
if not self.impl_is_multi():
|
||||||
do_validation(val,
|
do_validation(
|
||||||
None,
|
val,
|
||||||
)
|
None,
|
||||||
|
)
|
||||||
elif force_index is not None:
|
elif force_index is not None:
|
||||||
if self.impl_is_submulti():
|
if self.impl_is_submulti():
|
||||||
if not isinstance(value, list):
|
if not isinstance(value, list):
|
||||||
raise ValueError(_('which must be a list'))
|
raise ValueError(_("which must be a list"))
|
||||||
for val in value:
|
for val in value:
|
||||||
do_validation(val,
|
do_validation(
|
||||||
force_index,
|
val,
|
||||||
)
|
force_index,
|
||||||
|
)
|
||||||
_is_not_unique(value)
|
_is_not_unique(value)
|
||||||
else:
|
else:
|
||||||
do_validation(val,
|
do_validation(
|
||||||
force_index,
|
val,
|
||||||
)
|
force_index,
|
||||||
|
)
|
||||||
elif isinstance(value, Calculation) and not subconfig:
|
elif isinstance(value, Calculation) and not subconfig:
|
||||||
pass
|
pass
|
||||||
elif self.impl_is_submulti():
|
elif self.impl_is_submulti():
|
||||||
|
@ -367,83 +420,79 @@ class Option(BaseOption):
|
||||||
if isinstance(lval, Calculation):
|
if isinstance(lval, Calculation):
|
||||||
continue
|
continue
|
||||||
if not isinstance(lval, list):
|
if not isinstance(lval, list):
|
||||||
raise ValueError(_('which "{}" must be a list of list'
|
raise ValueError(
|
||||||
'').format(lval))
|
_('which "{}" must be a list of list' "").format(lval)
|
||||||
|
)
|
||||||
for val in lval:
|
for val in lval:
|
||||||
do_validation(val,
|
do_validation(val, err_index)
|
||||||
err_index)
|
|
||||||
_is_not_unique(lval)
|
_is_not_unique(lval)
|
||||||
elif not isinstance(value, list):
|
elif not isinstance(value, list):
|
||||||
raise ValueError(_('which must be a list'))
|
raise ValueError(_("which must be a list"))
|
||||||
else:
|
else:
|
||||||
# FIXME suboptimal, not several time for whole=True!
|
# FIXME suboptimal, not several time for whole=True!
|
||||||
for err_index, val in enumerate(value):
|
for err_index, val in enumerate(value):
|
||||||
do_validation(val,
|
do_validation(
|
||||||
err_index,
|
val,
|
||||||
)
|
err_index,
|
||||||
|
)
|
||||||
_is_not_unique(value)
|
_is_not_unique(value)
|
||||||
except ValueError as err:
|
except ValueError as err:
|
||||||
if not subconfig or \
|
if (
|
||||||
'demoting_error_warning' not in subconfig.config_bag.properties:
|
not subconfig
|
||||||
raise ValueOptionError(subconfig,
|
or "demoting_error_warning" not in subconfig.config_bag.properties
|
||||||
val,
|
):
|
||||||
_(self.get_type()),
|
raise ValueOptionError(
|
||||||
self,
|
subconfig, val, _(self.get_type()), self, str(err), err_index
|
||||||
str(err),
|
) from err
|
||||||
err_index) from err
|
warnings.warn_explicit(
|
||||||
warnings.warn_explicit(ValueErrorWarning(subconfig,
|
ValueErrorWarning(
|
||||||
val,
|
subconfig, val, _(self.get_type()), self, str(err), err_index
|
||||||
_(self.get_type()),
|
),
|
||||||
self,
|
ValueErrorWarning,
|
||||||
str(err),
|
self.__class__.__name__,
|
||||||
err_index),
|
0,
|
||||||
ValueErrorWarning,
|
)
|
||||||
self.__class__.__name__, 0)
|
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def validate_with_option(self,
|
def validate_with_option(
|
||||||
value: Any,
|
self,
|
||||||
subconfig: "SubConfig",
|
value: Any,
|
||||||
*,
|
subconfig: "SubConfig",
|
||||||
loaded: bool,
|
*,
|
||||||
) -> None:
|
loaded: bool,
|
||||||
"""validation function with option
|
) -> None:
|
||||||
"""
|
"""validation function with option"""
|
||||||
|
|
||||||
def second_level_validation(self,
|
def second_level_validation(
|
||||||
value: Any,
|
self,
|
||||||
warnings_only: bool,
|
value: Any,
|
||||||
) -> None:
|
warnings_only: bool,
|
||||||
"""less import validation function
|
) -> None:
|
||||||
"""
|
"""less import validation function"""
|
||||||
|
|
||||||
def impl_is_leader(self):
|
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()
|
leadership = self.impl_get_leadership()
|
||||||
if leadership is None:
|
if leadership is None:
|
||||||
return False
|
return False
|
||||||
return leadership.is_leader(self)
|
return leadership.is_leader(self)
|
||||||
|
|
||||||
def impl_is_follower(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()
|
leadership = self.impl_get_leadership()
|
||||||
if leadership is None:
|
if leadership is None:
|
||||||
return False
|
return False
|
||||||
return not leadership.is_leader(self)
|
return not leadership.is_leader(self)
|
||||||
|
|
||||||
def impl_get_leadership(self):
|
def impl_get_leadership(self):
|
||||||
"""get leadership
|
"""get leadership"""
|
||||||
"""
|
leadership = getattr(self, "_leadership", None)
|
||||||
leadership = getattr(self, '_leadership', None)
|
|
||||||
if leadership is None:
|
if leadership is None:
|
||||||
return leadership
|
return leadership
|
||||||
#pylint: disable=not-callable
|
# pylint: disable=not-callable
|
||||||
return leadership()
|
return leadership()
|
||||||
|
|
||||||
def validate(self, value: Any):
|
def validate(self, value: Any):
|
||||||
"""option needs a validate function
|
"""option needs a validate function"""
|
||||||
"""
|
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
|
@ -27,33 +27,34 @@ from typing import Optional, Iterator, Union, List, Dict
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from ..setting import ConfigBag, groups, undefined, owners, Undefined
|
from ..setting import ConfigBag, groups, undefined, owners, Undefined
|
||||||
from .baseoption import BaseOption
|
from .baseoption import BaseOption
|
||||||
|
|
||||||
# from .syndynoption import SubDynOptionDescription, SynDynOptionDescription
|
# from .syndynoption import SubDynOptionDescription, SynDynOptionDescription
|
||||||
from ..error import ConfigError, ConflictError
|
from ..error import ConfigError, ConflictError
|
||||||
|
|
||||||
|
|
||||||
class CacheOptionDescription(BaseOption):
|
class CacheOptionDescription(BaseOption):
|
||||||
"""manage cache for option description
|
"""manage cache for option description"""
|
||||||
"""
|
|
||||||
__slots__ = ('_cache_force_store_values',
|
__slots__ = (
|
||||||
'_cache_dependencies_information',
|
"_cache_force_store_values",
|
||||||
)
|
"_cache_dependencies_information",
|
||||||
|
)
|
||||||
|
|
||||||
def impl_already_build_caches(self) -> bool:
|
def impl_already_build_caches(self) -> bool:
|
||||||
"""is a readonly option?
|
"""is a readonly option?"""
|
||||||
"""
|
|
||||||
return self.impl_is_readonly()
|
return self.impl_is_readonly()
|
||||||
|
|
||||||
def _build_cache(self,
|
def _build_cache(
|
||||||
display_name,
|
self,
|
||||||
_consistencies=None,
|
display_name,
|
||||||
_consistencies_id=0,
|
_consistencies=None,
|
||||||
currpath: List[str]=None,
|
_consistencies_id=0,
|
||||||
cache_option=None,
|
currpath: List[str] = None,
|
||||||
force_store_values=None,
|
cache_option=None,
|
||||||
dependencies_information=None,
|
force_store_values=None,
|
||||||
) -> None:
|
dependencies_information=None,
|
||||||
"""validate options and set option has readonly option
|
) -> None:
|
||||||
"""
|
"""validate options and set option has readonly option"""
|
||||||
# pylint: disable=too-many-branches,too-many-arguments
|
# pylint: disable=too-many-branches,too-many-arguments
|
||||||
# _consistencies is None only when we start to build cache
|
# _consistencies is None only when we start to build cache
|
||||||
if _consistencies is None:
|
if _consistencies is None:
|
||||||
|
@ -69,112 +70,137 @@ class CacheOptionDescription(BaseOption):
|
||||||
|
|
||||||
if self.impl_is_readonly():
|
if self.impl_is_readonly():
|
||||||
# cache already set
|
# cache already set
|
||||||
raise ConfigError(_('option description seems to be part of an other '
|
raise ConfigError(
|
||||||
'config'))
|
_("option description seems to be part of an other " "config")
|
||||||
|
)
|
||||||
for option in self.get_children():
|
for option in self.get_children():
|
||||||
if __debug__:
|
if __debug__:
|
||||||
cache_option.append(option)
|
cache_option.append(option)
|
||||||
sub_currpath = currpath + [option.impl_getname()]
|
sub_currpath = currpath + [option.impl_getname()]
|
||||||
subpath = '.'.join(sub_currpath)
|
subpath = ".".join(sub_currpath)
|
||||||
if isinstance(option, OptionDescription):
|
if isinstance(option, OptionDescription):
|
||||||
# pylint: disable=protected-access
|
# pylint: disable=protected-access
|
||||||
option._build_cache(display_name,
|
option._build_cache(
|
||||||
_consistencies,
|
display_name,
|
||||||
_consistencies_id,
|
_consistencies,
|
||||||
sub_currpath,
|
_consistencies_id,
|
||||||
cache_option,
|
sub_currpath,
|
||||||
force_store_values,
|
cache_option,
|
||||||
dependencies_information,
|
force_store_values,
|
||||||
)
|
dependencies_information,
|
||||||
|
)
|
||||||
elif not option.impl_is_symlinkoption():
|
elif not option.impl_is_symlinkoption():
|
||||||
informations = option.get_dependencies_information()
|
informations = option.get_dependencies_information()
|
||||||
if informations:
|
if informations:
|
||||||
for param in informations.pop(None):
|
for param in informations.pop(None):
|
||||||
del param.self_option
|
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:
|
if None in options:
|
||||||
dependencies_information.setdefault(information, []).append(option)
|
dependencies_information.setdefault(information, []).append(
|
||||||
|
option
|
||||||
|
)
|
||||||
properties = option.impl_getproperties()
|
properties = option.impl_getproperties()
|
||||||
if 'force_store_value' in properties:
|
if "force_store_value" in properties:
|
||||||
force_store_values.append(option)
|
force_store_values.append(option)
|
||||||
if option.impl_is_readonly():
|
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:
|
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._path = subpath # pylint: disable=protected-access
|
||||||
option._set_readonly() # pylint: disable=protected-access
|
option._set_readonly() # pylint: disable=protected-access
|
||||||
if init:
|
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._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()
|
self._set_readonly()
|
||||||
|
|
||||||
def impl_build_force_store_values(self,
|
def impl_build_force_store_values(
|
||||||
config_bag: ConfigBag,
|
self,
|
||||||
) -> None:
|
config_bag: ConfigBag,
|
||||||
"""set value to force_store_values option
|
) -> None:
|
||||||
"""
|
"""set value to force_store_values option"""
|
||||||
# pylint: disable=too-many-branches
|
# pylint: disable=too-many-branches
|
||||||
context = config_bag.context
|
context = config_bag.context
|
||||||
if 'force_store_value' not in config_bag.properties:
|
if "force_store_value" not in config_bag.properties:
|
||||||
return
|
return
|
||||||
|
|
||||||
values = config_bag.context.get_values()
|
values = config_bag.context.get_values()
|
||||||
for option in self._cache_force_store_values:
|
for option in self._cache_force_store_values:
|
||||||
if option.issubdyn():
|
if option.issubdyn():
|
||||||
paths = option.impl_getpath().split('.')
|
paths = option.impl_getpath().split(".")
|
||||||
parents = [config_bag.context.get_root(config_bag)]
|
parents = [config_bag.context.get_root(config_bag)]
|
||||||
for name in paths:
|
for name in paths:
|
||||||
new_parents = []
|
new_parents = []
|
||||||
for parent in parents:
|
for parent in parents:
|
||||||
doption = parent.option.get_child(name,
|
doption = parent.option.get_child(
|
||||||
config_bag,
|
name,
|
||||||
parent,
|
config_bag,
|
||||||
allow_dynoption=True,
|
parent,
|
||||||
)
|
allow_dynoption=True,
|
||||||
|
)
|
||||||
if doption.impl_is_dynoptiondescription():
|
if doption.impl_is_dynoptiondescription():
|
||||||
new_parents.extend(parent.dyn_to_subconfig(doption,
|
new_parents.extend(
|
||||||
True,
|
parent.dyn_to_subconfig(
|
||||||
)
|
doption,
|
||||||
)
|
True,
|
||||||
|
)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
new_parents.append(parent.get_child(doption,
|
new_parents.append(
|
||||||
None,
|
parent.get_child(
|
||||||
True,
|
doption,
|
||||||
name=name,
|
None,
|
||||||
))
|
True,
|
||||||
|
name=name,
|
||||||
|
)
|
||||||
|
)
|
||||||
parents = new_parents
|
parents = new_parents
|
||||||
subconfigs = new_parents
|
subconfigs = new_parents
|
||||||
else:
|
else:
|
||||||
subconfigs = [context.get_sub_config(config_bag,
|
subconfigs = [
|
||||||
option.impl_getpath(),
|
context.get_sub_config(
|
||||||
None,
|
config_bag,
|
||||||
properties=None,
|
option.impl_getpath(),
|
||||||
validate_properties=False,
|
None,
|
||||||
)]
|
properties=None,
|
||||||
|
validate_properties=False,
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
if option.impl_is_follower():
|
if option.impl_is_follower():
|
||||||
for follower_subconfig in subconfigs:
|
for follower_subconfig in subconfigs:
|
||||||
parent = follower_subconfig.parent
|
parent = follower_subconfig.parent
|
||||||
follower_len = parent.get_length_leadership()
|
follower_len = parent.get_length_leadership()
|
||||||
for index in range(follower_len):
|
for index in range(follower_len):
|
||||||
if values.hasvalue(follower_subconfig.path,
|
if values.hasvalue(
|
||||||
index=index,
|
follower_subconfig.path,
|
||||||
):
|
index=index,
|
||||||
|
):
|
||||||
continue
|
continue
|
||||||
idx_follower_subconfig = parent.get_child(follower_subconfig.option,
|
idx_follower_subconfig = parent.get_child(
|
||||||
index,
|
follower_subconfig.option,
|
||||||
validate_properties=False,
|
index,
|
||||||
)
|
validate_properties=False,
|
||||||
|
)
|
||||||
|
|
||||||
value = values.get_value(idx_follower_subconfig)[0]
|
value = values.get_value(idx_follower_subconfig)[0]
|
||||||
if value is None:
|
if value is None:
|
||||||
continue
|
continue
|
||||||
values.set_storage_value(follower_subconfig.path,
|
values.set_storage_value(
|
||||||
index,
|
follower_subconfig.path,
|
||||||
value,
|
index,
|
||||||
owners.forced,
|
value,
|
||||||
)
|
owners.forced,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
for subconfig in subconfigs:
|
for subconfig in subconfigs:
|
||||||
subconfig.properties = frozenset()
|
subconfig.properties = frozenset()
|
||||||
|
@ -183,52 +209,59 @@ class CacheOptionDescription(BaseOption):
|
||||||
continue
|
continue
|
||||||
if values.hasvalue(subconfig.path):
|
if values.hasvalue(subconfig.path):
|
||||||
continue
|
continue
|
||||||
values.set_storage_value(subconfig.path,
|
values.set_storage_value(
|
||||||
None,
|
subconfig.path,
|
||||||
value,
|
None,
|
||||||
owners.forced,
|
value,
|
||||||
)
|
owners.forced,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class OptionDescriptionWalk(CacheOptionDescription):
|
class OptionDescriptionWalk(CacheOptionDescription):
|
||||||
"""get child of option description
|
"""get child of option description"""
|
||||||
"""
|
|
||||||
__slots__ = ('_children',)
|
|
||||||
|
|
||||||
def get_path(self,
|
__slots__ = ("_children",)
|
||||||
config_bag,
|
|
||||||
):
|
def get_path(
|
||||||
if config_bag is undefined or \
|
self,
|
||||||
config_bag.context.get_description() == self:
|
config_bag,
|
||||||
return ''
|
):
|
||||||
|
if config_bag is undefined or config_bag.context.get_description() == self:
|
||||||
|
return ""
|
||||||
return self.impl_getpath()
|
return self.impl_getpath()
|
||||||
|
|
||||||
def get_child_not_dynamic(self,
|
def get_child_not_dynamic(
|
||||||
name,
|
self,
|
||||||
allow_dynoption,
|
name,
|
||||||
):
|
allow_dynoption,
|
||||||
|
):
|
||||||
if name in self._children[0]: # pylint: disable=no-member
|
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:
|
if option.impl_is_dynoptiondescription() and not allow_dynoption:
|
||||||
raise AttributeError(_(f'unknown option "{name}" '
|
raise AttributeError(
|
||||||
"in root optiondescription (it's a dynamic option)"
|
_(
|
||||||
))
|
'unknown option "{0}" in root optiondescription (it\'s a dynamic option)'
|
||||||
|
).format(name)
|
||||||
|
)
|
||||||
return option
|
return option
|
||||||
|
|
||||||
def get_child(self,
|
def get_child(
|
||||||
name: str,
|
self,
|
||||||
config_bag: ConfigBag,
|
name: str,
|
||||||
parent: 'SubConfig',
|
config_bag: ConfigBag,
|
||||||
*,
|
parent: "SubConfig",
|
||||||
with_identifier: bool=False,
|
*,
|
||||||
allow_dynoption: bool=False,
|
with_identifier: bool = False,
|
||||||
) -> Union[BaseOption]:
|
allow_dynoption: bool = False,
|
||||||
"""get a child
|
) -> Union[BaseOption]:
|
||||||
"""
|
"""get a child"""
|
||||||
# if not dyn
|
# if not dyn
|
||||||
option = self.get_child_not_dynamic(name,
|
option = self.get_child_not_dynamic(
|
||||||
allow_dynoption,
|
name,
|
||||||
)
|
allow_dynoption,
|
||||||
|
)
|
||||||
if option:
|
if option:
|
||||||
return option
|
return option
|
||||||
# if dyn
|
# if dyn
|
||||||
|
@ -242,39 +275,42 @@ class OptionDescriptionWalk(CacheOptionDescription):
|
||||||
return child
|
return child
|
||||||
return identifier, child
|
return identifier, child
|
||||||
if self.impl_get_group_type() == groups.root: # pylint: disable=no-member
|
if self.impl_get_group_type() == groups.root: # pylint: disable=no-member
|
||||||
raise AttributeError(_(f'unknown option "{name}" '
|
raise AttributeError(
|
||||||
'in root optiondescription'
|
_('unknown option "{0}" in root optiondescription').format(name)
|
||||||
))
|
)
|
||||||
raise AttributeError(_(f'unknown option "{name}" '
|
raise AttributeError(
|
||||||
f'in optiondescription {self.impl_get_display_name(parent, with_quote=True)}'
|
_('unknown option "{0}" in optiondescription {1}').format(
|
||||||
))
|
name, self.impl_get_display_name(parent, with_quote=True)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def get_children(self) -> List[BaseOption]:
|
def get_children(self) -> List[BaseOption]:
|
||||||
"""get children
|
"""get children"""
|
||||||
"""
|
|
||||||
return self._children[1]
|
return self._children[1]
|
||||||
|
|
||||||
def get_children_recursively(self,
|
def get_children_recursively(
|
||||||
bytype: Optional[BaseOption],
|
self,
|
||||||
byname: Optional[str],
|
bytype: Optional[BaseOption],
|
||||||
config_bag: ConfigBag,
|
byname: Optional[str],
|
||||||
self_opt: BaseOption=None,
|
config_bag: ConfigBag,
|
||||||
*,
|
self_opt: BaseOption = None,
|
||||||
option_identifiers: Optional[list]=None
|
*,
|
||||||
) -> Iterator[Union[BaseOption]]:
|
option_identifiers: Optional[list] = None,
|
||||||
"""get children recursively
|
) -> Iterator[Union[BaseOption]]:
|
||||||
"""
|
"""get children recursively"""
|
||||||
if self_opt is None:
|
if self_opt is None:
|
||||||
self_opt = self
|
self_opt = self
|
||||||
for option in self_opt.get_children():
|
for option in self_opt.get_children():
|
||||||
if option.impl_is_optiondescription():
|
if option.impl_is_optiondescription():
|
||||||
for subopt in option.get_children_recursively(bytype,
|
for subopt in option.get_children_recursively(
|
||||||
byname,
|
bytype,
|
||||||
config_bag,
|
byname,
|
||||||
):
|
config_bag,
|
||||||
|
):
|
||||||
yield subopt
|
yield subopt
|
||||||
elif (byname is None or option.impl_getname() == byname) and \
|
elif (byname is None or option.impl_getname() == byname) and (
|
||||||
(bytype is None or isinstance(option, bytype)):
|
bytype is None or isinstance(option, bytype)
|
||||||
|
):
|
||||||
yield option
|
yield option
|
||||||
|
|
||||||
|
|
||||||
|
@ -282,28 +318,32 @@ class OptionDescription(OptionDescriptionWalk):
|
||||||
"""Config's schema (organisation, group) and container of Options
|
"""Config's schema (organisation, group) and container of Options
|
||||||
The `OptionsDescription` objects lives in the `tiramisu.config.Config`.
|
The `OptionsDescription` objects lives in the `tiramisu.config.Config`.
|
||||||
"""
|
"""
|
||||||
__slots__ = ('_group_type',)
|
|
||||||
|
|
||||||
def __init__(self,
|
__slots__ = ("_group_type",)
|
||||||
name: str,
|
|
||||||
doc: str,
|
def __init__(
|
||||||
children: List[BaseOption],
|
self,
|
||||||
*,
|
name: str,
|
||||||
properties=None,
|
doc: str,
|
||||||
informations: Optional[Dict]=None,
|
children: List[BaseOption],
|
||||||
group_type: Optional[groups.GroupType]=groups.default,
|
*,
|
||||||
) -> None:
|
properties=None,
|
||||||
|
informations: Optional[Dict] = None,
|
||||||
|
group_type: Optional[groups.GroupType] = groups.default,
|
||||||
|
) -> None:
|
||||||
"""
|
"""
|
||||||
:param children: a list of options (including optiondescriptions)
|
:param children: a list of options (including optiondescriptions)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
assert isinstance(children, list), _('children in optiondescription "{}" '
|
assert isinstance(children, list), _(
|
||||||
'must be a list').format(name)
|
'children in optiondescription "{}" ' "must be a list"
|
||||||
super().__init__(name,
|
).format(name)
|
||||||
doc,
|
super().__init__(
|
||||||
informations,
|
name,
|
||||||
properties=properties,
|
doc,
|
||||||
)
|
informations,
|
||||||
|
properties=properties,
|
||||||
|
)
|
||||||
child_names = []
|
child_names = []
|
||||||
if __debug__:
|
if __debug__:
|
||||||
dynopt_names = []
|
dynopt_names = []
|
||||||
|
@ -322,45 +362,48 @@ class OptionDescription(OptionDescriptionWalk):
|
||||||
old = None
|
old = None
|
||||||
for child in child_names:
|
for child in child_names:
|
||||||
if child == old:
|
if child == old:
|
||||||
raise ConflictError(_('duplicate option name: '
|
raise ConflictError(
|
||||||
'"{0}"').format(child))
|
_("duplicate option name: " '"{0}"').format(child)
|
||||||
|
)
|
||||||
if dynopt_names:
|
if dynopt_names:
|
||||||
for dynopt in dynopt_names:
|
for dynopt in dynopt_names:
|
||||||
if child != dynopt and child.startswith(dynopt):
|
if child != dynopt and child.startswith(dynopt):
|
||||||
raise ConflictError(_(f'the option\'s name "{child}" start as '
|
raise ConflictError(
|
||||||
f'the dynoptiondescription\'s name "{dynopt}"'))
|
_(
|
||||||
|
'the option\'s name "{0}" start as the dynoptiondescription\'s name "{1}"'
|
||||||
|
).format(child, dynopt)
|
||||||
|
)
|
||||||
old = child
|
old = child
|
||||||
self._children = children_
|
self._children = children_
|
||||||
# the group_type is useful for filtering OptionDescriptions in a config
|
# the group_type is useful for filtering OptionDescriptions in a config
|
||||||
self._group_type = None
|
self._group_type = None
|
||||||
self.impl_set_group_type(group_type)
|
self.impl_set_group_type(group_type)
|
||||||
|
|
||||||
def _setsubdyn(self,
|
def _setsubdyn(
|
||||||
subdyn,
|
self,
|
||||||
) -> None:
|
subdyn,
|
||||||
|
) -> None:
|
||||||
for child in self._children[1]:
|
for child in self._children[1]:
|
||||||
child._setsubdyn(subdyn)
|
child._setsubdyn(subdyn)
|
||||||
super()._setsubdyn(subdyn)
|
super()._setsubdyn(subdyn)
|
||||||
|
|
||||||
def impl_is_optiondescription(self) -> bool:
|
def impl_is_optiondescription(self) -> bool:
|
||||||
"""the option is an option description
|
"""the option is an option description"""
|
||||||
"""
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def impl_is_dynoptiondescription(self) -> bool:
|
def impl_is_dynoptiondescription(self) -> bool:
|
||||||
"""the option is not dynamic
|
"""the option is not dynamic"""
|
||||||
"""
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def impl_is_leadership(self) -> bool:
|
def impl_is_leadership(self) -> bool:
|
||||||
"""the option is not a leadership
|
"""the option is not a leadership"""
|
||||||
"""
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
def impl_set_group_type(self,
|
def impl_set_group_type(
|
||||||
group_type: groups.GroupType,
|
self,
|
||||||
) -> None:
|
group_type: groups.GroupType,
|
||||||
|
) -> None:
|
||||||
"""sets a given group object to an OptionDescription
|
"""sets a given group object to an OptionDescription
|
||||||
|
|
||||||
:param group_type: an instance of `GroupType` or `LeadershipGroupType`
|
:param group_type: an instance of `GroupType` or `LeadershipGroupType`
|
||||||
|
@ -368,22 +411,23 @@ class OptionDescription(OptionDescriptionWalk):
|
||||||
"""
|
"""
|
||||||
if __debug__:
|
if __debug__:
|
||||||
if self._group_type is not None and self._group_type != groups.default:
|
if self._group_type is not None and self._group_type != groups.default:
|
||||||
raise ValueError(_('cannot change group_type if already set '
|
raise ValueError(
|
||||||
'(old {0}, new {1})').format(self._group_type,
|
_(
|
||||||
group_type))
|
"cannot change group_type if already set " "(old {0}, new {1})"
|
||||||
|
).format(self._group_type, group_type)
|
||||||
|
)
|
||||||
if not isinstance(group_type, groups.GroupType):
|
if not isinstance(group_type, groups.GroupType):
|
||||||
raise ValueError(_('group_type: {0}'
|
raise ValueError(_("group_type: {0}" " not allowed").format(group_type))
|
||||||
' not allowed').format(group_type))
|
|
||||||
if isinstance(group_type, groups.LeadershipGroupType):
|
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
|
self._group_type = group_type
|
||||||
|
|
||||||
def impl_get_group_type(self) -> groups.GroupType:
|
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
|
return self._group_type
|
||||||
|
|
||||||
def impl_is_dynsymlinkoption(self) -> bool:
|
def impl_is_dynsymlinkoption(self) -> bool:
|
||||||
"""option is not a dyn symlink option
|
"""option is not a dyn symlink option"""
|
||||||
"""
|
|
||||||
return False
|
return False
|
||||||
|
|
|
@ -26,7 +26,7 @@ from .stroption import StrOption
|
||||||
|
|
||||||
|
|
||||||
class PasswordOption(StrOption):
|
class PasswordOption(StrOption):
|
||||||
"""represents the choice of a password
|
"""represents the choice of a password"""
|
||||||
"""
|
|
||||||
__slots__ = tuple()
|
__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.
|
If a fourth digit is present to the setuid bit, the setgid bit and the sticky bit attributes.
|
||||||
This option is an integer value.
|
This option is an integer value.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = tuple()
|
__slots__ = tuple()
|
||||||
perm_re = re.compile(r"^[0-7]{3,4}$")
|
perm_re = re.compile(r"^[0-7]{3,4}$")
|
||||||
_type = 'unix file permissions'
|
_type = "unix file permissions"
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
*args,
|
self,
|
||||||
**kwargs,
|
*args,
|
||||||
) -> None:
|
**kwargs,
|
||||||
#do not display intoption attributs
|
) -> None:
|
||||||
super().__init__(*args,
|
# do not display intoption attributs
|
||||||
**kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
def validate(self,
|
def validate(self, value: str) -> None:
|
||||||
value: str) -> None:
|
|
||||||
super().validate(value)
|
super().validate(value)
|
||||||
if not self.perm_re.search(str(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,
|
def second_level_validation(self, value: str, warnings_only: bool) -> None:
|
||||||
value: str,
|
|
||||||
warnings_only: bool) -> None:
|
|
||||||
old_digit = 7
|
old_digit = 7
|
||||||
str_value = str(value)
|
str_value = str(value)
|
||||||
if len(str_value) == 4:
|
if len(str_value) == 4:
|
||||||
|
@ -62,12 +60,12 @@ class PermissionsOption(IntOption):
|
||||||
new_digit = int(digit)
|
new_digit = int(digit)
|
||||||
if old_digit < new_digit:
|
if old_digit < new_digit:
|
||||||
if idx == 1:
|
if idx == 1:
|
||||||
old = _('user')
|
old = _("user")
|
||||||
new = _('group')
|
new = _("group")
|
||||||
else:
|
else:
|
||||||
old = _('group')
|
old = _("group")
|
||||||
new = _('other')
|
new = _("other")
|
||||||
raise ValueError(_(f'{new} has more right than {old}'))
|
raise ValueError(_("{0} has more right than {1}").format(new, old))
|
||||||
old_digit = new_digit
|
old_digit = new_digit
|
||||||
if str_value == '777':
|
if str_value == "777":
|
||||||
raise ValueError(_('too weak'))
|
raise ValueError(_("too weak"))
|
||||||
|
|
|
@ -36,62 +36,64 @@ class PortOption(StrOption):
|
||||||
Port number 0 is reserved and can't be used.
|
Port number 0 is reserved and can't be used.
|
||||||
see: http://en.wikipedia.org/wiki/Port_numbers
|
see: http://en.wikipedia.org/wiki/Port_numbers
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = tuple()
|
__slots__ = tuple()
|
||||||
port_re = re.compile(r"^[0-9]*$")
|
port_re = re.compile(r"^[0-9]*$")
|
||||||
_type = 'port'
|
_type = "port"
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
*args,
|
self,
|
||||||
allow_range: bool=False,
|
*args,
|
||||||
allow_zero: bool=False,
|
allow_range: bool = False,
|
||||||
allow_wellknown: bool=True,
|
allow_zero: bool = False,
|
||||||
allow_registred: bool=True,
|
allow_wellknown: bool = True,
|
||||||
allow_protocol: bool=False,
|
allow_registred: bool = True,
|
||||||
allow_private: bool=False,
|
allow_protocol: bool = False,
|
||||||
**kwargs) -> None:
|
allow_private: bool = False,
|
||||||
|
**kwargs,
|
||||||
|
) -> None:
|
||||||
|
|
||||||
extra = {'_allow_range': allow_range,
|
extra = {
|
||||||
'_allow_protocol': allow_protocol,
|
"_allow_range": allow_range,
|
||||||
'_min_value': None,
|
"_allow_protocol": allow_protocol,
|
||||||
'_max_value': None,
|
"_min_value": None,
|
||||||
}
|
"_max_value": None,
|
||||||
|
}
|
||||||
ports_min = [0, 1, 1024, 49152]
|
ports_min = [0, 1, 1024, 49152]
|
||||||
ports_max = [0, 1023, 49151, 65535]
|
ports_max = [0, 1023, 49151, 65535]
|
||||||
is_finally = False
|
is_finally = False
|
||||||
for index, allowed in enumerate([allow_zero,
|
for index, allowed in enumerate(
|
||||||
allow_wellknown,
|
[allow_zero, allow_wellknown, allow_registred, allow_private]
|
||||||
allow_registred,
|
):
|
||||||
allow_private]):
|
if extra["_min_value"] is None:
|
||||||
if extra['_min_value'] is None:
|
|
||||||
if allowed:
|
if allowed:
|
||||||
extra['_min_value'] = ports_min[index]
|
extra["_min_value"] = ports_min[index]
|
||||||
elif not allowed:
|
elif not allowed:
|
||||||
is_finally = True
|
is_finally = True
|
||||||
elif allowed and is_finally:
|
elif allowed and is_finally:
|
||||||
raise ValueError(_('inconsistency in allowed range'))
|
raise ValueError(_("inconsistency in allowed range"))
|
||||||
if allowed:
|
if allowed:
|
||||||
extra['_max_value'] = ports_max[index]
|
extra["_max_value"] = ports_max[index]
|
||||||
|
|
||||||
if extra['_max_value'] is None:
|
if extra["_max_value"] is None:
|
||||||
raise ValueError(_('max value is empty'))
|
raise ValueError(_("max value is empty"))
|
||||||
|
|
||||||
super().__init__(*args,
|
super().__init__(*args, extra=extra, **kwargs)
|
||||||
extra=extra,
|
|
||||||
**kwargs)
|
|
||||||
|
|
||||||
def validate(self,
|
def validate(self, value: str) -> None:
|
||||||
value: str) -> None:
|
|
||||||
super().validate(value)
|
super().validate(value)
|
||||||
if self.impl_get_extra('_allow_protocol') and (value.startswith('tcp:') or
|
if self.impl_get_extra("_allow_protocol") and (
|
||||||
value.startswith('udp:')):
|
value.startswith("tcp:") or value.startswith("udp:")
|
||||||
|
):
|
||||||
value = [value[4:]]
|
value = [value[4:]]
|
||||||
elif self.impl_get_extra('_allow_range') and ":" in str(value):
|
elif self.impl_get_extra("_allow_range") and ":" in str(value):
|
||||||
value = value.split(':')
|
value = value.split(":")
|
||||||
if len(value) != 2:
|
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]:
|
if not value[0] < value[1]:
|
||||||
raise ValueError(_('first port in range must be'
|
raise ValueError(
|
||||||
' smaller than the second one'))
|
_("first port in range must be" " smaller than the second one")
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
value = [value]
|
value = [value]
|
||||||
|
|
||||||
|
@ -99,22 +101,29 @@ class PortOption(StrOption):
|
||||||
if not self.port_re.search(val):
|
if not self.port_re.search(val):
|
||||||
raise ValueError()
|
raise ValueError()
|
||||||
|
|
||||||
def second_level_validation(self,
|
def second_level_validation(self, value: str, warnings_only: bool) -> None:
|
||||||
value: str,
|
if self.impl_get_extra("_allow_protocol") and (
|
||||||
warnings_only: bool) -> None:
|
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:]]
|
value = [value[4:]]
|
||||||
elif ':' in value:
|
elif ":" in value:
|
||||||
value = value.split(':')
|
value = value.split(":")
|
||||||
else:
|
else:
|
||||||
value = [value]
|
value = [value]
|
||||||
for val in value:
|
for val in value:
|
||||||
val = int(val)
|
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:
|
if warnings_only:
|
||||||
msg = 'should be between {0} and {1}'
|
msg = _("should be between {0} and {1}")
|
||||||
else:
|
else:
|
||||||
msg = 'must be between {0} and {1}'
|
msg = _("must be between {0} and {1}")
|
||||||
raise ValueError(_(msg).format(self.impl_get_extra('_min_value'),
|
raise ValueError(
|
||||||
self.impl_get_extra('_max_value')))
|
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):
|
class StrOption(Option):
|
||||||
"""represents a string
|
"""represents a string"""
|
||||||
"""
|
|
||||||
__slots__ = tuple()
|
|
||||||
_type = 'string'
|
|
||||||
|
|
||||||
def validate(self,
|
__slots__ = tuple()
|
||||||
value: str,
|
_type = "string"
|
||||||
) -> None:
|
|
||||||
"""validation
|
def validate(
|
||||||
"""
|
self,
|
||||||
|
value: str,
|
||||||
|
) -> None:
|
||||||
|
"""validation"""
|
||||||
if not isinstance(value, str):
|
if not isinstance(value, str):
|
||||||
raise ValueError()
|
raise ValueError()
|
||||||
|
|
||||||
|
|
||||||
class RegexpOption(StrOption):
|
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()
|
__slots__ = tuple()
|
||||||
|
|
||||||
def validate(self,
|
def validate(
|
||||||
value: Any,
|
self,
|
||||||
) -> None:
|
value: Any,
|
||||||
|
) -> None:
|
||||||
# pylint: disable=no-member
|
# pylint: disable=no-member
|
||||||
"""validation
|
"""validation"""
|
||||||
"""
|
|
||||||
super().validate(value)
|
super().validate(value)
|
||||||
match = self._regexp.search(value)
|
match = self._regexp.search(value)
|
||||||
if not match:
|
if not match:
|
||||||
|
|
|
@ -27,61 +27,66 @@ from ..i18n import _
|
||||||
|
|
||||||
|
|
||||||
class SymLinkOption(BaseOption):
|
class SymLinkOption(BaseOption):
|
||||||
"""SymLinkOption link to an other option
|
"""SymLinkOption link to an other option"""
|
||||||
"""
|
|
||||||
__slots__ = ('_opt',
|
|
||||||
'_leadership',
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(self,
|
__slots__ = (
|
||||||
name: str,
|
"_opt",
|
||||||
opt: BaseOption,
|
"_leadership",
|
||||||
) -> None:
|
)
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
name: str,
|
||||||
|
opt: BaseOption,
|
||||||
|
) -> None:
|
||||||
# pylint: disable=super-init-not-called
|
# pylint: disable=super-init-not-called
|
||||||
if not valid_name(name):
|
if not valid_name(name):
|
||||||
raise ValueError(_('"{0}" is an invalid name for an option').format(name))
|
raise ValueError(_('"{0}" is an invalid name for an option').format(name))
|
||||||
if not isinstance(opt, BaseOption) or \
|
if (
|
||||||
opt.impl_is_optiondescription() or \
|
not isinstance(opt, BaseOption)
|
||||||
opt.impl_is_symlinkoption():
|
or opt.impl_is_optiondescription()
|
||||||
raise ValueError(_(f'malformed symlink second parameters must be an option for "{name}", not {opt}'))
|
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._name = name
|
||||||
self._opt = opt
|
self._opt = opt
|
||||||
self._leadership = None
|
self._leadership = None
|
||||||
opt._add_dependency(self)
|
opt._add_dependency(self)
|
||||||
|
|
||||||
def __getattr__(self,
|
def __getattr__(
|
||||||
name: str,
|
self,
|
||||||
) -> Any:
|
name: str,
|
||||||
if name == '_subdyns':
|
) -> Any:
|
||||||
|
if name == "_subdyns":
|
||||||
return None
|
return None
|
||||||
if name == '_path':
|
if name == "_path":
|
||||||
raise AttributeError()
|
raise AttributeError()
|
||||||
return getattr(self._opt, name)
|
return getattr(self._opt, name)
|
||||||
|
|
||||||
def impl_is_symlinkoption(self) -> bool:
|
def impl_is_symlinkoption(self) -> bool:
|
||||||
"""it's a symlinkoption
|
"""it's a symlinkoption"""
|
||||||
"""
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def impl_is_leader(self) -> bool:
|
def impl_is_leader(self) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def impl_is_follower(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._leadership
|
leadership = self._leadership
|
||||||
if leadership is None:
|
if leadership is None:
|
||||||
return False
|
return False
|
||||||
return not leadership().is_leader(self)
|
return not leadership().is_leader(self)
|
||||||
|
|
||||||
def impl_getopt(self) -> BaseOption:
|
def impl_getopt(self) -> BaseOption:
|
||||||
"""get to linked option
|
"""get to linked option"""
|
||||||
"""
|
|
||||||
return self._opt
|
return self._opt
|
||||||
|
|
||||||
def impl_is_multi(self) -> bool:
|
def impl_is_multi(self) -> bool:
|
||||||
"""is it a multi?
|
"""is it a multi?"""
|
||||||
"""
|
|
||||||
if self._opt.impl_is_multi():
|
if self._opt.impl_is_multi():
|
||||||
return True
|
return True
|
||||||
if self._opt.issubdyn() or self.issubdyn():
|
if self._opt.issubdyn() or self.issubdyn():
|
||||||
|
@ -91,6 +96,5 @@ class SymLinkOption(BaseOption):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def impl_is_submulti(self) -> bool:
|
def impl_is_submulti(self) -> bool:
|
||||||
"""is it a submulti?
|
"""is it a submulti?"""
|
||||||
"""
|
|
||||||
return self._opt.impl_is_submulti()
|
return self._opt.impl_is_submulti()
|
||||||
|
|
|
@ -32,93 +32,97 @@ from .portoption import PortOption
|
||||||
|
|
||||||
|
|
||||||
class URLOption(StrOption):
|
class URLOption(StrOption):
|
||||||
"""URLOption to check url value
|
"""URLOption to check url value"""
|
||||||
"""
|
|
||||||
__slots__ = tuple()
|
__slots__ = tuple()
|
||||||
path_re = re.compile(r"^[A-Za-z0-9\-\._~:/\?#\[\]@!%\$&\'\(\)\*\+,;=]+$")
|
path_re = re.compile(r"^[A-Za-z0-9\-\._~:/\?#\[\]@!%\$&\'\(\)\*\+,;=]+$")
|
||||||
_type = 'URL'
|
_type = "URL"
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
name: str,
|
self,
|
||||||
doc: str,
|
name: str,
|
||||||
*args,
|
doc: str,
|
||||||
allow_ip: bool=False,
|
*args,
|
||||||
type: str='domainname',
|
allow_ip: bool = False,
|
||||||
allow_without_dot=False,
|
type: str = "domainname",
|
||||||
allow_range: bool=False,
|
allow_without_dot=False,
|
||||||
allow_zero: bool=False,
|
allow_range: bool = False,
|
||||||
allow_wellknown: bool=True,
|
allow_zero: bool = False,
|
||||||
allow_registred: bool=True,
|
allow_wellknown: bool = True,
|
||||||
allow_private: bool=False,
|
allow_registred: bool = True,
|
||||||
**kwargs,
|
allow_private: bool = False,
|
||||||
) -> None:
|
**kwargs,
|
||||||
|
) -> None:
|
||||||
# pylint: disable=too-many-arguments,too-many-locals,redefined-builtin
|
# pylint: disable=too-many-arguments,too-many-locals,redefined-builtin
|
||||||
extra = {'_domainname': DomainnameOption(name,
|
extra = {
|
||||||
doc,
|
"_domainname": DomainnameOption(
|
||||||
allow_ip=allow_ip,
|
name,
|
||||||
type=type,
|
doc,
|
||||||
allow_without_dot=allow_without_dot),
|
allow_ip=allow_ip,
|
||||||
'_port': PortOption(name,
|
type=type,
|
||||||
doc,
|
allow_without_dot=allow_without_dot,
|
||||||
allow_range=allow_range,
|
),
|
||||||
allow_zero=allow_zero,
|
"_port": PortOption(
|
||||||
allow_wellknown=allow_wellknown,
|
name,
|
||||||
allow_registred=allow_registred,
|
doc,
|
||||||
allow_private=allow_private)}
|
allow_range=allow_range,
|
||||||
super().__init__(name,
|
allow_zero=allow_zero,
|
||||||
doc,
|
allow_wellknown=allow_wellknown,
|
||||||
extra=extra,
|
allow_registred=allow_registred,
|
||||||
*args,
|
allow_private=allow_private,
|
||||||
**kwargs,
|
),
|
||||||
)
|
}
|
||||||
|
super().__init__(
|
||||||
|
name,
|
||||||
|
doc,
|
||||||
|
extra=extra,
|
||||||
|
*args,
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
|
|
||||||
def _get_domain_port_files(self,
|
def _get_domain_port_files(self, value: str) -> (str, str):
|
||||||
value: str) -> (str, str):
|
if value.startswith("http://"):
|
||||||
if value.startswith('http://'):
|
type_ = "http"
|
||||||
type_ = 'http'
|
|
||||||
value = value[7:]
|
value = value[7:]
|
||||||
elif value.startswith('https://'):
|
elif value.startswith("https://"):
|
||||||
type_ = 'https'
|
type_ = "https"
|
||||||
value = value[8:]
|
value = value[8:]
|
||||||
else:
|
else:
|
||||||
raise ValueError(_('must start with http:// or '
|
raise ValueError(_("must start with http:// or " "https://"))
|
||||||
'https://'))
|
|
||||||
# get domain/files
|
# get domain/files
|
||||||
splitted = value.split('/', 1)
|
splitted = value.split("/", 1)
|
||||||
if len(splitted) == 1:
|
if len(splitted) == 1:
|
||||||
domain = value
|
domain = value
|
||||||
files = None
|
files = None
|
||||||
else:
|
else:
|
||||||
domain, files = splitted
|
domain, files = splitted
|
||||||
# if port in domain
|
# if port in domain
|
||||||
splitted = domain.split(':', 1)
|
splitted = domain.split(":", 1)
|
||||||
if len(splitted) == 1:
|
if len(splitted) == 1:
|
||||||
domain = splitted[0]
|
domain = splitted[0]
|
||||||
port = {'http': '80',
|
port = {"http": "80", "https": "443"}[type_]
|
||||||
'https': '443'}[type_]
|
|
||||||
else:
|
else:
|
||||||
domain, port = splitted
|
domain, port = splitted
|
||||||
return domain, port, files
|
return domain, port, files
|
||||||
|
|
||||||
def validate(self,
|
def validate(self, value: str) -> None:
|
||||||
value: str) -> None:
|
|
||||||
super().validate(value)
|
super().validate(value)
|
||||||
domain, port, files = self._get_domain_port_files(value)
|
domain, port, files = self._get_domain_port_files(value)
|
||||||
# validate port
|
# validate port
|
||||||
portoption = self.impl_get_extra('_port')
|
portoption = self.impl_get_extra("_port")
|
||||||
portoption.validate(port)
|
portoption.validate(port)
|
||||||
# validate domainname
|
# validate domainname
|
||||||
domainnameoption = self.impl_get_extra('_domainname')
|
domainnameoption = self.impl_get_extra("_domainname")
|
||||||
domainnameoption.validate(domain)
|
domainnameoption.validate(domain)
|
||||||
# validate files
|
# validate files
|
||||||
if files is not None and files != '' and not self.path_re.search(files):
|
if files is not None and files != "" and not self.path_re.search(files):
|
||||||
raise ValueError(_('must ends with a valid resource name'))
|
raise ValueError(_("must ends with a valid resource name"))
|
||||||
|
|
||||||
def second_level_validation(self, value, warnings_only):
|
def second_level_validation(self, value, warnings_only):
|
||||||
domain, port, _ = self._get_domain_port_files(value)
|
domain, port, _ = self._get_domain_port_files(value)
|
||||||
# validate port
|
# validate port
|
||||||
portoption = self.impl_get_extra('_port')
|
portoption = self.impl_get_extra("_port")
|
||||||
portoption.second_level_validation(port, warnings_only)
|
portoption.second_level_validation(port, warnings_only)
|
||||||
# validate domainname
|
# validate domainname
|
||||||
domainnameoption = self.impl_get_extra('_domainname')
|
domainnameoption = self.impl_get_extra("_domainname")
|
||||||
domainnameoption.second_level_validation(domain, warnings_only)
|
domainnameoption.second_level_validation(domain, warnings_only)
|
||||||
|
|
|
@ -27,16 +27,16 @@ from .stroption import RegexpOption
|
||||||
|
|
||||||
|
|
||||||
class UsernameOption(RegexpOption):
|
class UsernameOption(RegexpOption):
|
||||||
"""UsernameOption to check unix username value
|
"""UsernameOption to check unix username value"""
|
||||||
"""
|
|
||||||
__slots__ = tuple()
|
__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}$")
|
_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):
|
class GroupnameOption(UsernameOption):
|
||||||
"""GroupnameOption to check unix group value
|
"""GroupnameOption to check unix group value"""
|
||||||
"""
|
|
||||||
__slots__ = tuple()
|
__slots__ = tuple()
|
||||||
_type = 'unix groupname'
|
_type = "unix groupname"
|
||||||
|
|
File diff suppressed because it is too large
Load diff
1040
tiramisu/todict.py
1040
tiramisu/todict.py
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue