Compare commits
No commits in common. "main" and "feature/5.0" have entirely different histories.
main
...
feature/5.
83 changed files with 11537 additions and 12755 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,5 +1,6 @@
|
|||
*~
|
||||
*#
|
||||
*.pyc
|
||||
*.mo
|
||||
*.swp
|
||||
build/
|
||||
|
|
28
CHANGELOG.md
28
CHANGELOG.md
|
@ -1,31 +1,3 @@
|
|||
## 5.1.0rc0 (2024-11-06)
|
||||
|
||||
### Feat
|
||||
|
||||
- add min_len, max_len, forbidden_char for password option
|
||||
|
||||
## 5.0.0 (2024-11-01)
|
||||
|
||||
### Fix
|
||||
|
||||
- add changelog_merge_prerelease to commitizen
|
||||
|
||||
## 5.0.0rc0 (2024-11-01)
|
||||
|
||||
### Feat
|
||||
|
||||
- return propertyerror in function
|
||||
- mandatory for a variable and replace suffix to identifier
|
||||
- reorganise code
|
||||
|
||||
### Fix
|
||||
|
||||
- translation + black
|
||||
- regexp tests
|
||||
- update documentation
|
||||
- better permissive support
|
||||
- 4.1.0
|
||||
|
||||
## 4.0.2 (2024-02-20)
|
||||
|
||||
### Fix
|
||||
|
|
8
MANIFEST.in
Normal file
8
MANIFEST.in
Normal file
|
@ -0,0 +1,8 @@
|
|||
# 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,25 +1,13 @@
|
|||
![Logo Tiramisu](logo.png "logo Tiramisu")
|
||||
|
||||
An options controller tool
|
||||
-------------------------------------
|
||||
|
||||
Due to more and more available options required to set up an operating system,
|
||||
compiler options or whatever, it became quite annoying to hand the necessary
|
||||
options to where they are actually used and even more annoying to add new
|
||||
options. To circumvent these problems the configuration control was
|
||||
introduced...
|
||||
|
||||
Tiramisu is an options handler and an options controller, wich aims at
|
||||
producing flexible and fast options access.
|
||||
|
||||
|
||||
[Documentations](doc/README.md)
|
||||
|
||||
|
||||
# LICENSES
|
||||
|
||||
See [COPYING](COPYING) for the licences of the code and the documentation.
|
||||
See COPYING for the licences of the code and the documentation.
|
||||
|
||||
See [AUTHORS](AUTHORS) for the details about the tiramisu's team.
|
||||
See AUTHORS for the details about the tiramisu's team.
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -83,20 +83,20 @@ Here is how to print our :class:`Config` details:
|
|||
|
||||
Root config object that enables us to handle the configuration options
|
||||
|
||||
Settings:
|
||||
forcepermissive Access to option without verifying permissive properties
|
||||
unrestraint Access to option without property restriction
|
||||
nowarnings Do not warnings during validation
|
||||
|
||||
Commands:
|
||||
description Get option description
|
||||
dict Convert config and option to tiramisu format
|
||||
get Get Tiramisu option
|
||||
has_dependency Test if option has dependency
|
||||
isdynamic Test if option is a dynamic optiondescription
|
||||
isleadership Test if option is a leader or a follower
|
||||
isoptiondescription Test if option is an optiondescription
|
||||
list List options (by default list only option)
|
||||
name Get option name
|
||||
option Select an option by path
|
||||
path Get option path
|
||||
type Get de option type
|
||||
updates Updates value with tiramisu format
|
||||
cache Manage config cache
|
||||
config Actions to Config
|
||||
information Manage config informations
|
||||
option Select an option
|
||||
owner Global owner
|
||||
permissive Manage config permissives
|
||||
property Manage config properties
|
||||
value Manage config value
|
||||
|
||||
Then let's print our :class:`Option` details.
|
||||
|
||||
|
@ -105,35 +105,16 @@ Then let's print our :class:`Option` details.
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
Manage selected option
|
||||
Select an option
|
||||
|
||||
Call: Select an option by path
|
||||
|
||||
Commands:
|
||||
dependencies Get dependencies from this option
|
||||
description Get option description
|
||||
dict Convert config and option to tiramisu format
|
||||
extra Get de option extra
|
||||
followers Get the followers option for a leadership
|
||||
get Get Tiramisu option
|
||||
group_type Get type for an optiondescription (only for optiondescription)
|
||||
has_dependency Test if option has dependency
|
||||
identifiers Get identifiers for dynamic option
|
||||
index Get index of option
|
||||
isdynamic Test if option is a dynamic optiondescription
|
||||
isfollower Test if option is a follower
|
||||
isleader Test if option is a leader
|
||||
isleadership Test if option is a leader or a follower
|
||||
ismulti Test if option could have multi value
|
||||
isoptiondescription Test if option is an optiondescription
|
||||
issubmulti Test if option could have submulti value
|
||||
issymlinkoption Test if option is a symlink option
|
||||
leader Get the leader option for a leadership or a follower option
|
||||
list List options inside an option description (by default list only option)
|
||||
name Get option name
|
||||
option For OptionDescription get sub option, for symlinkoption get the linked option
|
||||
path Get option path
|
||||
pattern Get the option pattern
|
||||
type Get de option type
|
||||
updates Updates value with tiramisu format
|
||||
dict Convert config and option to tiramisu format
|
||||
find Find an or a list of options
|
||||
list List options (by default list only option)
|
||||
name get the name
|
||||
updates Updates value with tiramisu format
|
||||
|
||||
Finaly, let's print the :class:`Config`.
|
||||
|
||||
|
@ -142,7 +123,7 @@ Finaly, let's print the :class:`Config`.
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
<Config path=None>
|
||||
<tiramisu.api.Config object at 0x7f3ee6204278>
|
||||
|
||||
:download:`download the getting started code <src/getting_started.py>`
|
||||
|
||||
|
|
|
@ -25,32 +25,26 @@ Dynamic option description is an :class:`OptionDescription` which multiplies acc
|
|||
|
||||
Note:: the option can be an :doc:`option` or an other option description
|
||||
|
||||
* - identifiers
|
||||
- Identifiers is a :doc:`calculation` that return the list of identifiers used to create dynamic option description.
|
||||
* - suffixes
|
||||
- Suffixes is a :doc:`calculation` that return the list of suffixes used to create dynamic option description.
|
||||
|
||||
* - properties
|
||||
- A list of :doc:`property` (inside a frozenset().
|
||||
|
||||
* - informations
|
||||
- We can add default informations to this option description.
|
||||
|
||||
* - group_type
|
||||
- Type for this group.
|
||||
|
||||
Example
|
||||
==============
|
||||
|
||||
Let's try:
|
||||
|
||||
>>> from tiramisu import StrOption, DynOptionDescription, Calculation
|
||||
>>> def return_identifiers():
|
||||
>>> def return_suffixes():
|
||||
... return ['1', '2']
|
||||
>>> child1 = StrOption('first', 'First basic option ')
|
||||
>>> child2 = StrOption('second', 'Second basic option ')
|
||||
>>> DynOptionDescription('basic ',
|
||||
... 'Basic options ',
|
||||
... [child1, child2],
|
||||
... Calculation(return_identifiers))
|
||||
... Calculation(return_suffixes))
|
||||
|
||||
This example will construct:
|
||||
|
||||
|
|
|
@ -35,9 +35,6 @@ The leadership
|
|||
* - properties
|
||||
- A list of :doc:`property` (inside a frozenset().
|
||||
|
||||
* - informations
|
||||
- We can add default informations to this option description.
|
||||
|
||||
Example
|
||||
====================
|
||||
|
||||
|
|
|
@ -18,6 +18,9 @@ Option
|
|||
* - doc
|
||||
- The `description` allows the user to understand where this option will be used for.
|
||||
|
||||
* - multi
|
||||
- There are cases where it can be interesting to have a list of values rather than just one.
|
||||
|
||||
* - default
|
||||
- For each option, we can defined a default value. This value will be the value of this option until user customize it.
|
||||
|
||||
|
@ -32,20 +35,14 @@ Option
|
|||
|
||||
The default_multi value can be a :doc:`calculation`.
|
||||
|
||||
* - multi
|
||||
- There are cases where it can be interesting to have a list of values rather than just one.
|
||||
|
||||
* - validators
|
||||
- A list of :doc:`validator`.
|
||||
|
||||
* - properties
|
||||
- A list of :doc:`property` (inside a frozenset().
|
||||
|
||||
* - warnings_only
|
||||
- Only emit warnings if not type validation is invalid.
|
||||
|
||||
* - informations
|
||||
- We can add default informations to this option.
|
||||
* - properties
|
||||
- A list of :doc:`property` (inside a frozenset().
|
||||
|
||||
|
||||
Examples
|
||||
|
|
|
@ -25,12 +25,6 @@ Option description
|
|||
* - properties
|
||||
- A list of :doc:`property` (inside a frozenset().
|
||||
|
||||
* - informations
|
||||
- We can add default informations to this option description.
|
||||
|
||||
* - group_type
|
||||
- Type for this group.
|
||||
|
||||
Examples
|
||||
==============
|
||||
|
||||
|
|
|
@ -103,7 +103,7 @@ Network options
|
|||
-
|
||||
|
||||
* - BroadcastOption
|
||||
- The last address within a network broadcast transmission to all hosts on the link. This option allow you to enter a broadcast.
|
||||
- The last address within a network broadcast transmission to all hosts on the link. This option allow you to enter a broadcast:
|
||||
-
|
||||
|
||||
* - PortOption
|
||||
|
@ -114,10 +114,6 @@ Network options
|
|||
- allow_wellknown: by default, the well-known ports (also known as system ports) those from 1 through 1023 are allowed, you can disabled it
|
||||
- allow_registred: by default, the registered ports are those from 1024 through 49151 are allowed, you can disabled it
|
||||
- allow_private: allow dynamic or private ports, which are those from 49152 through 65535, one common use for this range is for ephemeral ports
|
||||
- allow_protocol: allow to define protocol in value, it should be something like tcp:80 or udp:53
|
||||
|
||||
* - MACOption
|
||||
- MAC address for a network card.
|
||||
|
||||
|
||||
Examples
|
||||
|
@ -280,35 +276,18 @@ Unix options
|
|||
|
||||
* - Type
|
||||
- Comments
|
||||
- Extra parameters
|
||||
|
||||
* - UsernameOption
|
||||
- An unix username option is a 32 characters maximum length with lowercase ASCII characters, number, '_' or '-'. The username have to start with lowercase ASCII characters or "_".
|
||||
-
|
||||
|
||||
* - GroupnameOption
|
||||
- Same conditions has username
|
||||
-
|
||||
|
||||
* - PasswordOption
|
||||
- Simple string with no other restriction:
|
||||
-
|
||||
- min_len: minimum length autorise for a password
|
||||
- max_len: maximum length autorise for a passwword
|
||||
- forbidden_char: list of forbidden characters for a password
|
||||
|
||||
* - FilenameOption
|
||||
- For this option, only lowercase and uppercas ASCII character, "-", ".", "_", "~", and "/" are allowed.
|
||||
-
|
||||
- allow_relative: filename should starts with "/" (something like /etc/passwd), we can, with this option to allow relative name
|
||||
- test_existence: file or directory should exists
|
||||
- types
|
||||
- file: it should be a file
|
||||
- directory: it should be a directory
|
||||
|
||||
* - PermissionsOption
|
||||
- Permissions for Unix file. It could be something like 644 or 1644.
|
||||
-
|
||||
|
||||
>>> from tiramisu import UsernameOption
|
||||
>>> UsernameOption('user', 'user', 'my_user')
|
||||
|
|
|
@ -14,6 +14,6 @@ cfg = Config(descr)
|
|||
# the global help about the config
|
||||
cfg.help()
|
||||
# help about an option
|
||||
cfg.option("bool").help()
|
||||
cfg.option.help()
|
||||
# the config's __repr__
|
||||
print(cfg)
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,823 +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: 2024-11-05 08:52+0100\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"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/passwordoption.py:49
|
||||
msgid "at least {0} characters are required"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/passwordoption.py:52
|
||||
msgid "maximum {0} characters required"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/passwordoption.py:57
|
||||
msgid "must not have the characters {0}"
|
||||
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 ""
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
[build-system]
|
||||
build-backend = "flit_core.buildapi"
|
||||
requires = ["flit_core >=3.8.0,<4"]
|
||||
|
||||
[project]
|
||||
name = "tiramisu"
|
||||
version = "5.1.0"
|
||||
authors = [{name = "Emmanuel Garette", email = "gnunux@gnunux.info"}]
|
||||
readme = "README.md"
|
||||
description = "an options controller tool"
|
||||
requires-python = ">=3.8"
|
||||
license = {file = "LICENSE"}
|
||||
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
|
||||
changelog_merge_prerelease = true
|
52
setup.py
Normal file
52
setup.py
Normal file
|
@ -0,0 +1,52 @@
|
|||
#!/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://framagit.org/tiramisu/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],
|
||||
)
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"options.unicode": null
|
||||
}
|
|
@ -32,9 +32,6 @@ def list_data(ext='.py'):
|
|||
for filename in filenames:
|
||||
# if filename.endswith(ext) and not filename.startswith('__'):
|
||||
if filename.endswith(ext) and not filename.startswith('__') and not 'not_equal' in filename and not 'callback' in filename and not filename == 'unicode2_copy.py' and not filename == 'unicode2_multi_copy.py':
|
||||
# if 'leadership' in filename:
|
||||
# print('FIXME')
|
||||
# continue
|
||||
ret.append(filename)
|
||||
return ret
|
||||
|
||||
|
@ -61,7 +58,7 @@ def load_config(filename,
|
|||
form.extend(mod.get_form(add_extra_od))
|
||||
config.property.read_write()
|
||||
if root is None:
|
||||
values = loads(dumps(config.dict(remotable=remote, clearable=clearable, form=form)))
|
||||
values = loads(dumps(config.option.dict(remotable=remote, clearable=clearable, form=form)))
|
||||
else:
|
||||
values = loads(dumps(config.option(root).dict(remotable=remote, clearable=clearable, form=form)))
|
||||
return values
|
||||
|
@ -383,12 +380,11 @@ def test_updates(filename_mod):
|
|||
if dico_ori is None:
|
||||
if clearable == 'minimum' and remote == 'minimum':
|
||||
with open(join(datadir, modulepath + '.dict'), 'w') as fh:
|
||||
pouet
|
||||
dump(config.value.get(), fh, indent=2)
|
||||
dump(config.value.dict(), fh, indent=2)
|
||||
else:
|
||||
assert config.value.get() == dico_ori, "clearable {}, remote: {}, filename: {}".format(clearable, remote, filename_mod)
|
||||
assert config.value.dict() == dico_ori, "clearable {}, remote: {}, filename: {}".format(clearable, remote, filename_mod)
|
||||
if root is None:
|
||||
suboption = config
|
||||
suboption = config.option
|
||||
else:
|
||||
suboption = config.option(root)
|
||||
if with_model:
|
||||
|
|
|
@ -81,10 +81,10 @@ def test_cache_importation_property():
|
|||
def test_cache_importation_permissive():
|
||||
od1 = make_description()
|
||||
cfg = Config(od1)
|
||||
cfg.option('u2').permissive.add('prop')
|
||||
cfg.option('u2').permissive.set(frozenset(['prop']))
|
||||
export = cfg.permissive.exportation()
|
||||
assert cfg.option('u2').permissive.get() == {'prop'}
|
||||
cfg.option('u2').permissive.add('prop2')
|
||||
cfg.option('u2').permissive.set(frozenset(['prop', 'prop2']))
|
||||
assert cfg.option('u2').permissive.get() == {'prop', 'prop2'}
|
||||
cfg.permissive.importation(export)
|
||||
assert cfg.option('u2').permissive.get() == {'prop'}
|
||||
|
@ -266,7 +266,7 @@ def test_cache_leadership():
|
|||
#assert cache['ip_admin_eth0.netmask_admin_eth0'][None][0] == [None]
|
||||
#assert cache['ip_admin_eth0.netmask_admin_eth0'][0][0] is None
|
||||
cache = settings.get_cached()
|
||||
assert set(cache.keys()) == set(['ip_admin_eth0', 'ip_admin_eth0.ip_admin_eth0', 'ip_admin_eth0.netmask_admin_eth0'])
|
||||
assert set(cache.keys()) == set([None, 'ip_admin_eth0', 'ip_admin_eth0.ip_admin_eth0', 'ip_admin_eth0.netmask_admin_eth0'])
|
||||
assert set(cache['ip_admin_eth0'].keys()) == set([None])
|
||||
assert set(cache['ip_admin_eth0.ip_admin_eth0'].keys()) == set([None])
|
||||
assert set(cache['ip_admin_eth0.netmask_admin_eth0'].keys()) == {0}
|
||||
|
@ -284,7 +284,7 @@ def test_cache_leadership():
|
|||
#assert cache['ip_admin_eth0.netmask_admin_eth0'][0][0] is None
|
||||
#assert cache['ip_admin_eth0.netmask_admin_eth0'][1][0] is None
|
||||
cache = settings.get_cached()
|
||||
assert set(cache.keys()) == set(['ip_admin_eth0', 'ip_admin_eth0.ip_admin_eth0', 'ip_admin_eth0.netmask_admin_eth0'])
|
||||
assert set(cache.keys()) == set([None, 'ip_admin_eth0', 'ip_admin_eth0.ip_admin_eth0', 'ip_admin_eth0.netmask_admin_eth0'])
|
||||
assert set(cache['ip_admin_eth0'].keys()) == set([None])
|
||||
assert set(cache['ip_admin_eth0.ip_admin_eth0'].keys()) == set([None])
|
||||
assert set(cache['ip_admin_eth0.netmask_admin_eth0'].keys()) == set([0, 1])
|
||||
|
@ -376,22 +376,26 @@ def test_cache_leader_and_followers():
|
|||
idx_val2 = None
|
||||
values = cfg._config_bag.context._impl_values_cache
|
||||
settings = cfg._config_bag.context.properties_cache
|
||||
compare(settings.get_cached(), {'val1': {None: (val1_props, None)},
|
||||
'val1.val1': {None: (val1_val1_props, None)},
|
||||
})
|
||||
compare(settings.get_cached(), {None: {None: (global_props, None)},
|
||||
'val1': {None: (val1_props, None)},
|
||||
'val1.val1': {None: (val1_val1_props, None)},
|
||||
})
|
||||
# len is 0 so don't get any value
|
||||
compare(values.get_cached(), {'val1.val1': {None: ([], None)}})
|
||||
#
|
||||
cfg.option('val1.val1').value.set([None])
|
||||
val_val2_props = {idx_val2: (val1_val2_props, None), None: (set(), None)}
|
||||
compare(settings.get_cached(), {'val1.val1': {None: ({'empty', 'unique'}, None, True)}})
|
||||
compare(settings.get_cached(), {None: {None: (set(global_props), None)},
|
||||
# 'val1.val1': {None: (val1_val1_props, None)},
|
||||
})
|
||||
compare(values.get_cached(), {'val1.val1': {None: ([None], None, True)}})
|
||||
cfg.value.get()
|
||||
#has value
|
||||
idx_val2 = 0
|
||||
val_val2 = None
|
||||
val_val2_props = {idx_val2: (val1_val2_props, None)}
|
||||
compare(settings.get_cached(), {'val1': {None: (val1_props, None)},
|
||||
compare(settings.get_cached(), {None: {None: (global_props, None)},
|
||||
'val1': {None: (val1_props, None)},
|
||||
'val1.val1': {None: (val1_val1_props, None)},
|
||||
'val1.val2': val_val2_props})
|
||||
compare(values.get_cached(), {'val1.val1': {None: ([None], None)},
|
||||
|
@ -400,7 +404,7 @@ def test_cache_leader_and_followers():
|
|||
cfg.option('val1.val1').value.set([None, None])
|
||||
cfg.value.get()
|
||||
cfg.option('val1.val2', 1).value.set('oui')
|
||||
compare(settings.get_cached(), {})
|
||||
compare(settings.get_cached(), {None: {None: (set(['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings', 'force_store_value']), None)}})
|
||||
compare(values.get_cached(), {'val1.val2': {1: ('oui', None, True)}})
|
||||
val1_val2_props = {0: (frozenset([]), None), 1: (frozenset([]), None)}
|
||||
# assert not list_sessions()
|
||||
|
@ -424,12 +428,15 @@ def test_cache_leader_callback():
|
|||
val1_val2_props = frozenset(val1_val2_props)
|
||||
values = cfg._config_bag.context._impl_values_cache
|
||||
settings = cfg._config_bag.context.properties_cache
|
||||
compare(settings.get_cached(), {'val1': {None: (val1_props, None)},
|
||||
compare(settings.get_cached(), {None: {None: (global_props, None)},
|
||||
'val1': {None: (val1_props, None)},
|
||||
'val1.val1': {None: (val1_val1_props, None)},
|
||||
})
|
||||
compare(values.get_cached(), {'val1.val1': {None: ([], None)}})
|
||||
cfg.option('val1.val1').value.set([None])
|
||||
compare(settings.get_cached(), {'val1.val1': {None: ({'unique', 'empty'}, None, True)}})
|
||||
compare(settings.get_cached(), {None: {None: (set(global_props), None)},
|
||||
# 'val1.val1': {None: (val1_val1_props, None)},
|
||||
})
|
||||
|
||||
compare(values.get_cached(), {'val1.val1': {None: ([None], None, True)}})
|
||||
cfg.value.get()
|
||||
|
@ -451,34 +458,39 @@ def test_cache_requires():
|
|||
settings = cfg._config_bag.context.properties_cache
|
||||
assert values.get_cached() == {}
|
||||
assert cfg.option('ip_address_service').value.get() == None
|
||||
compare(settings.get_cached(), {'activate_service': {None: (set([]), None)},
|
||||
'ip_address_service': {None: (set([]), None)}})
|
||||
compare(settings.get_cached(), {None: {None: (set(['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings', 'force_store_value']), None)},
|
||||
'activate_service': {None: (set([]), None)},
|
||||
'ip_address_service': {None: (set([]), None)}})
|
||||
|
||||
compare(values.get_cached(), {'ip_address_service': {None: (None, None)},
|
||||
'activate_service': {None: (True, None)}})
|
||||
cfg.value.get()
|
||||
compare(settings.get_cached(), {'activate_service': {None: (set([]), None)},
|
||||
'ip_address_service': {None: (set([]), None)}})
|
||||
compare(settings.get_cached(), {None: {None: (set(['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings', 'force_store_value']), None)},
|
||||
'activate_service': {None: (set([]), None)},
|
||||
'ip_address_service': {None: (set([]), None)}})
|
||||
|
||||
compare(values.get_cached(), {'ip_address_service': {None: (None, None)},
|
||||
'activate_service': {None: (True, None)}})
|
||||
'activate_service': {None: (True, None)}})
|
||||
cfg.option('ip_address_service').value.set('1.1.1.1')
|
||||
compare(settings.get_cached(), {'activate_service': {None: (set([]), None)}})
|
||||
compare(settings.get_cached(), {None: {None: (set(['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings', 'force_store_value']), None)},
|
||||
'activate_service': {None: (set([]), None)}})
|
||||
|
||||
compare(values.get_cached(), {'activate_service': {None: (True, None)}, 'ip_address_service': {None: ('1.1.1.1', None, True)}})
|
||||
cfg.value.get()
|
||||
compare(settings.get_cached(), {'activate_service': {None: (set([]), None)},
|
||||
'ip_address_service': {None: (set([]), None)}})
|
||||
compare(settings.get_cached(), {None: {None: (set(['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings', 'force_store_value']), None)},
|
||||
'activate_service': {None: (set([]), None)},
|
||||
'ip_address_service': {None: (set([]), None)}})
|
||||
|
||||
compare(values.get_cached(), {'ip_address_service': {None: ('1.1.1.1', None)},
|
||||
'activate_service': {None: (True, None)}})
|
||||
cfg.option('activate_service').value.set(False)
|
||||
compare(settings.get_cached(), {})
|
||||
compare(settings.get_cached(), {None: {None: (set(['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings', 'force_store_value']), None)}})
|
||||
|
||||
compare(values.get_cached(), {'activate_service': {None: (False, None)}})
|
||||
cfg.value.get()
|
||||
compare(settings.get_cached(), {'activate_service': {None: (set([]), None)},
|
||||
'ip_address_service': {None: (set(['disabled']), None)}})
|
||||
compare(settings.get_cached(), {None: {None: (set(['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings', 'force_store_value']), None)},
|
||||
'activate_service': {None: (set([]), None)},
|
||||
'ip_address_service': {None: (set(['disabled']), None)}})
|
||||
|
||||
compare(values.get_cached(), {'activate_service': {None: (False, None)}})
|
||||
# assert not list_sessions()
|
||||
|
@ -499,19 +511,22 @@ def test_cache_global_properties():
|
|||
settings = cfg._config_bag.context.properties_cache
|
||||
assert values.get_cached() == {}
|
||||
assert cfg.option('ip_address_service').value.get() == None
|
||||
compare(settings.get_cached(), {'activate_service': {None: (set([]), None)},
|
||||
'ip_address_service': {None: (set([]), None)}})
|
||||
compare(settings.get_cached(), {None: {None: (set(['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings', 'force_store_value']), None)},
|
||||
'activate_service': {None: (set([]), None)},
|
||||
'ip_address_service': {None: (set([]), None)}})
|
||||
|
||||
compare(values.get_cached(), {'ip_address_service': {None: (None, None)},
|
||||
'activate_service': {None: (True, None)}})
|
||||
cfg.property.remove('disabled')
|
||||
assert cfg.option('ip_address_service').value.get() == None
|
||||
compare(settings.get_cached(), {'activate_service': {None: (set([]), None)},
|
||||
'ip_address_service': {None: (set([]), None)}})
|
||||
compare(settings.get_cached(), {None: {None: (set(['cache', 'frozen', 'hidden', 'validator', 'warnings', 'force_store_value']), None)},
|
||||
'activate_service': {None: (set([]), None)},
|
||||
'ip_address_service': {None: (set([]), None)}})
|
||||
cfg.property.add('test')
|
||||
assert cfg.option('ip_address_service').value.get() == None
|
||||
compare(settings.get_cached(), {'activate_service': {None: (set([]), None)},
|
||||
'ip_address_service': {None: (set([]), None)}})
|
||||
compare(settings.get_cached(), {None: {None: (set(['cache', 'frozen', 'hidden', 'validator', 'warnings', 'test', 'force_store_value']), None)},
|
||||
'activate_service': {None: (set([]), None)},
|
||||
'ip_address_service': {None: (set([]), None)}})
|
||||
# assert not list_sessions()
|
||||
|
||||
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
# coding: utf-8
|
||||
from py.test import raises
|
||||
|
||||
from .autopath import do_autopath
|
||||
do_autopath()
|
||||
from .config import config_type, get_config, value_list, global_owner, parse_od_get
|
||||
from .config import config_type, get_config, value_list, global_owner
|
||||
|
||||
from pytest import raises
|
||||
from tiramisu import ChoiceOption, StrOption, OptionDescription, Config, owners, Calculation, \
|
||||
undefined, Params, ParamValue, ParamOption
|
||||
from tiramisu.error import ConfigError
|
||||
|
@ -72,30 +73,6 @@ def test_choiceoption_function(config_type):
|
|||
assert cfg.option('choice').owner.isdefault()
|
||||
#
|
||||
assert value_list(cfg.option('choice').value.list()) == ('val1', 'val2')
|
||||
assert isinstance(cfg.option('choice').value.list(uncalculated=True), Calculation)
|
||||
# assert not list_sessions()
|
||||
|
||||
|
||||
def test_choiceoption_subfunction(config_type):
|
||||
choice = ChoiceOption('choice', '', values=(Calculation(return_val, Params(ParamValue('val1'))), Calculation(return_val, Params(ParamValue('val2')))))
|
||||
od1 = OptionDescription('od', '', [choice])
|
||||
cfg = Config(od1)
|
||||
cfg.property.read_write()
|
||||
cfg = get_config(cfg, config_type)
|
||||
owner = global_owner(cfg, config_type)
|
||||
assert cfg.option('choice').owner.isdefault()
|
||||
#
|
||||
cfg.option('choice').value.set('val1')
|
||||
assert cfg.option('choice').owner.get() == owner
|
||||
#
|
||||
cfg.option('choice').value.reset()
|
||||
assert cfg.option('choice').owner.isdefault()
|
||||
#
|
||||
with raises(ValueError):
|
||||
cfg.option('choice').value.set('no')
|
||||
assert cfg.option('choice').owner.isdefault()
|
||||
#
|
||||
assert value_list(cfg.option('choice').value.list()) == ('val1', 'val2')
|
||||
# assert not list_sessions()
|
||||
|
||||
|
||||
|
@ -285,13 +262,3 @@ def test_choiceoption_calc_not_list():
|
|||
with raises(ConfigError):
|
||||
cfg.option('choice').value.set(['val1'])
|
||||
# assert not list_sessions()
|
||||
|
||||
|
||||
def test_choiceoption_calc_default_value():
|
||||
var1 = StrOption("var1", '', default="val1")
|
||||
var2 = StrOption("var2", '', default="val2")
|
||||
choice = ChoiceOption("choice", '', values=(Calculation(return_val, Params((ParamOption(var1)))), Calculation(return_val, Params((ParamOption(var2))))), default="val1")
|
||||
od2 = OptionDescription("rougail", '', children=[var1, var2, choice])
|
||||
od1 = OptionDescription("baseoption", "", children=[od2])
|
||||
cfg = Config(od1)
|
||||
assert parse_od_get(cfg.value.get()) == {'rougail.var1': 'val1', 'rougail.var2': 'val2', 'rougail.choice': 'val1'}
|
||||
|
|
|
@ -9,14 +9,10 @@ do_autopath()
|
|||
from .config import config_type, get_config, value_list, global_owner
|
||||
|
||||
import pytest
|
||||
from tiramisu import Config, Calculation, Params, ParamSelfInformation, calc_value
|
||||
from tiramisu import Config
|
||||
from tiramisu.i18n import _
|
||||
from tiramisu import Config, IntOption, FloatOption, ChoiceOption, \
|
||||
BoolOption, StrOption, SymLinkOption, OptionDescription, undefined, \
|
||||
DomainnameOption, EmailOption, URLOption, RegexpOption, IPOption, \
|
||||
PortOption, NetworkOption, NetmaskOption, BroadcastOption, UsernameOption, \
|
||||
GroupnameOption, DateOption, FilenameOption, PasswordOption, MACOption, \
|
||||
PermissionsOption
|
||||
BoolOption, StrOption, SymLinkOption, OptionDescription, undefined
|
||||
from tiramisu.error import ConflictError, ConfigError, PropertiesOptionError
|
||||
|
||||
|
||||
|
@ -30,7 +26,8 @@ def make_description():
|
|||
floatoption = FloatOption('float', 'Test float option', default=2.3)
|
||||
stroption = StrOption('str', 'Test string option', default="abc", properties=('mandatory', ))
|
||||
boolop = BoolOption('boolop', 'Test boolean option op', default=True, properties=('hidden',))
|
||||
wantref_option = BoolOption('wantref', 'Test requires', default=False, informations={'info': 'default value'})
|
||||
wantref_option = BoolOption('wantref', 'Test requires', default=False)
|
||||
wantref_option.impl_set_information('info', 'default value')
|
||||
wantframework_option = BoolOption('wantframework', 'Test requires',
|
||||
default=False)
|
||||
|
||||
|
@ -133,29 +130,6 @@ def test_not_valid_properties():
|
|||
# assert not list_sessions()
|
||||
|
||||
|
||||
def test_information_load():
|
||||
ChoiceOption('a', '', ('a', 'b'), informations={'info': 'value'})
|
||||
BoolOption('a', '', informations={'info': 'value'})
|
||||
IntOption('a', '', informations={'info': 'value'})
|
||||
FloatOption('a', '', informations={'info': 'value'})
|
||||
StrOption('a', '', informations={'info': 'value'})
|
||||
RegexpOption('a', '', informations={'info': 'value'})
|
||||
IPOption('a', '', informations={'info': 'value'})
|
||||
PortOption('a', '', informations={'info': 'value'})
|
||||
NetworkOption('a', '', informations={'info': 'value'})
|
||||
NetmaskOption('a', '', informations={'info': 'value'})
|
||||
BroadcastOption('a', '', informations={'info': 'value'})
|
||||
DomainnameOption('a', '', informations={'info': 'value'})
|
||||
EmailOption('a', '', informations={'info': 'value'})
|
||||
URLOption('a', '', informations={'info': 'value'})
|
||||
UsernameOption('a', '', informations={'info': 'value'})
|
||||
GroupnameOption('a', '', informations={'info': 'value'})
|
||||
DateOption('a', '', informations={'info': 'value'})
|
||||
FilenameOption('a', '', informations={'info': 'value'})
|
||||
PasswordOption('a', '', informations={'info': 'value'})
|
||||
MACOption('a', '', informations={'info': 'value'})
|
||||
PermissionsOption('a', '', informations={'info': 'value'})
|
||||
|
||||
def test_information_config():
|
||||
od1 = make_description()
|
||||
cfg = Config(od1)
|
||||
|
@ -169,11 +143,11 @@ def test_information_config():
|
|||
with pytest.raises(ValueError):
|
||||
cfg.information.get('noinfo')
|
||||
assert cfg.information.get('noinfo', 'default') == 'default'
|
||||
cfg.information.remove('info')
|
||||
cfg.information.reset('info')
|
||||
with pytest.raises(ValueError):
|
||||
cfg.information.remove('info')
|
||||
cfg.information.get('info')
|
||||
with pytest.raises(ValueError):
|
||||
cfg.information.remove('noinfo')
|
||||
cfg.information.reset('noinfo')
|
||||
assert list(cfg.information.list()) == ['doc']
|
||||
# assert not list_sessions()
|
||||
|
||||
|
@ -220,23 +194,26 @@ def test_information_option():
|
|||
with pytest.raises(ValueError):
|
||||
cfg.option('gc.name').information.get('noinfo')
|
||||
assert cfg.option('gc.name').information.get('noinfo', 'default') == 'default'
|
||||
cfg.option('gc.name').information.remove('info')
|
||||
cfg.option('gc.name').information.reset('info')
|
||||
with pytest.raises(ValueError):
|
||||
cfg.option('gc.name').information.get('info')
|
||||
with pytest.raises(ValueError):
|
||||
cfg.option('gc.name').information.remove('noinfo')
|
||||
cfg.option('gc.name').information.reset('noinfo')
|
||||
assert list(cfg.option('gc.name').information.list()) == ['doc']
|
||||
#
|
||||
assert cfg.option('wantref').information.get('info') == 'default value'
|
||||
cfg.option('wantref').information.set('info', 'default value')
|
||||
assert cfg.option('wantref').information.get('info') == 'default value'
|
||||
cfg.option('wantref').information.remove('info')
|
||||
cfg.option('wantref').information.reset('info')
|
||||
assert cfg.option('wantref').information.get('info') == 'default value'
|
||||
# assert not list_sessions()
|
||||
|
||||
|
||||
def test_information_option_2():
|
||||
i1 = IntOption('test1', '', informations={'info': 'value'})
|
||||
i1 = IntOption('test1', '')
|
||||
i1.impl_set_information('info', 'value')
|
||||
# it's a dict
|
||||
assert set(i1.impl_list_information()) == {'info', 'doc'}
|
||||
od1 = OptionDescription('test', '', [i1])
|
||||
cfg = Config(od1)
|
||||
# it's tuples
|
||||
|
@ -244,17 +221,6 @@ def test_information_option_2():
|
|||
# assert not list_sessions()
|
||||
|
||||
|
||||
def test_information_option_symlink():
|
||||
i1 = IntOption('test1', '', Calculation(calc_value, Params(ParamSelfInformation('info'))), informations={'info': 'value'})
|
||||
i2 = SymLinkOption('test2', i1)
|
||||
od1 = OptionDescription('test', '', [i2, i1])
|
||||
cfg = Config(od1)
|
||||
# it's tuples
|
||||
assert set(cfg.option('test1').information.list()) == {'info', 'doc'}
|
||||
assert set(cfg.option('test2').information.list()) == {'info', 'doc'}
|
||||
# assert not list_sessions()
|
||||
|
||||
|
||||
def test_information_optiondescription():
|
||||
od1 = make_description()
|
||||
cfg = Config(od1)
|
||||
|
@ -268,11 +234,11 @@ def test_information_optiondescription():
|
|||
with pytest.raises(ValueError):
|
||||
cfg.option('gc').information.get('noinfo')
|
||||
assert cfg.option('gc').information.get('noinfo', 'default') == 'default'
|
||||
cfg.option('gc').information.remove('info')
|
||||
cfg.option('gc').information.reset('info')
|
||||
with pytest.raises(ValueError):
|
||||
cfg.option('gc').information.get('info')
|
||||
with pytest.raises(ValueError):
|
||||
cfg.option('gc').information.remove('noinfo')
|
||||
cfg.option('gc').information.reset('noinfo')
|
||||
assert list(cfg.option('gc').information.list()) == ['doc']
|
||||
# assert not list_sessions()
|
||||
|
||||
|
@ -446,7 +412,7 @@ def test_config_od_name(config_type):
|
|||
cfg = get_config(cfg, config_type)
|
||||
assert cfg.option('val.i').name() == 'i'
|
||||
assert cfg.option('val.s').name() == 's'
|
||||
assert cfg.option('val.s').type() == 'integer'
|
||||
assert cfg.option('val.s').type() == _('integer')
|
||||
assert cfg.option('val').type() == 'optiondescription'
|
||||
# assert not list_sessions()
|
||||
|
||||
|
@ -458,7 +424,7 @@ def test_config_od_type(config_type):
|
|||
cfg = Config(o2)
|
||||
cfg = get_config(cfg, config_type)
|
||||
assert cfg.option('val').type() == 'optiondescription'
|
||||
assert cfg.option('val.i').type() == 'integer'
|
||||
assert cfg.option('val.i').type() == _('integer')
|
||||
# assert not list_sessions()
|
||||
|
||||
|
||||
|
|
|
@ -412,6 +412,7 @@ def test_help():
|
|||
cfg = Config(od2)
|
||||
cfg.help(_display=False)
|
||||
cfg.config.help(_display=False)
|
||||
cfg.option.help(_display=False)
|
||||
cfg.option('o').help(_display=False)
|
||||
cfg.option('o.s').help(_display=False)
|
||||
# assert not list_sessions()
|
||||
|
@ -429,7 +430,7 @@ def test_config_reset():
|
|||
#
|
||||
cfg.option('gc.gc2.bool').value.set(True)
|
||||
cfg.option('boolop').property.add('test')
|
||||
cfg.option('float').permissive.add('test')
|
||||
cfg.option('float').permissive.set(frozenset(['test']))
|
||||
cfg.option('wantref').information.set('info', 'info')
|
||||
assert cfg.option('gc.gc2.bool').value.get()
|
||||
assert cfg.option('boolop').property.get()
|
||||
|
|
|
@ -201,7 +201,7 @@ def test_deref_symlink():
|
|||
def test_deref_dyn():
|
||||
a = StrOption('a', '', ['val1', 'val2'], multi=True)
|
||||
b = StrOption('b', '')
|
||||
dod = DynOptionDescription('dod', '', [b], identifiers=Calculation(funcname, Params((ParamOption(a),))))
|
||||
dod = DynOptionDescription('dod', '', [b], suffixes=Calculation(funcname, Params((ParamOption(a),))))
|
||||
o = OptionDescription('od', '', [dod, a])
|
||||
cfg = Config(o)
|
||||
w = weakref.ref(a)
|
||||
|
|
|
@ -59,27 +59,27 @@ def test_copy_information():
|
|||
ncfg = cfg.config.copy()
|
||||
assert ncfg.information.get('key') == 'value'
|
||||
# assert not list_sessions()
|
||||
|
||||
|
||||
def test_copy_force_store_value():
|
||||
od1 = make_description()
|
||||
conf = Config(od1)
|
||||
conf2 = Config(od1)
|
||||
assert conf.value.exportation() == {}
|
||||
assert conf2.value.exportation() == {}
|
||||
#
|
||||
conf.property.read_write()
|
||||
assert conf.value.exportation() == {'creole.general.wantref': {None: [False, 'forced']}}
|
||||
assert conf2.value.exportation() == {}
|
||||
#
|
||||
conf2.property.read_only()
|
||||
assert conf.value.exportation() == {'creole.general.wantref': {None: [False, 'forced']}}
|
||||
assert conf2.value.exportation() == {'creole.general.wantref': {None: [False, 'forced']}}
|
||||
#
|
||||
conf.option('creole.general.wantref').value.set(True)
|
||||
assert conf.value.exportation() == {'creole.general.wantref': {None: [True, 'user']}}
|
||||
assert conf2.value.exportation() == {'creole.general.wantref': {None: [False, 'forced']}}
|
||||
# assert not list_sessions()
|
||||
#
|
||||
#
|
||||
#def test_copy_force_store_value():
|
||||
# od1 = make_description()
|
||||
# conf = Config(od1)
|
||||
# conf2 = Config(od1)
|
||||
# assert conf.value.exportation() == {}
|
||||
# assert conf2.value.exportation() == {}
|
||||
# #
|
||||
# conf.property.read_write()
|
||||
# assert conf.value.exportation() == {'creole.general.wantref': {None: [False, 'forced']}}
|
||||
# assert conf2.value.exportation() == {}
|
||||
# #
|
||||
# conf2.property.read_only()
|
||||
# assert conf.value.exportation() == {'creole.general.wantref': {None: [False, 'forced']}}
|
||||
# assert conf2.value.exportation() == {'creole.general.wantref': {None: [False, 'forced']}}
|
||||
# #
|
||||
# conf.option('creole.general.wantref').value.set(True)
|
||||
# assert conf.value.exportation() == {'creole.general.wantref': {None: [True, 'user']}}
|
||||
# assert conf2.value.exportation() == {'creole.general.wantref': {None: [False, 'forced']}}
|
||||
## assert not list_sessions()
|
||||
#
|
||||
#
|
||||
#def test_copy_force_store_value_metaconfig():
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -160,57 +160,57 @@ def test_freeze_multi():
|
|||
# assert not list_sessions()
|
||||
|
||||
|
||||
def test_force_store_value():
|
||||
od1 = make_description_freeze()
|
||||
cfg = Config(od1)
|
||||
compare(cfg.value.exportation(), {})
|
||||
cfg.property.read_write()
|
||||
compare(cfg.value.exportation(), {'wantref': {None: [False, 'forced']}, 'wantref2': {None: [False, 'forced']}, 'wantref3': {None: [[False], 'forced']}})
|
||||
cfg.option('bool').value.set(False)
|
||||
cfg.option('wantref').value.set(True)
|
||||
cfg.option('bool').value.reset()
|
||||
compare(cfg.value.exportation(), {'wantref': {None: [True, 'user']}, 'wantref2': {None: [False, 'forced']}, 'wantref3': {None: [[False], 'forced']}})
|
||||
cfg.option('bool').value.set(False)
|
||||
cfg.option('wantref').value.reset()
|
||||
cfg.option('bool').value.reset()
|
||||
compare(cfg.value.exportation(), {'wantref': {None: [False, 'forced']}, 'wantref2': {None: [False, 'forced']}, 'wantref3': {None: [[False], 'forced']}})
|
||||
# assert not list_sessions()
|
||||
|
||||
|
||||
def test_force_store_value_leadership_sub():
|
||||
b = IntOption('int', 'Test int option', multi=True, properties=('force_store_value',))
|
||||
c = StrOption('str', 'Test string option', multi=True)
|
||||
descr = Leadership("int", "", [b, c])
|
||||
od1 = OptionDescription('odr', '', [descr])
|
||||
cfg = Config(od1)
|
||||
cfg.property.read_only()
|
||||
compare(cfg.value.exportation(), {'int.int': {None: [[], 'forced']}})
|
||||
# assert not list_sessions()
|
||||
|
||||
|
||||
def test_force_store_value_callback():
|
||||
b = IntOption('int', 'Test int option', Calculation(return_val), properties=('force_store_value',))
|
||||
od1 = OptionDescription("int", "", [b])
|
||||
cfg = Config(od1)
|
||||
cfg.property.read_only()
|
||||
compare(cfg.value.exportation(), {'int': {None: [1, 'forced']}})
|
||||
# assert not list_sessions()
|
||||
|
||||
|
||||
def test_force_store_value_callback_params():
|
||||
b = IntOption('int', 'Test int option', Calculation(return_val2, Params(kwargs={'value': ParamValue(2)})), properties=('force_store_value',))
|
||||
od1 = OptionDescription("int", "", [b])
|
||||
cfg = Config(od1)
|
||||
cfg.property.read_only()
|
||||
compare(cfg.value.exportation(), {'int': {None: [2, 'forced']}})
|
||||
# assert not list_sessions()
|
||||
|
||||
|
||||
def test_force_store_value_callback_params_with_opt():
|
||||
a = IntOption('val1', "", 2)
|
||||
b = IntOption('int', 'Test int option', Calculation(return_val2, Params(kwargs={'value': ParamOption(a)})), properties=('force_store_value',))
|
||||
od1 = OptionDescription("int", "", [a, b])
|
||||
cfg = Config(od1)
|
||||
cfg.property.read_only()
|
||||
compare(cfg.value.exportation(), {'int': {None: [2, 'forced']}})
|
||||
# assert not list_sessions()
|
||||
#def test_force_store_value():
|
||||
# od1 = make_description_freeze()
|
||||
# cfg = Config(od1)
|
||||
# compare(cfg.value.exportation(), {})
|
||||
# cfg.property.read_write()
|
||||
# compare(cfg.value.exportation(), {'wantref': {None: [False, 'forced']}, 'wantref2': {None: [False, 'forced']}, 'wantref3': {None: [[False], 'forced']}})
|
||||
# cfg.option('bool').value.set(False)
|
||||
# cfg.option('wantref').value.set(True)
|
||||
# cfg.option('bool').value.reset()
|
||||
# compare(cfg.value.exportation(), {'wantref': {None: [True, 'user']}, 'wantref2': {None: [False, 'forced']}, 'wantref3': {None: [[False], 'forced']}})
|
||||
# cfg.option('bool').value.set(False)
|
||||
# cfg.option('wantref').value.reset()
|
||||
# cfg.option('bool').value.reset()
|
||||
# compare(cfg.value.exportation(), {'wantref': {None: [False, 'forced']}, 'wantref2': {None: [False, 'forced']}, 'wantref3': {None: [[False], 'forced']}})
|
||||
## assert not list_sessions()
|
||||
#
|
||||
#
|
||||
#def test_force_store_value_leadership_sub():
|
||||
# b = IntOption('int', 'Test int option', multi=True, properties=('force_store_value',))
|
||||
# c = StrOption('str', 'Test string option', multi=True)
|
||||
# descr = Leadership("int", "", [b, c])
|
||||
# od1 = OptionDescription('odr', '', [descr])
|
||||
# cfg = Config(od1)
|
||||
# cfg.property.read_only()
|
||||
# compare(cfg.value.exportation(), {'int.int': {None: [[], 'forced']}})
|
||||
## assert not list_sessions()
|
||||
#
|
||||
#
|
||||
#def test_force_store_value_callback():
|
||||
# b = IntOption('int', 'Test int option', Calculation(return_val), properties=('force_store_value',))
|
||||
# od1 = OptionDescription("int", "", [b])
|
||||
# cfg = Config(od1)
|
||||
# cfg.property.read_only()
|
||||
# compare(cfg.value.exportation(), {'int': {None: [1, 'forced']}})
|
||||
## assert not list_sessions()
|
||||
#
|
||||
#
|
||||
#def test_force_store_value_callback_params():
|
||||
# b = IntOption('int', 'Test int option', Calculation(return_val2, Params(kwargs={'value': ParamValue(2)})), properties=('force_store_value',))
|
||||
# od1 = OptionDescription("int", "", [b])
|
||||
# cfg = Config(od1)
|
||||
# cfg.property.read_only()
|
||||
# compare(cfg.value.exportation(), {'int': {None: [2, 'forced']}})
|
||||
## assert not list_sessions()
|
||||
#
|
||||
#
|
||||
#def test_force_store_value_callback_params_with_opt():
|
||||
# a = IntOption('val1', "", 2)
|
||||
# b = IntOption('int', 'Test int option', Calculation(return_val2, Params(kwargs={'value': ParamOption(a)})), properties=('force_store_value',))
|
||||
# od1 = OptionDescription("int", "", [a, b])
|
||||
# cfg = Config(od1)
|
||||
# cfg.property.read_only()
|
||||
# compare(cfg.value.exportation(), {'int': {None: [2, 'forced']}})
|
||||
## assert not list_sessions()
|
||||
|
|
|
@ -159,7 +159,7 @@ def test_iter_on_empty_group():
|
|||
od1 = OptionDescription("name", "descr", [])
|
||||
cfg = Config(od1)
|
||||
cfg.property.read_write()
|
||||
result = list(cfg.list())
|
||||
result = list(cfg.option.list())
|
||||
assert result == []
|
||||
# assert not list_sessions()
|
||||
|
||||
|
@ -194,7 +194,7 @@ def test_groups_is_leader(config_type):
|
|||
assert not cfg.option('leadership.netmask_admin_eth0').isleader()
|
||||
assert cfg.option('leadership.netmask_admin_eth0').isfollower()
|
||||
assert cfg.option('leadership.netmask_admin_eth0').path() == 'leadership.netmask_admin_eth0'
|
||||
assert cfg.option('leadership.netmask_admin_eth0').value.defaultmulti() == 'value'
|
||||
assert cfg.option('leadership.netmask_admin_eth0').defaultmulti() == 'value'
|
||||
if config_type == 'tiramisu-api':
|
||||
cfg.send()
|
||||
# assert not list_sessions()
|
||||
|
@ -207,7 +207,7 @@ def test_leader_list(config_type):
|
|||
od1 = OptionDescription('od', '', [interface1])
|
||||
cfg = Config(od1)
|
||||
cfg = get_config(cfg, config_type)
|
||||
ret = cfg.list()
|
||||
ret = cfg.option.list()
|
||||
assert len(ret) == 1
|
||||
assert ret[0].name() == 'leadership'
|
||||
#
|
||||
|
@ -983,65 +983,65 @@ def test_follower_not_multi():
|
|||
# assert not list_sessions()
|
||||
|
||||
|
||||
def test_follower_force_store_value_none():
|
||||
ip_admin_eth0 = IPOption('ip_admin_eth0', "ip réseau autorisé", multi=True, default=['1.1.1.1'])
|
||||
netmask_admin_eth0 = NetmaskOption('netmask_admin_eth0', "masque du sous-réseau", multi=True, properties=('force_store_value',))
|
||||
interface0 = Leadership('interface0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||
od1 = OptionDescription('od', '', [interface0])
|
||||
od2 = OptionDescription('toto', '', [od1])
|
||||
cfg = Config(od2)
|
||||
cfg.property.read_write()
|
||||
assert cfg.option('od.interface0.netmask_admin_eth0', 0).owner.isdefault()
|
||||
# assert not list_sessions()
|
||||
|
||||
|
||||
def test_follower_force_store_value():
|
||||
ip_admin_eth0 = IPOption('ip_admin_eth0', "ip réseau autorisé", multi=True, default=['1.1.1.1'])
|
||||
netmask_admin_eth0 = NetmaskOption('netmask_admin_eth0', "masque du sous-réseau", default_multi='255.255.255.0', multi=True, properties=('force_store_value',))
|
||||
interface0 = Leadership('interface0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||
od1 = OptionDescription('od', '', [interface0])
|
||||
od2 = OptionDescription('toto', '', [od1])
|
||||
cfg = Config(od2)
|
||||
cfg.property.read_write()
|
||||
assert not cfg.option('od.interface0.netmask_admin_eth0', 0).owner.isdefault()
|
||||
# assert not list_sessions()
|
||||
|
||||
|
||||
def test_follower_force_store_value_read_only():
|
||||
ip_admin_eth0 = IPOption('ip_admin_eth0', "ip réseau autorisé", multi=True, default=['1.1.1.1'])
|
||||
netmask_admin_eth0 = NetmaskOption('netmask_admin_eth0', "masque du sous-réseau", default_multi='255.255.255.0', multi=True, properties=('force_store_value',))
|
||||
interface0 = Leadership('interface0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||
od1 = OptionDescription('od', '', [interface0])
|
||||
od2 = OptionDescription('toto', '', [od1])
|
||||
cfg = Config(od2)
|
||||
cfg.property.read_only()
|
||||
assert not cfg.option('od.interface0.netmask_admin_eth0', 0).owner.isdefault()
|
||||
# assert not list_sessions()
|
||||
|
||||
|
||||
def test_follower_force_store_value_reset():
|
||||
ip_admin_eth0 = IPOption('ip_admin_eth0', "ip réseau autorisé", multi=True, default=['1.1.1.1'])
|
||||
netmask_admin_eth0 = NetmaskOption('netmask_admin_eth0', "masque du sous-réseau", default_multi='255.255.255.0', multi=True, properties=('force_store_value',))
|
||||
interface0 = Leadership('interface0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||
od1 = OptionDescription('od', '', [interface0])
|
||||
od2 = OptionDescription('toto', '', [od1])
|
||||
cfg = Config(od2)
|
||||
cfg.property.read_write()
|
||||
cfg.option('od.interface0.ip_admin_eth0').value.set(['1.1.1.1', '192.168.0.0'])
|
||||
assert not cfg.option('od.interface0.netmask_admin_eth0', 0).owner.isdefault()
|
||||
assert not cfg.option('od.interface0.netmask_admin_eth0', 1).owner.isdefault()
|
||||
#
|
||||
cfg.option('od.interface0.netmask_admin_eth0', 1).value.reset()
|
||||
assert not cfg.option('od.interface0.netmask_admin_eth0', 1).owner.isdefault()
|
||||
#
|
||||
cfg.option('od.interface0.ip_admin_eth0').value.pop(0)
|
||||
cfg.option('od.interface0.ip_admin_eth0').value.pop(0)
|
||||
assert cfg.option('od.interface0.ip_admin_eth0').value.get() == []
|
||||
cfg.option('od.interface0.ip_admin_eth0').value.reset()
|
||||
assert not cfg.option('od.interface0.netmask_admin_eth0', 0).owner.isdefault()
|
||||
# assert not list_sessions()
|
||||
|
||||
|
||||
#def test_follower_force_store_value_none():
|
||||
# ip_admin_eth0 = IPOption('ip_admin_eth0', "ip réseau autorisé", multi=True, default=['1.1.1.1'])
|
||||
# netmask_admin_eth0 = NetmaskOption('netmask_admin_eth0', "masque du sous-réseau", multi=True, properties=('force_store_value',))
|
||||
# interface0 = Leadership('interface0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||
# od1 = OptionDescription('od', '', [interface0])
|
||||
# od2 = OptionDescription('toto', '', [od1])
|
||||
# cfg = Config(od2)
|
||||
# cfg.property.read_write()
|
||||
# assert cfg.option('od.interface0.netmask_admin_eth0', 0).owner.isdefault()
|
||||
## assert not list_sessions()
|
||||
#
|
||||
#
|
||||
#def test_follower_force_store_value():
|
||||
# ip_admin_eth0 = IPOption('ip_admin_eth0', "ip réseau autorisé", multi=True, default=['1.1.1.1'])
|
||||
# netmask_admin_eth0 = NetmaskOption('netmask_admin_eth0', "masque du sous-réseau", default_multi='255.255.255.0', multi=True, properties=('force_store_value',))
|
||||
# interface0 = Leadership('interface0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||
# od1 = OptionDescription('od', '', [interface0])
|
||||
# od2 = OptionDescription('toto', '', [od1])
|
||||
# cfg = Config(od2)
|
||||
# cfg.property.read_write()
|
||||
# assert not cfg.option('od.interface0.netmask_admin_eth0', 0).owner.isdefault()
|
||||
## assert not list_sessions()
|
||||
#
|
||||
#
|
||||
#def test_follower_force_store_value_read_only():
|
||||
# ip_admin_eth0 = IPOption('ip_admin_eth0', "ip réseau autorisé", multi=True, default=['1.1.1.1'])
|
||||
# netmask_admin_eth0 = NetmaskOption('netmask_admin_eth0', "masque du sous-réseau", default_multi='255.255.255.0', multi=True, properties=('force_store_value',))
|
||||
# interface0 = Leadership('interface0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||
# od1 = OptionDescription('od', '', [interface0])
|
||||
# od2 = OptionDescription('toto', '', [od1])
|
||||
# cfg = Config(od2)
|
||||
# cfg.property.read_only()
|
||||
# assert not cfg.option('od.interface0.netmask_admin_eth0', 0).owner.isdefault()
|
||||
## assert not list_sessions()
|
||||
#
|
||||
#
|
||||
#def test_follower_force_store_value_reset():
|
||||
# ip_admin_eth0 = IPOption('ip_admin_eth0', "ip réseau autorisé", multi=True, default=['1.1.1.1'])
|
||||
# netmask_admin_eth0 = NetmaskOption('netmask_admin_eth0', "masque du sous-réseau", default_multi='255.255.255.0', multi=True, properties=('force_store_value',))
|
||||
# interface0 = Leadership('interface0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||
# od1 = OptionDescription('od', '', [interface0])
|
||||
# od2 = OptionDescription('toto', '', [od1])
|
||||
# cfg = Config(od2)
|
||||
# cfg.property.read_write()
|
||||
# cfg.option('od.interface0.ip_admin_eth0').value.set(['1.1.1.1', '192.168.0.0'])
|
||||
# assert not cfg.option('od.interface0.netmask_admin_eth0', 0).owner.isdefault()
|
||||
# assert not cfg.option('od.interface0.netmask_admin_eth0', 1).owner.isdefault()
|
||||
# #
|
||||
# cfg.option('od.interface0.netmask_admin_eth0', 1).value.reset()
|
||||
# assert not cfg.option('od.interface0.netmask_admin_eth0', 1).owner.isdefault()
|
||||
# #
|
||||
# cfg.option('od.interface0.ip_admin_eth0').value.pop(0)
|
||||
# cfg.option('od.interface0.ip_admin_eth0').value.pop(0)
|
||||
# assert cfg.option('od.interface0.ip_admin_eth0').value.get() == []
|
||||
# cfg.option('od.interface0.ip_admin_eth0').value.reset()
|
||||
# assert not cfg.option('od.interface0.netmask_admin_eth0', 0).owner.isdefault()
|
||||
## assert not list_sessions()
|
||||
#
|
||||
#
|
||||
#def test_follower_properties():
|
||||
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
|
||||
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True, properties=('aproperty',))
|
||||
|
|
|
@ -681,7 +681,7 @@ def test_mandatory_od_disabled():
|
|||
# assert not list_sessions()
|
||||
|
||||
|
||||
def return_list(val=None, identifier=None):
|
||||
def return_list(val=None, suffix=None):
|
||||
if val:
|
||||
return val
|
||||
else:
|
||||
|
@ -690,7 +690,7 @@ def return_list(val=None, identifier=None):
|
|||
|
||||
#def test_mandatory_dyndescription():
|
||||
# st = StrOption('st', '', properties=('mandatory',))
|
||||
# dod = DynOptionDescription('dod', '', [st], identifiers=Calculation(return_list))
|
||||
# dod = DynOptionDescription('dod', '', [st], suffixes=Calculation(return_list))
|
||||
# od = OptionDescription('od', '', [dod])
|
||||
# od2 = OptionDescription('od', '', [od])
|
||||
# cfg = Config(od2)
|
||||
|
@ -701,7 +701,7 @@ def return_list(val=None, identifier=None):
|
|||
#def test_mandatory_dyndescription_context():
|
||||
# val1 = StrOption('val1', '', ['val1', 'val2'], multi=True)
|
||||
# st = StrOption('st', '', properties=('mandatory',))
|
||||
# dod = DynOptionDescription('dod', '', [st], identifiers=Calculation(return_list, Params(ParamOption(val1))))
|
||||
# dod = DynOptionDescription('dod', '', [st], suffixes=Calculation(return_list, Params(ParamOption(val1))))
|
||||
# od = OptionDescription('od', '', [dod, val1])
|
||||
# od2 = OptionDescription('od', '', [od])
|
||||
# cfg = Config(od2)
|
||||
|
|
|
@ -20,7 +20,7 @@ def a_func():
|
|||
return None
|
||||
|
||||
|
||||
def display_name(*args, with_quote=False):
|
||||
def display_name(*args):
|
||||
return 'display_name'
|
||||
|
||||
|
||||
|
@ -34,6 +34,20 @@ def test_option_valid_name():
|
|||
i = SymLinkOption("test1", i)
|
||||
|
||||
|
||||
def test_option_get_information():
|
||||
description = "it's ok"
|
||||
string = 'some informations'
|
||||
i = IntOption('test', description)
|
||||
with pytest.raises(ValueError):
|
||||
i.impl_get_information('noinfo')
|
||||
i.impl_set_information('info', string)
|
||||
assert i.impl_get_information('info') == string
|
||||
with pytest.raises(ValueError):
|
||||
i.impl_get_information('noinfo')
|
||||
assert i.impl_get_information('noinfo', 'default') == 'default'
|
||||
assert i.impl_get_information('doc') == description
|
||||
|
||||
|
||||
def test_option_get_information_config():
|
||||
description = "it's ok"
|
||||
string = 'some informations'
|
||||
|
@ -41,16 +55,21 @@ def test_option_get_information_config():
|
|||
od = OptionDescription('od', '', [i])
|
||||
cfg = Config(od)
|
||||
with pytest.raises(ValueError):
|
||||
cfg.option('test').information.get('noinfo')
|
||||
assert cfg.option('test').information.get('noinfo', 'default') == 'default'
|
||||
assert cfg.option('test').information.get('doc') == description
|
||||
i.impl_get_information('noinfo')
|
||||
with pytest.raises(AttributeError):
|
||||
i.impl_set_information('info', string)
|
||||
with pytest.raises(ValueError):
|
||||
i.impl_get_information('noinfo')
|
||||
assert i.impl_get_information('noinfo', 'default') == 'default'
|
||||
assert i.impl_get_information('doc') == description
|
||||
# assert not list_sessions()
|
||||
|
||||
|
||||
def test_option_unknown():
|
||||
description = "it's ok"
|
||||
string = 'some informations'
|
||||
i = IntOption('test', description, informations={'noinfo': 'optdefault'})
|
||||
i = IntOption('test', description)
|
||||
i.impl_set_information('noinfo', 'optdefault')
|
||||
od = OptionDescription('od', '', [i])
|
||||
cfg = Config(od)
|
||||
#
|
||||
|
@ -74,7 +93,8 @@ def test_option_description():
|
|||
def test_option_get_information_default():
|
||||
description = "it's ok"
|
||||
string = 'some informations'
|
||||
i = IntOption('test', description, informations={'noinfo': 'optdefault'})
|
||||
i = IntOption('test', description)
|
||||
i.impl_set_information('noinfo', 'optdefault')
|
||||
od = OptionDescription('od', '', [i])
|
||||
cfg = Config(od)
|
||||
#
|
||||
|
@ -88,30 +108,32 @@ def test_option_get_information_default():
|
|||
def test_option_get_information_config2():
|
||||
description = "it's ok"
|
||||
string = 'some informations'
|
||||
i = IntOption('test', description, informations={'info': string})
|
||||
i = IntOption('test', description)
|
||||
i.impl_set_information('info', string)
|
||||
od = OptionDescription('od', '', [i])
|
||||
cfg = Config(od)
|
||||
with pytest.raises(ValueError):
|
||||
cfg.option('test').information.get('noinfo')
|
||||
assert cfg.option('test').information.get('info') == string
|
||||
i.impl_get_information('noinfo')
|
||||
with pytest.raises(AttributeError):
|
||||
i.impl_set_information('info', 'hello')
|
||||
assert i.impl_get_information('info') == string
|
||||
with pytest.raises(ValueError):
|
||||
cfg.option('test').information.get('noinfo')
|
||||
assert cfg.option('test').information.get('noinfo', 'default') == 'default'
|
||||
assert cfg.option('test').information.get('doc') == description
|
||||
i.impl_get_information('noinfo')
|
||||
assert i.impl_get_information('noinfo', 'default') == 'default'
|
||||
assert i.impl_get_information('doc') == description
|
||||
# assert not list_sessions()
|
||||
|
||||
|
||||
def test_optiondescription_get_information():
|
||||
description = "it's ok"
|
||||
string = 'some informations'
|
||||
o = OptionDescription('test', description, [], informations={'info': string})
|
||||
od = OptionDescription('od', '', [o])
|
||||
cfg = Config(od)
|
||||
assert cfg.option('test').information.get('info') == string
|
||||
o = OptionDescription('test', description, [])
|
||||
o.impl_set_information('info', string)
|
||||
assert o.impl_get_information('info') == string
|
||||
with pytest.raises(ValueError):
|
||||
cfg.option('test').information.get('noinfo')
|
||||
assert cfg.option('test').information.get('noinfo', 'default') == 'default'
|
||||
assert cfg.option('test').information.get('doc') == description
|
||||
o.impl_get_information('noinfo')
|
||||
assert o.impl_get_information('noinfo', 'default') == 'default'
|
||||
assert o.impl_get_information('doc') == description
|
||||
# assert not list_sessions()
|
||||
|
||||
|
||||
|
@ -196,7 +218,7 @@ def test_optiondescription_group():
|
|||
od3.impl_set_group_type(groups.notfamily)
|
||||
od2 = OptionDescription('od', '', [od1, od3])
|
||||
cfg = Config(od2)
|
||||
assert len(list(cfg.list())) == 2
|
||||
assert len(list(cfg.option.list())) == 2
|
||||
# assert not list_sessions()
|
||||
|
||||
|
||||
|
@ -299,4 +321,4 @@ def test_option_display_name():
|
|||
display_name=display_name,
|
||||
)
|
||||
assert cfg.option('test1').name() == 'test1'
|
||||
assert cfg.option('test1').description() == 'display_name'
|
||||
assert cfg.option('test1').doc() == 'display_name'
|
||||
|
|
|
@ -289,12 +289,11 @@ def test_callback(config_type):
|
|||
cfg = Config(od1)
|
||||
cfg.property.read_write()
|
||||
cfg = get_config(cfg, config_type)
|
||||
assert isinstance(cfg.option('val1').value.get(uncalculated=True), Calculation)
|
||||
assert cfg.option('val1').value.get() == 'val'
|
||||
cfg.option('val1').value.set('new-val')
|
||||
assert cfg.option('val1').value.get() == 'new-val'
|
||||
with pytest.raises(ConfigError):
|
||||
assert cfg.option('val1').value.defaultmulti() == None
|
||||
assert cfg.option('val1').defaultmulti() == None
|
||||
cfg.option('val1').value.reset()
|
||||
assert cfg.option('val1').value.get() == 'val'
|
||||
# assert not list_sessions()
|
||||
|
@ -416,7 +415,8 @@ def test_callback_information(config_type):
|
|||
|
||||
def test_callback_information2(config_type):
|
||||
val1 = StrOption('val1', "", Calculation(return_value, Params(ParamSelfInformation('information', 'no_value'))))
|
||||
val2 = StrOption('val2', "", Calculation(return_value, Params(ParamSelfInformation('information'))), informations={'information': 'new_value'})
|
||||
val2 = StrOption('val2', "", Calculation(return_value, Params(ParamSelfInformation('information'))))
|
||||
val2.impl_set_information('information', 'new_value')
|
||||
val3 = StrOption('val3', "", Calculation(return_value, Params(ParamSelfInformation('information'))))
|
||||
od1 = OptionDescription('rootconfig', '', [val1, val2, val3])
|
||||
cfg = Config(od1)
|
||||
|
@ -432,8 +432,9 @@ def test_callback_information2(config_type):
|
|||
|
||||
|
||||
def test_callback_information3(config_type):
|
||||
val1 = StrOption('val1', "", informations={'information': 'new_value'})
|
||||
val1 = StrOption('val1', "")
|
||||
val2 = StrOption('val2', "", Calculation(return_value, Params(ParamInformation('information', option=val1))))
|
||||
val1.impl_set_information('information', 'new_value')
|
||||
od1 = OptionDescription('rootconfig', '', [val1, val2])
|
||||
cfg = Config(od1)
|
||||
cfg.property.read_write()
|
||||
|
@ -548,7 +549,7 @@ def test_callback_multi(config_type):
|
|||
cfg = get_config(cfg, config_type)
|
||||
assert cfg.option('val1').value.get() == ['val']
|
||||
cfg.option('val1').value.set(['new-val'])
|
||||
assert cfg.option('val1').value.defaultmulti() == None
|
||||
assert cfg.option('val1').defaultmulti() == None
|
||||
assert cfg.option('val1').value.get() == ['new-val']
|
||||
cfg.option('val1').value.set(['new-val', 'new-val2'])
|
||||
assert cfg.option('val1').value.get() == ['new-val', 'new-val2']
|
||||
|
@ -945,7 +946,7 @@ def test_consistency_leader_and_followers_leader_mandatory_transitive():
|
|||
try:
|
||||
cfg.option('val1.val2', 0).value.get()
|
||||
except PropertiesOptionError as error:
|
||||
assert str(error) == str(_('cannot access to {0} {1} because has {2} {3}').format('option', '"val2"', _('property'), '"disabled"'))
|
||||
assert str(error) == str(_('cannot access to {0} "{1}" because has {2} {3}').format('option', 'val2', _('property'), '"disabled"'))
|
||||
else:
|
||||
raise Exception('must raises')
|
||||
assert list(cfg.value.mandatory()) == []
|
||||
|
@ -963,7 +964,7 @@ def test_callback_leader_and_followers_leader_list(config_type):
|
|||
assert cfg.option('val1.val1').value.get() == ['val', 'val']
|
||||
assert cfg.option('val1.val2', 0).value.get() == None
|
||||
assert cfg.option('val1.val2', 1).value.get() == None
|
||||
default_multi = cfg.option('val1.val1').value.defaultmulti()
|
||||
default_multi = cfg.option('val1.val1').defaultmulti()
|
||||
cfg.option('val1.val1').value.set(['val', 'val', default_multi])
|
||||
assert cfg.option('val1.val1').value.get() == ['val', 'val', None]
|
||||
assert cfg.option('val1.val2', 0).value.get() == None
|
||||
|
@ -1502,22 +1503,6 @@ def test_leadership_callback_description(config_type):
|
|||
# assert not list_sessions()
|
||||
|
||||
|
||||
def test_leadership_callback_outside(config_type):
|
||||
st1 = StrOption('st1', "", multi=True)
|
||||
st2 = StrOption('st2', "", multi=True, default_multi='val2')
|
||||
stm = Leadership('st1', '', [st1, st2])
|
||||
st3 = StrOption('st3', "", Calculation(return_value, Params(ParamOption(st2))), multi=True)
|
||||
st = OptionDescription('st', '', [stm, st3])
|
||||
od = OptionDescription('od', '', [st])
|
||||
od2 = OptionDescription('od', '', [od])
|
||||
cfg = Config(od2)
|
||||
cfg = get_config(cfg, config_type)
|
||||
owner = cfg.owner.get()
|
||||
cfg.option('od.st.st1.st1').value.set(['yes'])
|
||||
assert parse_od_get(cfg.value.get()) == {'od.st.st1.st1': [{'od.st.st1.st1': 'yes', 'od.st.st1.st2': 'val2'}], 'od.st.st3': ['val2']}
|
||||
## assert not list_sessions()
|
||||
|
||||
|
||||
def test_callback_raise():
|
||||
opt1 = BoolOption('opt1', 'Option 1', Calculation(return_raise))
|
||||
opt2 = BoolOption('opt2', 'Option 2', Calculation(return_valueerror))
|
||||
|
@ -1706,38 +1691,3 @@ def test_calc_dependencies(config_type):
|
|||
def test_callback__kwargs_wrong(config_type):
|
||||
with pytest.raises(ValueError):
|
||||
Params(kwargs='string')
|
||||
|
||||
|
||||
def test_callback_information_parent(config_type):
|
||||
information = ParamInformation('information')
|
||||
val1 = StrOption('val1', "", Calculation(return_value, Params(information)))
|
||||
od2 = OptionDescription('od', '', [val1], informations={'information': 'new_value'})
|
||||
information.set_option(od2)
|
||||
od1 = OptionDescription('rootconfig', '', [od2])
|
||||
cfg = Config(od1)
|
||||
cfg.property.read_write()
|
||||
cfg = get_config(cfg, config_type)
|
||||
assert cfg.option('od.val1').value.get() == 'new_value'
|
||||
cfg.option('od').information.set('information', 'new_value2')
|
||||
assert cfg.option('od.val1').value.get() == 'new_value2'
|
||||
|
||||
|
||||
def test_callback_information_redefined(config_type):
|
||||
val1 = StrOption('val1', "")
|
||||
information = ParamInformation('information', option=val1)
|
||||
val2 = StrOption('val2', "", Calculation(return_value, Params(information)))
|
||||
od2 = OptionDescription('od', '', [val1, val2], informations={'information': 'new_value'})
|
||||
with pytest.raises(ConfigError):
|
||||
information.set_option(od2)
|
||||
|
||||
|
||||
def test_callback_information_redefined_after(config_type):
|
||||
information = ParamInformation('information')
|
||||
val1 = StrOption('val1', "", Calculation(return_value, Params(information)))
|
||||
od2 = OptionDescription('od', '', [val1], informations={'information': 'new_value'})
|
||||
od1 = OptionDescription('rootconfig', '', [od2])
|
||||
cfg = Config(od1)
|
||||
cfg.property.read_write()
|
||||
cfg = get_config(cfg, config_type)
|
||||
with pytest.raises(ConfigError):
|
||||
information.set_option(od2)
|
||||
|
|
|
@ -166,6 +166,28 @@ def test_force_default_on_freeze_multi():
|
|||
# assert not list_sessions()
|
||||
|
||||
|
||||
def test_force_default_on_freeze_leader_frozen():
|
||||
dummy1 = BoolOption('dummy1', 'Test int option', multi=True, properties=('force_default_on_freeze', 'frozen'))
|
||||
dummy2 = BoolOption('dummy2', 'Test string option', multi=True)
|
||||
descr = Leadership("dummy1", "", [dummy1, dummy2])
|
||||
od1 = OptionDescription("root", "", [descr])
|
||||
cfg = Config(od1)
|
||||
with pytest.raises(LeadershipError):
|
||||
cfg.option('dummy1.dummy1').property.remove('frozen')
|
||||
# assert not list_sessions()
|
||||
|
||||
|
||||
def test_force_metaconfig_on_freeze_leader_frozen():
|
||||
dummy1 = BoolOption('dummy1', 'Test int option', multi=True, properties=('force_metaconfig_on_freeze', 'frozen'))
|
||||
dummy2 = BoolOption('dummy2', 'Test string option', multi=True)
|
||||
descr = Leadership("dummy1", "", [dummy1, dummy2])
|
||||
od1 = OptionDescription("root", "", [descr])
|
||||
cfg = Config(od1)
|
||||
with pytest.raises(LeadershipError):
|
||||
cfg.option('dummy1.dummy1').property.remove('frozen')
|
||||
# assert not list_sessions()
|
||||
|
||||
|
||||
def test_force_default_on_freeze_follower(config_type):
|
||||
dummy1 = BoolOption('dummy1', 'Test int option', multi=True, properties=('notunique',))
|
||||
dummy2 = BoolOption('dummy2', 'Test string option', multi=True, properties=('force_default_on_freeze',))
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
""" RegexpOption
|
||||
"""
|
||||
from .autopath import do_autopath
|
||||
do_autopath()
|
||||
|
||||
import pytest
|
||||
from tiramisu import RegexpOption, OptionDescription, Config
|
||||
import re
|
||||
|
||||
|
||||
class ColorOption(RegexpOption):
|
||||
__slots__ = tuple()
|
||||
_type = 'Color'
|
||||
_regexp = re.compile(r"^#(?:[0-9a-f]{3}){1,2}$")
|
||||
|
||||
|
||||
def test_regexp_option():
|
||||
r = ColorOption('test', 'test')
|
||||
od = OptionDescription('od', 'od', [r])
|
||||
cfg = Config(od)
|
||||
cfg.option('test').value.set('#ff0000')
|
||||
with pytest.raises(ValueError):
|
||||
cfg.option('test').value.set('not a color')
|
|
@ -82,7 +82,7 @@ def test_mod_read_only_write():
|
|||
'empty',
|
||||
}
|
||||
#
|
||||
# config.property.setdefault(frozenset(['cache']))
|
||||
config.property.setdefault(frozenset(['cache']))
|
||||
config.property.setdefault(type='read_only', when='append', properties=frozenset(['disabled']))
|
||||
config.property.setdefault(type='read_only', when='remove', properties=frozenset(['hidden']))
|
||||
config.property.setdefault(type='read_write', when='append', properties=frozenset(['disabled', 'hidden']))
|
||||
|
@ -94,7 +94,7 @@ def test_mod_read_only_write():
|
|||
with pytest.raises(TypeError):
|
||||
config.property.setdefault(type='read_only', when='append', properties=['disabled'])
|
||||
|
||||
assert config.property.default() == {'warnings', 'validator', 'cache'}
|
||||
assert config.property.default() == {'cache'}
|
||||
assert config.property.default('read_only', 'append') == {'disabled'}
|
||||
assert config.property.default('read_only', 'remove') == {'hidden'}
|
||||
assert config.property.default('read_write', 'append') == {'disabled',
|
||||
|
@ -102,11 +102,11 @@ def test_mod_read_only_write():
|
|||
assert config.property.default('read_write', 'remove') == set([])
|
||||
#
|
||||
config.property.read_only()
|
||||
assert config.property.get() == {'warnings', 'validator', 'cache', 'disabled'}
|
||||
assert config.property.get() == {'cache', 'disabled'}
|
||||
config.property.read_write()
|
||||
assert config.property.get() == {'warnings', 'validator', 'cache', 'disabled', 'hidden'}
|
||||
assert config.property.get() == {'cache', 'disabled', 'hidden'}
|
||||
config.property.read_only()
|
||||
assert config.property.get() == {'warnings', 'validator', 'cache', 'disabled'}
|
||||
assert config.property.get() == {'cache', 'disabled'}
|
||||
#
|
||||
assert config2.property.default() == {'cache', 'validator', 'warnings'}
|
||||
assert config2.property.default('read_only', 'append') == {'frozen',
|
||||
|
@ -138,19 +138,6 @@ def test_mod_read_only_write():
|
|||
# assert not list_sessions()
|
||||
|
||||
|
||||
def test_setting_tree(config_type):
|
||||
s = StrOption("string", "", default=["string", "sdfsdf"], default_multi="prout", multi=True)
|
||||
od4 = OptionDescription("option4", "", [s])
|
||||
od3 = OptionDescription("option3", "", [od4])
|
||||
od2 = OptionDescription("option2", "", [od3], properties=('hidden',))
|
||||
od1 = OptionDescription("root", "", [od2])
|
||||
cfg = Config(od1)
|
||||
cfg = get_config(cfg, config_type)
|
||||
cfg.property.read_write()
|
||||
with pytest.raises(PropertiesOptionError):
|
||||
cfg.option('option2.option3.option4.string').value.get()
|
||||
|
||||
|
||||
def test_setitem(config_type):
|
||||
s = StrOption("string", "", default=["string", "sdfsdf"], default_multi="prout", multi=True)
|
||||
od1 = OptionDescription("options", "", [s])
|
||||
|
@ -378,7 +365,8 @@ def test_apply_requires_from_config():
|
|||
with pytest.raises(PropertiesOptionError):
|
||||
cfg.option('opt.str').value.get()
|
||||
assert 'hidden' in cfg.forcepermissive.option('opt.str').property.get()
|
||||
assert 'hidden' not in cfg.forcepermissive.option('opt.str').property.get(only_raises=True)
|
||||
assert 'hidden' not in cfg.forcepermissive.option('opt.str').properties()
|
||||
assert 'hidden' not in cfg.forcepermissive.option('opt.str').properties(only_raises=True)
|
||||
# assert not list_sessions()
|
||||
|
||||
|
||||
|
@ -398,7 +386,8 @@ def test_apply_requires_with_disabled():
|
|||
cfg.option('int').value.set(1)
|
||||
with pytest.raises(PropertiesOptionError):
|
||||
cfg.option('opt.str').value.get()
|
||||
assert 'disabled' not in cfg.unrestraint.option('opt.str').property.get(only_raises=True, apply_requires=False)
|
||||
assert 'disabled' not in cfg.unrestraint.option('opt.str').properties()
|
||||
assert 'disabled' not in cfg.unrestraint.option('opt.str').properties(only_raises=True)
|
||||
assert 'disabled' in cfg.unrestraint.option('opt.str').property.get()
|
||||
# assert not list_sessions()
|
||||
|
||||
|
@ -514,10 +503,10 @@ def test_accepts_multiple_changes_from_option():
|
|||
od1 = OptionDescription("options", "", [s])
|
||||
cfg = Config(od1)
|
||||
cfg.option('string').value.set("egg")
|
||||
assert cfg.option('string').value.default() == "string"
|
||||
assert cfg.option('string').default() == "string"
|
||||
assert cfg.option('string').value.get() == "egg"
|
||||
cfg.option('string').value.set('blah')
|
||||
assert cfg.option('string').value.default() == "string"
|
||||
assert cfg.option('string').default() == "string"
|
||||
assert cfg.option('string').value.get() == "blah"
|
||||
cfg.option('string').value.set('bol')
|
||||
assert cfg.option('string').value.get() == 'bol'
|
||||
|
@ -618,7 +607,7 @@ def test_properties_get_add_reset():
|
|||
cfg.property.add('frozen')
|
||||
assert cfg.property.get() == {'validator', 'warnings', 'cache', 'frozen'}
|
||||
cfg.property.reset()
|
||||
assert cfg.property.get() == frozenset()
|
||||
assert cfg.property.get() == {'validator', 'warnings', 'cache'}
|
||||
|
||||
|
||||
def test_reset_properties_force_store_value():
|
||||
|
@ -626,195 +615,28 @@ def test_reset_properties_force_store_value():
|
|||
gcgroup = OptionDescription('gc', '', [gcdummy])
|
||||
od1 = OptionDescription('tiramisu', '', [gcgroup])
|
||||
cfg = Config(od1)
|
||||
assert cfg.property.exportation() == {'properties': {None: {None: frozenset({'cache',
|
||||
'validator',
|
||||
'warnings'})}},
|
||||
'ro_append': frozenset({'disabled',
|
||||
'empty',
|
||||
'everything_frozen',
|
||||
'force_store_value',
|
||||
'frozen',
|
||||
'mandatory',
|
||||
'validator'}),
|
||||
'ro_remove': frozenset({'hidden',
|
||||
'permissive'}),
|
||||
'rw_append': frozenset({'disabled',
|
||||
'force_store_value',
|
||||
'frozen',
|
||||
'hidden',
|
||||
'validator'}),
|
||||
'rw_remove': frozenset({'empty',
|
||||
'everything_frozen',
|
||||
'mandatory',
|
||||
'permissive'}),
|
||||
}
|
||||
|
||||
assert cfg.property.exportation() == {}
|
||||
cfg.property.add('frozen')
|
||||
assert cfg.property.exportation() == \
|
||||
{
|
||||
'properties': {None: {None: frozenset({'cache',
|
||||
'frozen',
|
||||
'validator',
|
||||
'warnings'})}},
|
||||
'ro_append': frozenset({'disabled',
|
||||
'empty',
|
||||
'everything_frozen',
|
||||
'force_store_value',
|
||||
'frozen',
|
||||
'mandatory',
|
||||
'validator'}),
|
||||
'ro_remove': frozenset({'hidden',
|
||||
'permissive'}),
|
||||
'rw_append': frozenset({'disabled',
|
||||
'force_store_value',
|
||||
'frozen',
|
||||
'hidden',
|
||||
'validator'}),
|
||||
'rw_remove': frozenset({'empty',
|
||||
'everything_frozen',
|
||||
'mandatory',
|
||||
'permissive'}),
|
||||
}
|
||||
{None: {None: set(('frozen', 'cache', 'validator', 'warnings'))}}
|
||||
cfg.property.reset()
|
||||
assert cfg.property.exportation() == {'properties': {None: {}},
|
||||
'ro_append': frozenset({'disabled',
|
||||
'empty',
|
||||
'everything_frozen',
|
||||
'force_store_value',
|
||||
'frozen',
|
||||
'mandatory',
|
||||
'validator'}),
|
||||
'ro_remove': frozenset({'hidden',
|
||||
'permissive'}),
|
||||
'rw_append': frozenset({'disabled',
|
||||
'force_store_value',
|
||||
'frozen',
|
||||
'hidden',
|
||||
'validator'}),
|
||||
'rw_remove': frozenset({'empty',
|
||||
'everything_frozen',
|
||||
'mandatory',
|
||||
'permissive'}),
|
||||
}
|
||||
|
||||
assert cfg.property.exportation() == {None: {}}
|
||||
cfg.option('gc.dummy').property.add('test')
|
||||
assert cfg.property.exportation() == {
|
||||
'properties': {None: {},
|
||||
'gc.dummy': {None: frozenset({'test'})}},
|
||||
'ro_append': frozenset({'disabled',
|
||||
'empty',
|
||||
'everything_frozen',
|
||||
'force_store_value',
|
||||
'frozen',
|
||||
'mandatory',
|
||||
'validator'}),
|
||||
'ro_remove': frozenset({'hidden',
|
||||
'permissive'}),
|
||||
'rw_append': frozenset({'disabled',
|
||||
'force_store_value',
|
||||
'frozen',
|
||||
'hidden',
|
||||
'validator'}),
|
||||
'rw_remove': frozenset({'empty',
|
||||
'everything_frozen',
|
||||
'mandatory',
|
||||
'permissive'}),
|
||||
}
|
||||
|
||||
assert cfg.property.exportation() == {None: {}, 'gc.dummy': {None: set(('test', 'force_store_value'))}}
|
||||
cfg.property.reset()
|
||||
assert cfg.property.exportation() == {
|
||||
'properties': {None: {},
|
||||
'gc.dummy': {None: frozenset({'test'})}},
|
||||
'ro_append': frozenset({'disabled',
|
||||
'empty',
|
||||
'everything_frozen',
|
||||
'force_store_value',
|
||||
'frozen',
|
||||
'mandatory',
|
||||
'validator'}),
|
||||
'ro_remove': frozenset({'hidden',
|
||||
'permissive'}),
|
||||
'rw_append': frozenset({'disabled',
|
||||
'force_store_value',
|
||||
'frozen',
|
||||
'hidden',
|
||||
'validator'}),
|
||||
'rw_remove': frozenset({'empty',
|
||||
'everything_frozen',
|
||||
'mandatory',
|
||||
'permissive'}),
|
||||
}
|
||||
|
||||
assert cfg.property.exportation() == {None: {}, 'gc.dummy': {None: set(('test', 'force_store_value'))}}
|
||||
cfg.property.add('frozen')
|
||||
assert cfg.property.exportation() == \
|
||||
{
|
||||
'properties': {None: {None: frozenset({'frozen'})},
|
||||
'gc.dummy': {None: frozenset({'test'})}},
|
||||
'ro_append': frozenset({'disabled',
|
||||
'empty',
|
||||
'everything_frozen',
|
||||
'force_store_value',
|
||||
'frozen',
|
||||
'mandatory',
|
||||
'validator'}),
|
||||
'ro_remove': frozenset({'hidden',
|
||||
'permissive'}),
|
||||
'rw_append': frozenset({'disabled',
|
||||
'force_store_value',
|
||||
'frozen',
|
||||
'hidden',
|
||||
'validator'}),
|
||||
'rw_remove': frozenset({'empty',
|
||||
'everything_frozen',
|
||||
'mandatory',
|
||||
'permissive'}),
|
||||
}
|
||||
{None: {None: set(('frozen', 'validator', 'cache', 'warnings'))},
|
||||
'gc.dummy': {None: set(('test', 'force_store_value'))}}
|
||||
cfg.property.add('frozen')
|
||||
assert cfg.property.exportation() == \
|
||||
{
|
||||
'properties': {None: {None: frozenset({'frozen'})}, 'gc.dummy': {None: frozenset({'test'})}},
|
||||
'ro_append': frozenset({'disabled',
|
||||
'empty',
|
||||
'everything_frozen',
|
||||
'force_store_value',
|
||||
'frozen',
|
||||
'mandatory',
|
||||
'validator'}),
|
||||
'ro_remove': frozenset({'hidden',
|
||||
'permissive'}),
|
||||
'rw_append': frozenset({'disabled',
|
||||
'force_store_value',
|
||||
'frozen',
|
||||
'hidden',
|
||||
'validator'}),
|
||||
'rw_remove': frozenset({'empty',
|
||||
'everything_frozen',
|
||||
'mandatory',
|
||||
'permissive'}),
|
||||
}
|
||||
{None: {None: set(('frozen', 'validator', 'cache', 'warnings'))},
|
||||
'gc.dummy': {None: set(('test', 'force_store_value'))}}
|
||||
cfg.option('gc.dummy').property.add('test')
|
||||
assert cfg.property.exportation() == \
|
||||
{
|
||||
'properties': {None: {None: frozenset({'frozen'})}, 'gc.dummy': {None: frozenset({'test'})}},
|
||||
'ro_append': frozenset({'disabled',
|
||||
'empty',
|
||||
'everything_frozen',
|
||||
'force_store_value',
|
||||
'frozen',
|
||||
'mandatory',
|
||||
'validator'}),
|
||||
'ro_remove': frozenset({'hidden',
|
||||
'permissive'}),
|
||||
'rw_append': frozenset({'disabled',
|
||||
'force_store_value',
|
||||
'frozen',
|
||||
'hidden',
|
||||
'validator'}),
|
||||
'rw_remove': frozenset({'empty',
|
||||
'everything_frozen',
|
||||
'mandatory',
|
||||
'permissive'}),
|
||||
}
|
||||
{None: {None: set(('frozen', 'validator', 'cache', 'warnings'))},
|
||||
'gc.dummy': {None: set(('test', 'force_store_value'))}}
|
||||
# assert not list_sessions()
|
||||
|
||||
|
||||
|
@ -844,79 +666,10 @@ def test_set_modified_value():
|
|||
gcgroup = OptionDescription('gc', '', [gcdummy])
|
||||
od1 = OptionDescription('tiramisu', '', [gcgroup])
|
||||
cfg = Config(od1)
|
||||
assert cfg.property.exportation() == {
|
||||
'properties': {None: {None: frozenset({'cache',
|
||||
'validator',
|
||||
'warnings'})}},
|
||||
'ro_append': frozenset({'disabled',
|
||||
'empty',
|
||||
'everything_frozen',
|
||||
'force_store_value',
|
||||
'frozen',
|
||||
'mandatory',
|
||||
'validator'}),
|
||||
'ro_remove': frozenset({'hidden',
|
||||
'permissive'}),
|
||||
'rw_append': frozenset({'disabled',
|
||||
'force_store_value',
|
||||
'frozen',
|
||||
'hidden',
|
||||
'validator'}),
|
||||
'rw_remove': frozenset({'empty',
|
||||
'everything_frozen',
|
||||
'mandatory',
|
||||
'permissive'}),
|
||||
}
|
||||
|
||||
cfg.property.importation({
|
||||
'properties': {None: {None: frozenset({'cache',
|
||||
'frozen',
|
||||
'validator',
|
||||
'warnings'})}},
|
||||
'ro_append': frozenset({'disabled',
|
||||
'empty',
|
||||
'everything_frozen',
|
||||
'force_store_value',
|
||||
'frozen',
|
||||
'mandatory',
|
||||
'validator'}),
|
||||
'ro_remove': frozenset({'hidden',
|
||||
'permissive'}),
|
||||
'rw_append': frozenset({'disabled',
|
||||
'force_store_value',
|
||||
'frozen',
|
||||
'hidden',
|
||||
'validator'}),
|
||||
'rw_remove': frozenset({'empty',
|
||||
'everything_frozen',
|
||||
'mandatory',
|
||||
'permissive'}),
|
||||
})
|
||||
assert cfg.property.exportation() == {}
|
||||
cfg.property.importation({None: {None: set(('frozen', 'cache', 'validator', 'warnings'))}})
|
||||
assert cfg.property.exportation() == \
|
||||
{
|
||||
'properties': {None: {None: frozenset({'cache',
|
||||
'frozen',
|
||||
'validator',
|
||||
'warnings'})}},
|
||||
'ro_append': frozenset({'disabled',
|
||||
'empty',
|
||||
'everything_frozen',
|
||||
'force_store_value',
|
||||
'frozen',
|
||||
'mandatory',
|
||||
'validator'}),
|
||||
'ro_remove': frozenset({'hidden',
|
||||
'permissive'}),
|
||||
'rw_append': frozenset({'disabled',
|
||||
'force_store_value',
|
||||
'frozen',
|
||||
'hidden',
|
||||
'validator'}),
|
||||
'rw_remove': frozenset({'empty',
|
||||
'everything_frozen',
|
||||
'mandatory',
|
||||
'permissive'}),
|
||||
}
|
||||
{None: {None: set(('frozen', 'cache', 'validator', 'warnings'))}}
|
||||
# assert not list_sessions()
|
||||
|
||||
|
||||
|
@ -933,7 +686,7 @@ def test_set_modified_value():
|
|||
#
|
||||
#
|
||||
def test_pprint():
|
||||
msg_error = _("cannot access to {0} {1} because has {2} {3}")
|
||||
msg_error = _("cannot access to {0} \"{1}\" because has {2} {3}")
|
||||
msg_is_not = _('the value of "{0}" is not {1}')
|
||||
msg_is = _('the value of "{0}" is {1}')
|
||||
properties = _('properties')
|
||||
|
@ -987,8 +740,8 @@ def test_pprint():
|
|||
err = error
|
||||
|
||||
list_disabled = '"disabled" (' + display_list([msg_is.format('Test int option', '"1"'), msg_is.format('string2', '"string"')], add_quote=False) + ')'
|
||||
list_hidden = '"hidden" (' + msg_is_not.format('Test int option', display_list([2, 3, 4], separator='or', add_quote=True)) + ')'
|
||||
assert str(err) == _(msg_error.format('option', '"Test string option"', properties, display_list([list_disabled, list_hidden], add_quote=False)))
|
||||
list_hidden = '"hidden" (' + msg_is_not.format('Test int option', display_list([2, 3, 4], 'or', add_quote=True)) + ')'
|
||||
assert str(err) == _(msg_error.format('option', 'Test string option', properties, display_list([list_disabled, list_hidden], add_quote=False)))
|
||||
del err
|
||||
|
||||
err = None
|
||||
|
@ -997,7 +750,7 @@ def test_pprint():
|
|||
except PropertiesOptionError as error:
|
||||
err = error
|
||||
|
||||
assert str(err) == msg_error.format('optiondescription', '"options"', prop, '"hidden" (' + msg_is.format('Test int option', '"1"') + ')')
|
||||
assert str(err) == msg_error.format('optiondescription', 'options', prop, '"hidden" (' + msg_is.format('Test int option', '"1"') + ')')
|
||||
|
||||
#err = None
|
||||
#try:
|
||||
|
@ -1018,7 +771,7 @@ def test_pprint():
|
|||
except Exception as error:
|
||||
err = error
|
||||
|
||||
assert str(err) == msg_error.format('option', '"string"', properties, display_list(['disabled', 'hidden'], add_quote=True))
|
||||
assert str(err) == msg_error.format('option', 'string', properties, display_list(['disabled', 'hidden'], add_quote=True))
|
||||
del err
|
||||
|
||||
err = None
|
||||
|
@ -1027,13 +780,13 @@ def test_pprint():
|
|||
except Exception as error:
|
||||
err = error
|
||||
|
||||
assert str(err) == msg_error.format('option', '"string3"', prop, '"hidden"')
|
||||
assert str(err) == msg_error.format('option', 'string3', prop, '"hidden"')
|
||||
del err
|
||||
# assert not list_sessions()
|
||||
|
||||
|
||||
def test_pprint_not_todict():
|
||||
msg_error = _("cannot access to {0} {1} because has {2} {3}")
|
||||
msg_error = _("cannot access to {0} \"{1}\" because has {2} {3}")
|
||||
msg_is_not = _('the value of "{0}" is not {1}')
|
||||
msg_is = _('the value of "{0}" is {1}')
|
||||
properties = _('properties')
|
||||
|
@ -1088,7 +841,7 @@ def test_pprint_not_todict():
|
|||
|
||||
list_disabled = '"disabled"'
|
||||
list_hidden = '"hidden"'
|
||||
assert str(err) == _(msg_error.format('option', '"Test string option"', properties, display_list([list_disabled, list_hidden], add_quote=False)))
|
||||
assert str(err) == _(msg_error.format('option', 'Test string option', properties, display_list([list_disabled, list_hidden], add_quote=False)))
|
||||
del err
|
||||
|
||||
err = None
|
||||
|
@ -1097,7 +850,7 @@ def test_pprint_not_todict():
|
|||
except PropertiesOptionError as error:
|
||||
err = error
|
||||
|
||||
assert str(err) == msg_error.format('optiondescription', '"options"', prop, '"hidden"')
|
||||
assert str(err) == msg_error.format('optiondescription', 'options', prop, '"hidden"')
|
||||
|
||||
err = None
|
||||
try:
|
||||
|
@ -1105,7 +858,7 @@ def test_pprint_not_todict():
|
|||
except Exception as error:
|
||||
err = error
|
||||
|
||||
assert str(err) == msg_error.format('option', '"string"', properties, display_list(['disabled', 'hidden'], add_quote=True))
|
||||
assert str(err) == msg_error.format('option', 'string', properties, display_list(['disabled', 'hidden'], add_quote=True))
|
||||
del err
|
||||
|
||||
err = None
|
||||
|
@ -1114,7 +867,7 @@ def test_pprint_not_todict():
|
|||
except Exception as error:
|
||||
err = error
|
||||
|
||||
assert str(err) == msg_error.format('option', '"string3"', prop, '"hidden"')
|
||||
assert str(err) == msg_error.format('option', 'string3', prop, '"hidden"')
|
||||
del err
|
||||
# assert not list_sessions()
|
||||
|
||||
|
|
|
@ -64,10 +64,7 @@ def test_is_hidden(config_type):
|
|||
|
||||
|
||||
def test_group_is_hidden(config_type):
|
||||
gcdummy = BoolOption('dummy', 'dummy', default=False, properties=(('hidden'),))
|
||||
floatoption = FloatOption('float', 'Test float option', default=2.3)
|
||||
gcgroup = OptionDescription('gc', '', [gcdummy, floatoption])
|
||||
od1 = OptionDescription('trs', '', [gcgroup])
|
||||
od1 = make_description()
|
||||
cfg_ori = Config(od1)
|
||||
cfg_ori.property.read_write()
|
||||
cfg_ori.option('gc').property.add('hidden')
|
||||
|
@ -76,14 +73,14 @@ def test_group_is_hidden(config_type):
|
|||
cfg.option('gc.dummy').value.get()
|
||||
if config_type == 'tiramisu-api':
|
||||
cfg.send()
|
||||
assert 'hidden' in cfg_ori.option('gc').property.get()
|
||||
assert 'hidden' in cfg_ori.forcepermissive.option('gc').property.get()
|
||||
cfg = get_config(cfg_ori, config_type)
|
||||
with pytest.raises(PropertiesOptionError):
|
||||
cfg.option('gc.float').value.get()
|
||||
# manually set the subconfigs to "show"
|
||||
if config_type == 'tiramisu-api':
|
||||
cfg.send()
|
||||
cfg_ori.option('gc').property.remove('hidden')
|
||||
cfg_ori.forcepermissive.option('gc').property.remove('hidden')
|
||||
cfg = get_config(cfg_ori, config_type)
|
||||
assert not 'hidden' in cfg.option('gc').property.get()
|
||||
assert cfg.option('gc.float').value.get() == 2.3
|
||||
|
@ -158,38 +155,13 @@ def test_with_many_subgroups(config_type):
|
|||
|
||||
def test_password_option(config_type):
|
||||
o = PasswordOption('o', '')
|
||||
o1 = PasswordOption('o1', '', min_len=4)
|
||||
o2 = PasswordOption('o2', '', max_len=4)
|
||||
o3 = PasswordOption('o3', '', forbidden_char=['p'])
|
||||
od1 = OptionDescription('d', '', [o, o1, o2, o3])
|
||||
od1 = OptionDescription('d', '', [o])
|
||||
cfg = Config(od1)
|
||||
cfg = get_config(cfg, config_type)
|
||||
|
||||
cfg.option('o').value.set('a_valid_password')
|
||||
with pytest.raises(ValueError):
|
||||
cfg.option('o').value.set(1)
|
||||
#
|
||||
assert cfg.option('o1').value.get() is None
|
||||
with pytest.raises(ValueError):
|
||||
cfg.option('o1').value.set("1")
|
||||
with pytest.raises(ValueError):
|
||||
cfg.option('o1').value.set("12")
|
||||
with pytest.raises(ValueError):
|
||||
cfg.option('o1').value.set("123")
|
||||
cfg.option('o1').value.set("1234")
|
||||
cfg.option('o1').value.set("12345")
|
||||
#
|
||||
assert cfg.option('o2').value.get() is None
|
||||
with pytest.raises(ValueError):
|
||||
cfg.option('o2').value.set("12345")
|
||||
cfg.option('o2').value.set("1")
|
||||
cfg.option('o2').value.set("12")
|
||||
cfg.option('o2').value.set("123")
|
||||
cfg.option('o2').value.set("1234")
|
||||
#
|
||||
with pytest.raises(ValueError):
|
||||
cfg.option('o3').value.set("password")
|
||||
cfg.option('o3').value.set("assword")
|
||||
# assert not list_sessions()
|
||||
|
||||
|
||||
|
|
|
@ -334,7 +334,7 @@ def test_validator_warning(config_type):
|
|||
assert len(w) == 1
|
||||
if config_type != 'tiramisu-api':
|
||||
assert w[0].message.opt() == opt2
|
||||
assert str(w[0].message) == msg_err.format('val', _(opt2.get_type()), 'opt2') + ', ' + 'test error return_false'
|
||||
assert str(w[0].message) == msg_err.format('val', opt2.get_type(), 'opt2') + ', ' + 'test error return_false'
|
||||
#
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
cfg.nowarnings.option('opt2').value.set('val')
|
||||
|
@ -352,7 +352,7 @@ def test_validator_warning(config_type):
|
|||
assert len(w) == 1
|
||||
if config_type != 'tiramisu-api':
|
||||
assert w[0].message.opt() == opt3
|
||||
assert str(w[0].message) == msg_err.format('val1', _(opt3.get_type()), 'opt3') + ', ' + 'test error'
|
||||
assert str(w[0].message) == msg_err.format('val1', opt3.get_type(), 'opt3') + ', ' + 'test error'
|
||||
#
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
with pytest.raises(ValueError):
|
||||
|
@ -365,9 +365,9 @@ def test_validator_warning(config_type):
|
|||
assert len(w) == 2
|
||||
if config_type != 'tiramisu-api':
|
||||
assert w[0].message.opt() == opt2
|
||||
assert str(w[0].message) == msg_err.format('val', _(opt2.get_type()), 'opt2') + ', ' + 'test error return_false'
|
||||
assert str(w[0].message) == msg_err.format('val', opt2.get_type(), 'opt2') + ', ' + 'test error return_false'
|
||||
assert w[1].message.opt() == opt3
|
||||
assert str(w[1].message) == msg_err.format('val1', _(opt3.get_type()), 'opt3') + ', ' + 'test error'
|
||||
assert str(w[1].message) == msg_err.format('val1', opt3.get_type(), 'opt3') + ', ' + 'test error'
|
||||
# assert not list_sessions()
|
||||
|
||||
|
||||
|
@ -436,13 +436,13 @@ def test_validator_warning_leadership(config_type):
|
|||
assert len(w) == 1
|
||||
if config_type != 'tiramisu-api':
|
||||
assert w[0].message.opt() == netmask_admin_eth0
|
||||
assert str(w[0].message) == msg_err.format('val1', _(netmask_admin_eth0.get_type()), display_name_netmask) + ', test error'
|
||||
assert str(w[0].message) == msg_err.format('val1', netmask_admin_eth0.get_type(), display_name_netmask) + ', test error'
|
||||
#
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
cfg.option('ip_admin_eth0.ip_admin_eth0').value.set(['val'])
|
||||
if config_type != 'tiramisu-api':
|
||||
assert w and w[0].message.opt() == ip_admin_eth0
|
||||
assert str(w[0].message) == msg_err.format('val', _(ip_admin_eth0.get_type()), display_name_ip) + ', test error return_false'
|
||||
assert str(w[0].message) == msg_err.format('val', ip_admin_eth0.get_type(), display_name_ip) + ', test error return_false'
|
||||
else:
|
||||
assert len(w) == 2
|
||||
#
|
||||
|
@ -450,7 +450,7 @@ def test_validator_warning_leadership(config_type):
|
|||
cfg.option('ip_admin_eth0.ip_admin_eth0').value.set(['val', 'val1', 'val1'])
|
||||
if config_type != 'tiramisu-api':
|
||||
assert w[0].message.opt() == ip_admin_eth0
|
||||
assert str(w[0].message) == msg_err.format('val', _(ip_admin_eth0.get_type()), display_name_ip) + ', test error return_false'
|
||||
assert str(w[0].message) == msg_err.format('val', ip_admin_eth0.get_type(), display_name_ip) + ', test error return_false'
|
||||
else:
|
||||
assert len(w) == 3
|
||||
#
|
||||
|
@ -458,7 +458,7 @@ def test_validator_warning_leadership(config_type):
|
|||
cfg.option('ip_admin_eth0.ip_admin_eth0').value.set(['val1', 'val', 'val1'])
|
||||
if config_type != 'tiramisu-api':
|
||||
assert w[0].message.opt() == ip_admin_eth0
|
||||
assert str(w[0].message) == msg_err.format('val', _(ip_admin_eth0.get_type()), display_name_ip) + ', test error return_false'
|
||||
assert str(w[0].message) == msg_err.format('val', ip_admin_eth0.get_type(), display_name_ip) + ', test error return_false'
|
||||
else:
|
||||
assert len(w) == 3
|
||||
#
|
||||
|
@ -467,7 +467,7 @@ def test_validator_warning_leadership(config_type):
|
|||
cfg.option('ip_admin_eth0.ip_admin_eth0').value.set(['val1', 'val1', 'val'])
|
||||
if config_type != 'tiramisu-api':
|
||||
assert w[0].message.opt() == ip_admin_eth0
|
||||
assert str(w[0].message) == msg_err.format('val', _(ip_admin_eth0.get_type()), display_name_ip) + ', test error return_false'
|
||||
assert str(w[0].message) == msg_err.format('val', ip_admin_eth0.get_type(), display_name_ip) + ', test error return_false'
|
||||
else:
|
||||
assert len(w) == 3
|
||||
# assert not list_sessions()
|
||||
|
@ -1046,12 +1046,12 @@ def test_validator_error_prefix():
|
|||
try:
|
||||
cfg.option('b').value.set(1)
|
||||
except Exception as err:
|
||||
assert str(err) == _('"{0}" is an invalid {1} for "{2}"').format('1', _('integer'), 'b') + ', ' + _('value is identical to {0}').format('"a"')
|
||||
assert str(err) == _('"{0}" is an invalid {1} for "{2}"').format('1', _('integer'), 'b') + ', ' + _('value is identical to {}').format('"a"')
|
||||
try:
|
||||
cfg.option('b').value.set(1)
|
||||
except Exception as err:
|
||||
err.prefix = ''
|
||||
assert str(err) == _('value is identical to {0}').format('"a"')
|
||||
assert str(err) == _('value is identical to {}').format('"a"')
|
||||
# assert not list_sessions()
|
||||
|
||||
|
||||
|
@ -1260,24 +1260,18 @@ def test_consistency_not_equal_has_dependency():
|
|||
def test_validator_information(config_type):
|
||||
opt1 = StrOption('opt1', '', validators=[Calculation(return_true, Params((ParamSelfInformation('key'), ParamValue('yes'))))], default='val')
|
||||
opt2 = StrOption('opt2', '', validators=[Calculation(return_true, Params((ParamInformation('key'), ParamValue('yes'))))], default='val')
|
||||
opt3 = StrOption('opt3', '', validators=[Calculation(return_true, Params((ParamInformation('key', option=opt1), ParamValue('yes'))))], default='val')
|
||||
od1 = OptionDescription('root', '', [opt1, opt2, opt3])
|
||||
od1 = OptionDescription('root', '', [opt1, opt2])
|
||||
cfg = Config(od1)
|
||||
with pytest.raises(ConfigError):
|
||||
cfg.option('opt1').value.get()
|
||||
with pytest.raises(ConfigError):
|
||||
cfg.option('opt3').value.get()
|
||||
cfg.option('opt1').information.set('key', 'val')
|
||||
assert cfg.option('opt1').value.get() == 'val'
|
||||
assert cfg.option('opt3').value.get() == 'val'
|
||||
cfg.option('opt1').information.set('key', 'val1')
|
||||
with pytest.raises(ValueError):
|
||||
cfg.option('opt1').value.get()
|
||||
with pytest.raises(ValueError):
|
||||
cfg.option('opt3').value.get()
|
||||
#
|
||||
with pytest.raises(ConfigError):
|
||||
cfg.option('opt2').value.get()
|
||||
assert cfg.option('opt2').value.get()
|
||||
cfg.information.set('key', 'val')
|
||||
assert cfg.option('opt2').value.get() == 'val'
|
||||
cfg.information.set('key', 'val1')
|
||||
|
|
|
@ -22,7 +22,7 @@ def test_forcepermissive_and_unrestraint(config_type):
|
|||
cfg_ori.property.read_write()
|
||||
cfg = get_config(cfg_ori, config_type)
|
||||
with pytest.raises(ConfigError):
|
||||
cfg_ori.forcepermissive.add('disabled')
|
||||
cfg_ori.unrestraint.forcepermissive.add('disabled')
|
||||
|
||||
|
||||
def test_permissive(config_type):
|
||||
|
@ -39,9 +39,9 @@ def test_permissive(config_type):
|
|||
assert set(props) == {'disabled'}
|
||||
if config_type == 'tiramisu-api':
|
||||
cfg.send()
|
||||
cfg_ori.permissive.add('disabled')
|
||||
cfg_ori.permissive.remove('hidden')
|
||||
assert cfg_ori.permissive.get() == frozenset(['disabled'])
|
||||
cfg_ori.unrestraint.permissive.add('disabled')
|
||||
cfg_ori.unrestraint.permissive.remove('hidden')
|
||||
assert cfg_ori.unrestraint.permissive.get() == frozenset(['disabled'])
|
||||
cfg = get_config(cfg_ori, config_type)
|
||||
props = frozenset()
|
||||
try:
|
||||
|
@ -81,8 +81,8 @@ def test_permissive_add(config_type):
|
|||
assert set(props) == {'disabled'}
|
||||
if config_type == 'tiramisu-api':
|
||||
cfg.send()
|
||||
cfg_ori.permissive.add('disabled')
|
||||
assert cfg_ori.permissive.get() == frozenset(['hidden', 'disabled'])
|
||||
cfg_ori.unrestraint.permissive.add('disabled')
|
||||
assert cfg_ori.unrestraint.permissive.get() == frozenset(['hidden', 'disabled'])
|
||||
cfg = get_config(cfg_ori, config_type)
|
||||
props = frozenset()
|
||||
try:
|
||||
|
@ -119,10 +119,10 @@ def test_permissive_pop():
|
|||
except PropertiesOptionError as err:
|
||||
props = err.proptype
|
||||
assert set(props) == {'disabled'}
|
||||
cfg.permissive.add('disabled')
|
||||
assert cfg.permissive.get() == frozenset(['hidden', 'disabled'])
|
||||
cfg.unrestraint.permissive.add('disabled')
|
||||
assert cfg.unrestraint.permissive.get() == frozenset(['hidden', 'disabled'])
|
||||
cfg.forcepermissive.option('u1').value.get()
|
||||
cfg.permissive.remove('disabled')
|
||||
cfg.unrestraint.permissive.remove('disabled')
|
||||
props = frozenset()
|
||||
try:
|
||||
cfg.forcepermissive.option('u1').value.get()
|
||||
|
@ -136,14 +136,14 @@ def test_permissive_reset():
|
|||
od1 = make_description()
|
||||
cfg = Config(od1)
|
||||
cfg.property.read_write()
|
||||
assert cfg.permissive.get() == frozenset(['hidden'])
|
||||
assert cfg.unrestraint.permissive.get() == frozenset(['hidden'])
|
||||
#
|
||||
cfg.permissive.add('disabled')
|
||||
cfg.permissive.remove('hidden')
|
||||
assert cfg.permissive.get() == frozenset(['disabled'])
|
||||
cfg.unrestraint.permissive.add('disabled')
|
||||
cfg.unrestraint.permissive.remove('hidden')
|
||||
assert cfg.unrestraint.permissive.get() == frozenset(['disabled'])
|
||||
#
|
||||
cfg.permissive.reset()
|
||||
assert cfg.permissive.get() == frozenset(['hidden'])
|
||||
cfg.unrestraint.permissive.reset()
|
||||
assert cfg.unrestraint.permissive.get() == frozenset()
|
||||
# assert not list_sessions()
|
||||
|
||||
|
||||
|
@ -157,9 +157,9 @@ def test_permissive_mandatory():
|
|||
except PropertiesOptionError as err:
|
||||
props = err.proptype
|
||||
assert frozenset(props) == frozenset(['disabled'])
|
||||
cfg.permissive.add('mandatory')
|
||||
cfg.permissive.add('disabled')
|
||||
assert cfg.permissive.get() == frozenset(['hidden', 'mandatory', 'disabled'])
|
||||
cfg.unrestraint.permissive.add('mandatory')
|
||||
cfg.unrestraint.permissive.add('disabled')
|
||||
assert cfg.unrestraint.permissive.get() == frozenset(['mandatory', 'disabled'])
|
||||
cfg.property.add('permissive')
|
||||
cfg.option('u1').value.get()
|
||||
cfg.property.remove('permissive')
|
||||
|
@ -175,10 +175,10 @@ def test_permissive_frozen():
|
|||
od1 = make_description()
|
||||
cfg = Config(od1)
|
||||
cfg.property.read_write()
|
||||
cfg.permissive.remove('hidden')
|
||||
cfg.permissive.add('frozen')
|
||||
cfg.permissive.add('disabled')
|
||||
assert cfg.permissive.get() == frozenset(['frozen', 'disabled'])
|
||||
cfg.unrestraint.permissive.remove('hidden')
|
||||
cfg.unrestraint.permissive.add('frozen')
|
||||
cfg.unrestraint.permissive.add('disabled')
|
||||
assert cfg.unrestraint.permissive.get() == frozenset(['frozen', 'disabled'])
|
||||
assert cfg.permissive.get() == frozenset(['frozen', 'disabled'])
|
||||
try:
|
||||
cfg.option('u1').value.set(1)
|
||||
|
@ -229,7 +229,7 @@ def test_permissive_option(config_type):
|
|||
|
||||
if config_type == 'tiramisu-api':
|
||||
cfg.send()
|
||||
cfg_ori.option('u1').permissive.add('disabled')
|
||||
cfg_ori.unrestraint.option('u1').permissive.set(frozenset(['disabled']))
|
||||
cfg = get_config(cfg_ori, config_type)
|
||||
props = frozenset()
|
||||
try:
|
||||
|
@ -293,7 +293,7 @@ def test_permissive_option_cache():
|
|||
props = err.proptype
|
||||
assert set(props) == {'disabled'}
|
||||
|
||||
cfg.option('u1').permissive.add('disabled')
|
||||
cfg.unrestraint.option('u1').permissive.set(frozenset(['disabled']))
|
||||
props = frozenset()
|
||||
try:
|
||||
cfg.option('u1').value.get()
|
||||
|
@ -342,9 +342,8 @@ def test_permissive_option_mandatory():
|
|||
except PropertiesOptionError as err:
|
||||
props = err.proptype
|
||||
assert frozenset(props) == frozenset(['disabled'])
|
||||
cfg.option('u1').permissive.add('mandatory')
|
||||
cfg.option('u1').permissive.add('disabled')
|
||||
assert cfg.option('u1').permissive.get() == frozenset(['mandatory', 'disabled'])
|
||||
cfg.unrestraint.option('u1').permissive.set(frozenset(['mandatory', 'disabled']))
|
||||
assert cfg.unrestraint.option('u1').permissive.get() == frozenset(['mandatory', 'disabled'])
|
||||
cfg.property.add('permissive')
|
||||
cfg.option('u1').value.get()
|
||||
cfg.property.remove('permissive')
|
||||
|
@ -360,8 +359,7 @@ def test_permissive_option_frozen():
|
|||
od1 = make_description()
|
||||
cfg = Config(od1)
|
||||
cfg.property.read_write()
|
||||
cfg.option('u1').permissive.add('disabled')
|
||||
cfg.option('u1').permissive.add('frozen')
|
||||
cfg.unrestraint.option('u1').permissive.set(frozenset(['frozen', 'disabled']))
|
||||
cfg.option('u1').value.set(1)
|
||||
assert cfg.option('u1').value.get() == 1
|
||||
cfg.property.add('permissive')
|
||||
|
@ -371,6 +369,15 @@ def test_permissive_option_frozen():
|
|||
# assert not list_sessions()
|
||||
|
||||
|
||||
def test_invalid_option_permissive():
|
||||
od1 = make_description()
|
||||
cfg = Config(od1)
|
||||
cfg.property.read_write()
|
||||
with pytest.raises(TypeError):
|
||||
cfg.unrestraint.option('u1').permissive.set(['frozen', 'disabled'])
|
||||
# assert not list_sessions()
|
||||
|
||||
|
||||
def test_remove_option_permissive(config_type):
|
||||
var1 = StrOption('var1', '', u'value', properties=('hidden',))
|
||||
od1 = OptionDescription('od1', '', [var1])
|
||||
|
@ -382,13 +389,13 @@ def test_remove_option_permissive(config_type):
|
|||
cfg.option('od1.var1').value.get()
|
||||
if config_type == 'tiramisu-api':
|
||||
cfg.send()
|
||||
cfg_ori.forcepermissive.option('od1.var1').permissive.add('hidden')
|
||||
cfg_ori.forcepermissive.option('od1.var1').permissive.set(frozenset(['hidden']))
|
||||
assert cfg_ori.forcepermissive.option('od1.var1').permissive.get() == frozenset(['hidden'])
|
||||
cfg = get_config(cfg_ori, config_type)
|
||||
assert cfg.option('od1.var1').value.get() == 'value'
|
||||
if config_type == 'tiramisu-api':
|
||||
cfg.send()
|
||||
cfg_ori.forcepermissive.option('od1.var1').permissive.reset()
|
||||
cfg_ori.forcepermissive.option('od1.var1').permissive.set(frozenset())
|
||||
assert cfg_ori.forcepermissive.option('od1.var1').permissive.get() == frozenset()
|
||||
cfg = get_config(cfg_ori, config_type)
|
||||
with pytest.raises(PropertiesOptionError):
|
||||
|
@ -407,7 +414,7 @@ def test_reset_option_permissive(config_type):
|
|||
cfg.option('od1.var1').value.get()
|
||||
if config_type == 'tiramisu-api':
|
||||
cfg.send()
|
||||
cfg_ori.forcepermissive.option('od1.var1').permissive.add('hidden')
|
||||
cfg_ori.forcepermissive.option('od1.var1').permissive.set(frozenset(['hidden']))
|
||||
assert cfg_ori.forcepermissive.option('od1.var1').permissive.get() == frozenset(['hidden'])
|
||||
cfg = get_config(cfg_ori, config_type)
|
||||
assert cfg.option('od1.var1').value.get() == 'value'
|
||||
|
|
|
@ -31,12 +31,12 @@ def test_properties(config_type):
|
|||
assert frozenset(props) == frozenset(['disabled'])
|
||||
if config_type == 'tiramisu-api':
|
||||
cfg.send()
|
||||
cfg_ori.unrestraint.option('ip_address_service').permissive.add('disabled')
|
||||
cfg_ori.unrestraint.option('ip_address_service').property.remove('disabled')
|
||||
cfg = get_config(cfg_ori, config_type)
|
||||
cfg.option('ip_address_service').value.get()
|
||||
if config_type == 'tiramisu-api':
|
||||
cfg.send()
|
||||
cfg_ori.unrestraint.option('ip_address_service').permissive.remove('disabled')
|
||||
cfg_ori.unrestraint.option('ip_address_service').property.add('disabled')
|
||||
cfg = get_config(cfg_ori, config_type)
|
||||
props = []
|
||||
try:
|
||||
|
@ -47,8 +47,8 @@ def test_properties(config_type):
|
|||
# pop twice
|
||||
if config_type == 'tiramisu-api':
|
||||
cfg.send()
|
||||
cfg_ori.unrestraint.option('ip_address_service').permissive.add('disabled')
|
||||
cfg_ori.unrestraint.option('ip_address_service').permissive.remove('disabled')
|
||||
cfg_ori.unrestraint.option('ip_address_service').property.remove('disabled')
|
||||
cfg_ori.unrestraint.option('ip_address_service').property.remove('disabled')
|
||||
# assert not list_sessions()
|
||||
|
||||
|
||||
|
@ -196,10 +196,10 @@ def test_requires_same_action(config_type):
|
|||
submsg = '"disabled" (' + _('the value of "{0}" is {1}').format('activate_service', '"False"') + ')'
|
||||
if config_type == 'tiramisu':
|
||||
submsg = '"new" (' + _('the value of "{0}" is {1}').format('activate_service', '"False"') + ')'
|
||||
submsg = '"disabled" (' + str(_('cannot access to {0} {1} because has {2} {3}').format('option', '"activate_service_web"', _('property'), submsg)) + ')'
|
||||
assert str(err) == str(_('cannot access to {0} {1} because has {2} {3}').format('option', '"ip_address_service_web"', _('property'), submsg))
|
||||
submsg = '"disabled" (' + str(_('cannot access to {0} "{1}" because has {2} {3}').format('option', 'activate_service_web', _('property'), submsg)) + ')'
|
||||
assert str(err) == str(_('cannot access to {0} "{1}" because has {2} {3}').format('option', 'ip_address_service_web', _('property'), submsg))
|
||||
#access to cache
|
||||
assert str(err) == str(_('cannot access to {0} {1} because has {2} {3}').format('option', '"ip_address_service_web"', _('property'), submsg))
|
||||
assert str(err) == str(_('cannot access to {0} "{1}" because has {2} {3}').format('option', 'ip_address_service_web', _('property'), submsg))
|
||||
else:
|
||||
# FIXME
|
||||
assert str(err) == 'error'
|
||||
|
@ -426,9 +426,8 @@ def test_requires_transitive_unrestraint(config_type):
|
|||
#
|
||||
if config_type == 'tiramisu-api':
|
||||
cfg.send()
|
||||
assert cfg_ori.option('activate_service_web').property.get() == {'disabled'}
|
||||
# FIXME assert cfg_ori.unrestraint.option('ip_address_service_web').property.get() == {'disabled'}
|
||||
assert cfg_ori.option('ip_address_service_web').property.get() == {'disabled'}
|
||||
assert cfg_ori.unrestraint.option('activate_service_web').property.get() == {'disabled'}
|
||||
assert cfg_ori.unrestraint.option('ip_address_service_web').property.get() == {'disabled'}
|
||||
# assert not list_sessions()
|
||||
|
||||
|
||||
|
@ -592,7 +591,7 @@ def test_requires_transitive_hidden_disabled_multiple(config_type):
|
|||
cfg.option('activate_service').value.set(False)
|
||||
except ConfigError as err:
|
||||
req = err
|
||||
error_msg = str(_('unable to transform tiramisu object to dict: {}').format(_('cannot access to option {0} because required option {1} has {2} {3}').format('ip_address_service_web', '"activate_service_web"', _('property'), '"disabled"')))
|
||||
error_msg = str(_('unable to transform tiramisu object to dict: {}').format(_('cannot access to option "{0}" because required option "{1}" has {2} {3}').format('ip_address_service_web', 'activate_service_web', _('property'), '"disabled"')))
|
||||
else:
|
||||
cfg.option('activate_service').value.set(False)
|
||||
#
|
||||
|
@ -608,26 +607,25 @@ def test_requires_transitive_hidden_disabled_multiple(config_type):
|
|||
cfg.option('ip_address_service_web').value.get()
|
||||
except ConfigError as err:
|
||||
req = err
|
||||
error_msg = str(_('unable to carry out a calculation for {}, {}').format('"ip_address_service_web"', _('cannot access to {0} {1} because has {2} {3}').format('option', '"activate_service_web"', _('property'), display_list(['disabled'], add_quote=True))))
|
||||
error_msg = str(_('unable to carry out a calculation for "{}", {}').format('ip_address_service_web', _('cannot access to {0} "{1}" because has {2} {3}').format('option', 'activate_service_web', _('property'), display_list(['disabled'], add_quote=True))))
|
||||
assert req, "ip_address_service_web should raise ConfigError"
|
||||
assert str(req) == error_msg
|
||||
del req
|
||||
#
|
||||
cfg_ori.permissive.reset()
|
||||
cfg_ori.permissive.remove('hidden')
|
||||
if config_type == 'tiramisu-api':
|
||||
try:
|
||||
cfg = get_config(cfg_ori, config_type)
|
||||
except ConfigError as err:
|
||||
req = err
|
||||
error_msg = str(_('unable to transform tiramisu object to dict: {}').format(_('cannot access to option "{0}" because required option {1} has {2} {3}').format('ip_address_service_web', '"activate_service_web"', _('properties'), '"disabled" {} "hidden"'.format(_('and')))))
|
||||
error_msg = str(_('unable to transform tiramisu object to dict: {}').format(_('cannot access to option "{0}" because required option "{1}" has {2} {3}').format('ip_address_service_web', 'activate_service_web', _('properties'), '"disabled" {} "hidden"'.format(_('and')))))
|
||||
else:
|
||||
cfg = get_config(cfg_ori, config_type)
|
||||
try:
|
||||
cfg.option('ip_address_service_web').value.get()
|
||||
except ConfigError as err:
|
||||
req = err
|
||||
error_msg = str(_('unable to carry out a calculation for {}, {}').format('"ip_address_service_web"', _('cannot access to {0} {1} because has {2} {3}').format('option', '"activate_service_web"', _('properties'), display_list(['hidden', 'disabled'], add_quote=True))))
|
||||
error_msg = str(_('unable to carry out a calculation for "{}", {}').format('ip_address_service_web', _('cannot access to {0} "{1}" because has {2} {3}').format('option', 'activate_service_web', _('properties'), display_list(['hidden', 'disabled'], add_quote=True))))
|
||||
assert req, "ip_address_service_web should raise ConfigError"
|
||||
assert str(req) == error_msg
|
||||
del req
|
||||
|
|
|
@ -115,18 +115,18 @@ def test_append_submulti():
|
|||
#
|
||||
assert cfg.option('multi2').value.get() == []
|
||||
assert cfg.option('multi2').owner.get() == owners.default
|
||||
cfg.option('multi2').value.set([cfg.option('multi2').value.defaultmulti()])
|
||||
cfg.option('multi2').value.set([cfg.option('multi2').defaultmulti()])
|
||||
assert cfg.option('multi2').owner.get() == owner
|
||||
assert cfg.option('multi2').value.get() == [['yes']]
|
||||
cfg.option('multi2').value.set([cfg.option('multi2').value.defaultmulti(), ['no']])
|
||||
cfg.option('multi2').value.set([cfg.option('multi2').defaultmulti(), ['no']])
|
||||
assert cfg.option('multi2').value.get() == [['yes'], ['no']]
|
||||
#
|
||||
assert cfg.option('multi3').value.get() == [['yes']]
|
||||
assert cfg.option('multi3').owner.get() == owners.default
|
||||
cfg.option('multi3').value.set([cfg.option('multi2').value.defaultmulti(), []])
|
||||
cfg.option('multi3').value.set([cfg.option('multi2').defaultmulti(), []])
|
||||
assert cfg.option('multi3').owner.get() == owner
|
||||
assert cfg.option('multi3').value.get() == [['yes'], []]
|
||||
cfg.option('multi3').value.set([cfg.option('multi2').value.defaultmulti(), [], ['no']])
|
||||
cfg.option('multi3').value.set([cfg.option('multi2').defaultmulti(), [], ['no']])
|
||||
assert cfg.option('multi3').value.get() == [['yes'], [], ['no']]
|
||||
# assert not list_sessions()
|
||||
|
||||
|
@ -193,7 +193,7 @@ def test_callback_submulti_str():
|
|||
owner = cfg.owner.get()
|
||||
assert cfg.option('multi').owner.get() == owners.default
|
||||
assert cfg.option('multi').value.get() == [['val']]
|
||||
cfg.option('multi').value.set([['val'], cfg.option('multi').value.defaultmulti()])
|
||||
cfg.option('multi').value.set([['val'], cfg.option('multi').defaultmulti()])
|
||||
assert cfg.option('multi').owner.get() == owner
|
||||
assert cfg.option('multi').value.get() == [['val'], ['val']]
|
||||
cfg.option('multi').value.reset()
|
||||
|
@ -209,10 +209,10 @@ def test_callback_submulti_list():
|
|||
owner = cfg.owner.get()
|
||||
assert cfg.option('multi').value.get() == [['val', 'val']]
|
||||
assert cfg.option('multi').owner.get() == owners.default
|
||||
cfg.option('multi').value.set([['val', 'val'], cfg.option('multi').value.defaultmulti()])
|
||||
cfg.option('multi').value.set([['val', 'val'], cfg.option('multi').defaultmulti()])
|
||||
assert cfg.option('multi').owner.get() == owner
|
||||
assert cfg.option('multi').value.get() == [['val', 'val'], ['val', 'val']]
|
||||
cfg.option('multi').value.set([['val', 'val'], cfg.option('multi').value.defaultmulti(), cfg.option('multi').value.defaultmulti()])
|
||||
cfg.option('multi').value.set([['val', 'val'], cfg.option('multi').defaultmulti(), cfg.option('multi').defaultmulti()])
|
||||
assert cfg.option('multi').value.get() == [['val', 'val'], ['val', 'val'], ['val', 'val']]
|
||||
cfg.option('multi').value.reset()
|
||||
assert cfg.option('multi').owner.get() == owners.default
|
||||
|
@ -227,7 +227,7 @@ def test_callback_submulti_list_list():
|
|||
owner = cfg.owner.get()
|
||||
assert cfg.option('multi').value.get() == [['val', 'val']]
|
||||
assert cfg.option('multi').owner.get() == owners.default
|
||||
cfg.option('multi').value.set([['val', 'val'], cfg.option('multi').value.defaultmulti()])
|
||||
cfg.option('multi').value.set([['val', 'val'], cfg.option('multi').defaultmulti()])
|
||||
assert cfg.option('multi').owner.get() == owner
|
||||
assert cfg.option('multi').value.get() == [['val', 'val'], []]
|
||||
cfg.option('multi').value.reset()
|
||||
|
|
|
@ -26,8 +26,8 @@ def test_symlink_option(config_type):
|
|||
cfg = get_config(cfg, config_type)
|
||||
assert not cfg.option('s1.b').issymlinkoption()
|
||||
assert cfg.option('c').issymlinkoption()
|
||||
assert cfg.option('s1.b').type() == 'boolean'
|
||||
assert cfg.option('c').type() == 'boolean'
|
||||
assert cfg.option('s1.b').type() == _('boolean')
|
||||
assert cfg.option('c').type() == _('boolean')
|
||||
assert cfg.option('s1.b').value.get() is False
|
||||
cfg.option("s1.b").value.set(True)
|
||||
cfg.option("s1.b").value.set(False)
|
||||
|
@ -54,13 +54,17 @@ def test_symlink_default(config_type):
|
|||
assert not cfg.option('c').ismulti()
|
||||
assert not cfg.option('s1.b').issubmulti()
|
||||
assert not cfg.option('c').issubmulti()
|
||||
assert not cfg.option('s1.b').default()
|
||||
assert not cfg.option('c').default()
|
||||
assert not cfg.option('s1.b').value.default()
|
||||
assert not cfg.option('c').value.default()
|
||||
with pytest.raises(ConfigError):
|
||||
assert not cfg.option('s1.b').value.defaultmulti()
|
||||
assert not cfg.option('s1.b').defaultmulti()
|
||||
with pytest.raises(ConfigError):
|
||||
assert not cfg.option('c').value.defaultmulti()
|
||||
assert not cfg.option('c').defaultmulti()
|
||||
cfg.option("s1.b").value.set(True)
|
||||
assert not cfg.option('s1.b').default()
|
||||
assert not cfg.option('c').default()
|
||||
assert not cfg.option('s1.b').value.default()
|
||||
assert not cfg.option('c').value.default()
|
||||
## assert not list_sessions()
|
||||
|
@ -78,15 +82,19 @@ def test_symlink_default_multi(config_type):
|
|||
assert cfg.option('c').ismulti()
|
||||
assert not cfg.option('s1.b').issubmulti()
|
||||
assert not cfg.option('c').issubmulti()
|
||||
assert cfg.option('s1.b').default() == [False]
|
||||
assert cfg.option('c').default() == [False]
|
||||
assert cfg.option('s1.b').value.default() == [False]
|
||||
assert cfg.option('c').value.default() == [False]
|
||||
assert cfg.option('s1.b').value.defaultmulti()
|
||||
assert cfg.option('c').value.defaultmulti()
|
||||
assert cfg.option('s1.b').defaultmulti()
|
||||
assert cfg.option('c').defaultmulti()
|
||||
cfg.option("s1.b").value.set([True])
|
||||
assert cfg.option('s1.b').default() == [False]
|
||||
assert cfg.option('c').default() == [False]
|
||||
assert cfg.option('s1.b').value.default() == [False]
|
||||
assert cfg.option('c').value.default() == [False]
|
||||
assert cfg.option('s1.b').value.defaultmulti()
|
||||
assert cfg.option('c').value.defaultmulti()
|
||||
assert cfg.option('s1.b').defaultmulti()
|
||||
assert cfg.option('c').defaultmulti()
|
||||
## assert not list_sessions()
|
||||
|
||||
|
||||
|
@ -133,7 +141,7 @@ def test_symlink_getpermissive():
|
|||
od1 = OptionDescription('opt', '', [boolopt, linkopt])
|
||||
cfg = Config(od1)
|
||||
cfg.property.read_write()
|
||||
cfg.option('b').permissive.add('perm')
|
||||
cfg.option('b').permissive.set(frozenset(['perm']))
|
||||
cfg.option('c').permissive.get() == frozenset(['perm'])
|
||||
# assert not list_sessions()
|
||||
|
||||
|
@ -258,26 +266,14 @@ def test_symlink_owner(config_type):
|
|||
|
||||
|
||||
def test_symlink_get_information():
|
||||
boolopt = BoolOption("b", "", default=False, informations={'test': 'test'})
|
||||
linkopt = SymLinkOption("c", boolopt)
|
||||
od1 = OptionDescription('opt', '', [linkopt, boolopt])
|
||||
cfg = Config(od1)
|
||||
assert cfg.option('b').information.get('test') == 'test'
|
||||
assert cfg.option('c').information.get('test') == 'test'
|
||||
cfg.option('b').information.set('test', 'test2')
|
||||
assert cfg.option('b').information.get('test') == 'test2'
|
||||
assert cfg.option('c').information.get('test') == 'test2'
|
||||
|
||||
|
||||
def test_symlink_informations():
|
||||
boolopt = BoolOption("b", "", default=False)
|
||||
with pytest.raises(TypeError):
|
||||
linkopt = SymLinkOption("c", boolopt, informations={'test': 'test'})
|
||||
linkopt = SymLinkOption("c", boolopt)
|
||||
od1 = OptionDescription('opt', '', [linkopt, boolopt])
|
||||
cfg = Config(od1)
|
||||
with pytest.raises(ConfigError):
|
||||
cfg.option('c').information.set('test', 'test2')
|
||||
boolopt.impl_set_information('test', 'test')
|
||||
assert boolopt.impl_get_information('test') == 'test'
|
||||
assert linkopt.impl_get_information('test') == 'test'
|
||||
boolopt.impl_set_information('test', 'test2')
|
||||
assert boolopt.impl_get_information('test') == 'test2'
|
||||
assert linkopt.impl_get_information('test') == 'test2'
|
||||
|
||||
|
||||
def test_symlink_leader():
|
||||
|
@ -289,59 +285,11 @@ def test_symlink_leader():
|
|||
|
||||
|
||||
def test_symlink_followers():
|
||||
a = StrOption('a', "", multi=True)
|
||||
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
|
||||
netmask_admin_eth0 = SymLinkOption('netmask_admin_eth0', ip_admin_eth0)
|
||||
leader = Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||
od1 = OptionDescription('opt', '', [leader])
|
||||
cfg = Config(od1)
|
||||
assert parse_od_get(cfg.value.get()) == {'ip_admin_eth0.ip_admin_eth0': []}
|
||||
cfg.option('ip_admin_eth0.ip_admin_eth0').value.set(['val1', 'val2'])
|
||||
assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 1).value.get() == 'val2'
|
||||
assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 1).owner.get() == 'user'
|
||||
assert parse_od_get(cfg.value.get()) == {
|
||||
'ip_admin_eth0.ip_admin_eth0': [{'ip_admin_eth0.ip_admin_eth0': 'val1',
|
||||
'ip_admin_eth0.netmask_admin_eth0': 'val1'},
|
||||
{'ip_admin_eth0.ip_admin_eth0': 'val2',
|
||||
'ip_admin_eth0.netmask_admin_eth0': 'val2'}],
|
||||
}
|
||||
|
||||
def test_symlink_leader_default():
|
||||
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", ['val1', 'val2'], multi=True)
|
||||
netmask_admin_eth0 = SymLinkOption('netmask_admin_eth0', ip_admin_eth0)
|
||||
leader = Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||
od1 = OptionDescription('opt', '', [leader])
|
||||
cfg = Config(od1)
|
||||
assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 1).value.get() == 'val2'
|
||||
assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 1).owner.isdefault()
|
||||
assert parse_od_get(cfg.value.get()) == {
|
||||
'ip_admin_eth0.ip_admin_eth0': [{'ip_admin_eth0.ip_admin_eth0': 'val1',
|
||||
'ip_admin_eth0.netmask_admin_eth0': 'val1'},
|
||||
{'ip_admin_eth0.ip_admin_eth0': 'val2',
|
||||
'ip_admin_eth0.netmask_admin_eth0': 'val2'}],
|
||||
}
|
||||
|
||||
|
||||
def test_symlink_followers_2():
|
||||
variable1 = StrOption('variable1', "", multi=True)
|
||||
variable2 = StrOption('variable2', "", multi=True)
|
||||
variable3 = SymLinkOption('variable3', variable2)
|
||||
leader = Leadership('variable1', '', [variable1, variable2, variable3])
|
||||
od1 = OptionDescription('opt', '', [leader])
|
||||
cfg = Config(od1)
|
||||
assert parse_od_get(cfg.value.get()) == {'variable1.variable1': []}
|
||||
cfg.option('variable1.variable1').value.set(['val1', 'val2'])
|
||||
cfg.option('variable1.variable2', 0).value.set('ival1')
|
||||
cfg.option('variable1.variable2', 1).value.set('ival2')
|
||||
assert cfg.option('variable1.variable3', 1).owner.get() == 'user'
|
||||
assert cfg.option('variable1.variable3', 1).value.get() == 'ival2'
|
||||
assert parse_od_get(cfg.value.get()) == {'variable1.variable1': [{'variable1.variable1': 'val1',
|
||||
'variable1.variable2': 'ival1',
|
||||
'variable1.variable3': 'ival1'},
|
||||
{'variable1.variable1': 'val2',
|
||||
'variable1.variable2': 'ival2',
|
||||
'variable1.variable3': 'ival2'}],
|
||||
}
|
||||
|
||||
netmask_admin_eth0 = SymLinkOption('netmask_admin_eth0', a)
|
||||
with pytest.raises(ValueError):
|
||||
Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||
|
||||
|
||||
def test_symlink_with_leader(config_type):
|
||||
|
@ -411,9 +359,9 @@ def test_symlink_dependency():
|
|||
[linkopt, OptionDescription("s1", "", [boolopt])])
|
||||
cfg = Config(od1)
|
||||
assert cfg.option('s1.b').has_dependency() is False
|
||||
assert cfg.option('c').has_dependency() is False
|
||||
assert cfg.option('c').has_dependency() is True
|
||||
assert cfg.option('s1.b').has_dependency(False) is True
|
||||
assert cfg.option('c').has_dependency(False) is True
|
||||
assert cfg.option('c').has_dependency(False) is False
|
||||
# assert not list_sessions()
|
||||
|
||||
|
||||
|
@ -437,13 +385,13 @@ def test_symlink_list(config_type):
|
|||
[linkopt, OptionDescription("s1", "", [boolopt])])
|
||||
cfg = Config(od1)
|
||||
cfg = get_config(cfg, config_type)
|
||||
assert [opt.path() for opt in cfg.list()] == ['c', 's1']
|
||||
assert [opt.path() for opt in cfg.option.list()] == ['c', 's1']
|
||||
#
|
||||
assert [opt.path() for opt in cfg.option('s1').list()] == ['s1.b']
|
||||
# assert not list_sessions()
|
||||
|
||||
|
||||
def test_symlink_submulti():
|
||||
def test_submulti():
|
||||
multi = StrOption('multi', '', multi=submulti)
|
||||
multi2 = SymLinkOption('multi2', multi)
|
||||
od1 = OptionDescription('od', '', [multi, multi2])
|
||||
|
@ -452,13 +400,3 @@ def test_symlink_submulti():
|
|||
assert cfg.option('multi').issubmulti()
|
||||
assert cfg.option('multi2').ismulti()
|
||||
assert cfg.option('multi2').issubmulti()
|
||||
|
||||
|
||||
def test_symlink_get_option():
|
||||
multi = StrOption('multi', '', multi=submulti)
|
||||
multi2 = SymLinkOption('multi2', multi)
|
||||
od1 = OptionDescription('od', '', [multi, multi2])
|
||||
cfg = Config(od1)
|
||||
option = cfg.option('multi2').option()
|
||||
assert option.name() == 'multi'
|
||||
assert option.path() == 'multi'
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright (C) 2012-2024 Team tiramisu (see AUTHORS for all contributors)
|
||||
# Copyright (C) 2012-2023 Team tiramisu (see AUTHORS for all contributors)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by the
|
||||
|
@ -14,29 +14,11 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""Configuration management library written in python
|
||||
"""
|
||||
from .function import (
|
||||
calc_value,
|
||||
calc_value_property_help,
|
||||
valid_ip_netmask,
|
||||
valid_network_netmask,
|
||||
valid_in_network,
|
||||
valid_broadcast,
|
||||
valid_not_equal,
|
||||
function_waiting_for_dict,
|
||||
function_waiting_for_error,
|
||||
)
|
||||
from .autolib import (
|
||||
Calculation,
|
||||
Params,
|
||||
ParamOption,
|
||||
ParamDynOption,
|
||||
ParamSelfOption,
|
||||
ParamValue,
|
||||
ParamIndex,
|
||||
ParamIdentifier,
|
||||
ParamInformation,
|
||||
ParamSelfInformation,
|
||||
)
|
||||
from .function import calc_value, calc_value_property_help, valid_ip_netmask, \
|
||||
valid_network_netmask, valid_in_network, valid_broadcast, \
|
||||
valid_not_equal, function_waiting_for_dict
|
||||
from .autolib import Calculation, Params, ParamOption, ParamDynOption, ParamSelfOption, \
|
||||
ParamValue, ParamIndex, ParamSuffix, ParamInformation, ParamSelfInformation
|
||||
from .option import *
|
||||
from .error import ConfigError
|
||||
from .api import Config, MetaConfig, GroupConfig, MixConfig
|
||||
|
@ -44,36 +26,34 @@ from .option import __all__ as all_options
|
|||
from .setting import owners, groups, undefined
|
||||
|
||||
|
||||
allfuncs = [
|
||||
"Calculation",
|
||||
"Params",
|
||||
"ParamOption",
|
||||
"ParamDynOption",
|
||||
"ParamSelfOption",
|
||||
"ParamValue",
|
||||
"ParamIndex",
|
||||
"ParamIdentifier",
|
||||
"ParamInformation",
|
||||
"ParamSelfInformation",
|
||||
"MetaConfig",
|
||||
"MixConfig",
|
||||
"GroupConfig",
|
||||
"Config",
|
||||
"ConfigError",
|
||||
"undefined",
|
||||
"owners",
|
||||
"groups",
|
||||
"calc_value",
|
||||
"calc_value_property_help",
|
||||
"valid_ip_netmask",
|
||||
"valid_network_netmask",
|
||||
"valid_in_network",
|
||||
"valid_broadcast",
|
||||
"function_waiting_for_dict",
|
||||
"function_waiting_for_error",
|
||||
]
|
||||
allfuncs = ['Calculation',
|
||||
'Params',
|
||||
'ParamOption',
|
||||
'ParamDynOption',
|
||||
'ParamSelfOption',
|
||||
'ParamValue',
|
||||
'ParamIndex',
|
||||
'ParamSuffix',
|
||||
'ParamInformation',
|
||||
'ParamSelfInformation',
|
||||
'MetaConfig',
|
||||
'MixConfig',
|
||||
'GroupConfig',
|
||||
'Config',
|
||||
'ConfigError',
|
||||
'undefined',
|
||||
'owners',
|
||||
'groups',
|
||||
'calc_value',
|
||||
'calc_value_property_help',
|
||||
'valid_ip_netmask',
|
||||
'valid_network_netmask',
|
||||
'valid_in_network',
|
||||
'valid_broadcast',
|
||||
'function_waiting_for_dict',
|
||||
]
|
||||
allfuncs.extend(all_options)
|
||||
del all_options
|
||||
del(all_options)
|
||||
__all__ = tuple(allfuncs)
|
||||
del allfuncs
|
||||
del(allfuncs)
|
||||
__version__ = "4.1.0"
|
||||
|
|
2043
tiramisu/api.py
2043
tiramisu/api.py
File diff suppressed because it is too large
Load diff
1008
tiramisu/autolib.py
1008
tiramisu/autolib.py
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"cache used by storage"
|
||||
# Copyright (C) 2013-2024 Team tiramisu (see AUTHORS for all contributors)
|
||||
# Copyright (C) 2013-2023 Team tiramisu (see AUTHORS for all contributors)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by the
|
||||
|
@ -19,9 +19,9 @@ from time import time
|
|||
|
||||
|
||||
class Cache:
|
||||
"""cache object"""
|
||||
|
||||
__slots__ = ("_cache",)
|
||||
"""cache object
|
||||
"""
|
||||
__slots__ = ('_cache',)
|
||||
|
||||
def __init__(self):
|
||||
self._cache = {}
|
||||
|
@ -35,30 +35,34 @@ class Cache:
|
|||
index = subconfig.index
|
||||
return path, index
|
||||
|
||||
def getcache(
|
||||
self,
|
||||
subconfig,
|
||||
type_,
|
||||
expiration=True,
|
||||
):
|
||||
"""get the cache value fot a specified path"""
|
||||
def getcache(self,
|
||||
subconfig,
|
||||
type_,
|
||||
expiration=True,
|
||||
):
|
||||
"""get the cache value fot a specified path
|
||||
"""
|
||||
no_cache = False, None, False
|
||||
path, index = self._get_path_index(subconfig)
|
||||
if path not in self._cache or index not in self._cache[path]:
|
||||
return no_cache
|
||||
value, timestamp, validated = self._cache[path][index]
|
||||
props = subconfig.config_bag.properties
|
||||
if type_ == "self_props":
|
||||
# cached value is self_props
|
||||
self_props = value
|
||||
if type_ == 'context_props':
|
||||
# cached value is settings properties so value is props
|
||||
props = value
|
||||
self_props = {}
|
||||
else:
|
||||
self_props = subconfig.properties
|
||||
if "cache" in props or "cache" in self_props:
|
||||
if (
|
||||
expiration
|
||||
and timestamp
|
||||
and ("expire" in props or "expire" in self_props)
|
||||
):
|
||||
props = subconfig.config_bag.properties
|
||||
if type_ == 'self_props':
|
||||
# cached value is self_props
|
||||
self_props = value
|
||||
else:
|
||||
self_props = subconfig.properties
|
||||
if 'cache' in props or \
|
||||
'cache' in self_props:
|
||||
if expiration and timestamp and \
|
||||
('expire' in props or \
|
||||
'expire' in self_props):
|
||||
ntime = int(time())
|
||||
if timestamp + subconfig.config_bag.expiration_time >= ntime:
|
||||
return True, value, validated
|
||||
|
@ -66,38 +70,37 @@ class Cache:
|
|||
return True, value, validated
|
||||
return no_cache
|
||||
|
||||
def setcache(
|
||||
self,
|
||||
subconfig,
|
||||
val,
|
||||
type_="values",
|
||||
validated=True,
|
||||
):
|
||||
def setcache(self,
|
||||
subconfig,
|
||||
val,
|
||||
type_='values',
|
||||
validated=True,
|
||||
):
|
||||
"""add val in cache for a specified path
|
||||
if follower, add index
|
||||
"""
|
||||
if type_ == "values":
|
||||
if (
|
||||
"cache" not in subconfig.config_bag.properties
|
||||
and "cache" not in subconfig.properties
|
||||
):
|
||||
if type_ == 'values':
|
||||
if 'cache' not in subconfig.config_bag.properties and \
|
||||
'cache' not in subconfig.properties:
|
||||
return
|
||||
elif (
|
||||
subconfig is None or "cache" not in subconfig.config_bag.properties
|
||||
) and "cache" not in val:
|
||||
elif (subconfig is None or 'cache' not in subconfig.config_bag.properties) and \
|
||||
'cache' not in val:
|
||||
return
|
||||
path, index = self._get_path_index(subconfig)
|
||||
self._cache.setdefault(path, {})[index] = (val, int(time()), validated)
|
||||
|
||||
def delcache(self, path):
|
||||
"""reset cache a a specified path"""
|
||||
if path in self._cache:
|
||||
"""reset cache a a specified path
|
||||
"""
|
||||
if path in self._cache:
|
||||
del self._cache[path]
|
||||
|
||||
def get_cached(self):
|
||||
"""get cache values"""
|
||||
"""get cache values
|
||||
"""
|
||||
return self._cache
|
||||
|
||||
def reset_all_cache(self):
|
||||
"""reset all cache values"""
|
||||
"""reset all cache values
|
||||
"""
|
||||
self._cache.clear()
|
||||
|
|
1971
tiramisu/config.py
1971
tiramisu/config.py
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2012-2024 Team tiramisu (see AUTHORS for all contributors)
|
||||
# Copyright (C) 2012-2023 Team tiramisu (see AUTHORS for all contributors)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by the
|
||||
|
@ -19,18 +19,13 @@ import weakref
|
|||
from .i18n import _
|
||||
|
||||
|
||||
def display_list(
|
||||
lst,
|
||||
*,
|
||||
separator="and",
|
||||
add_quote=False,
|
||||
) -> str():
|
||||
def display_list(lst, separator='and', add_quote=False):
|
||||
if not lst:
|
||||
return '""'
|
||||
if separator == "and":
|
||||
separator = _("and")
|
||||
elif separator == "or":
|
||||
separator = _("or")
|
||||
if separator == 'and':
|
||||
separator = _('and')
|
||||
elif separator == 'or':
|
||||
separator = _('or')
|
||||
if isinstance(lst, tuple) or isinstance(lst, frozenset):
|
||||
lst = list(lst)
|
||||
if len(lst) == 1:
|
||||
|
@ -52,37 +47,31 @@ def display_list(
|
|||
lst__.append(l)
|
||||
lst__.sort()
|
||||
last = lst__[-1]
|
||||
return ", ".join(lst__[:-1]) + _(" {} ").format(separator) + "{}".format(last)
|
||||
return ', '.join(lst__[:-1]) + _(' {} ').format(separator) + '{}'.format(last)
|
||||
|
||||
|
||||
# Exceptions for an Option
|
||||
class PropertiesOptionError(AttributeError):
|
||||
"attempt to access to an option with a property that is not allowed"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
subconfig,
|
||||
proptype,
|
||||
settings,
|
||||
opt_type=None,
|
||||
name=None,
|
||||
orig_opt=None,
|
||||
help_properties=None,
|
||||
):
|
||||
def __init__(self,
|
||||
subconfig,
|
||||
proptype,
|
||||
settings,
|
||||
opt_type=None,
|
||||
name=None,
|
||||
orig_opt=None,
|
||||
help_properties=None):
|
||||
if opt_type:
|
||||
self._opt_type = opt_type
|
||||
self._name = name
|
||||
self._orig_opt = orig_opt
|
||||
else:
|
||||
if subconfig.option.impl_is_optiondescription():
|
||||
self._opt_type = "optiondescription"
|
||||
self._opt_type = 'optiondescription'
|
||||
else:
|
||||
self._opt_type = "option"
|
||||
self._name = subconfig.option.impl_get_display_name(
|
||||
subconfig, with_quote=True
|
||||
)
|
||||
self._opt_type = 'option'
|
||||
self._name = subconfig.option.impl_get_display_name()
|
||||
self._orig_opt = None
|
||||
self._subconfig = subconfig
|
||||
self.proptype = proptype
|
||||
self.help_properties = help_properties
|
||||
self._settings = settings
|
||||
|
@ -97,7 +86,7 @@ class PropertiesOptionError(AttributeError):
|
|||
if self.msg is not None:
|
||||
return self.msg
|
||||
if self._settings is None:
|
||||
return "error"
|
||||
return 'error'
|
||||
if self.help_properties:
|
||||
properties = list(self.help_properties)
|
||||
else:
|
||||
|
@ -105,47 +94,45 @@ class PropertiesOptionError(AttributeError):
|
|||
only_one = len(properties) == 1
|
||||
properties_msg = display_list(properties, add_quote=True)
|
||||
if only_one:
|
||||
prop_msg = _("property")
|
||||
prop_msg = _('property')
|
||||
else:
|
||||
prop_msg = _("properties")
|
||||
if properties == ["frozen"]:
|
||||
prop_msg = _('properties')
|
||||
if properties == ['frozen']:
|
||||
if self._orig_opt:
|
||||
msg = _('cannot modify the {0} {1} because "{2}" has {3} {4}')
|
||||
msg = 'cannot modify the {0} "{1}" because "{2}" has {3} {4}'
|
||||
else:
|
||||
msg = _("cannot modify the {0} {1} because has {2} {3}")
|
||||
msg = 'cannot modify the {0} "{1}" because has {2} {3}'
|
||||
else:
|
||||
if self._orig_opt:
|
||||
msg = _('cannot access to {0} {1} because "{2}" has {3} {4}')
|
||||
msg = 'cannot access to {0} "{1}" because "{2}" has {3} {4}'
|
||||
else:
|
||||
msg = _("cannot access to {0} {1} because has {2} {3}")
|
||||
msg = 'cannot access to {0} "{1}" because has {2} {3}'
|
||||
if self._orig_opt:
|
||||
# FIXME _orig_opt ?
|
||||
self.msg = msg.format(
|
||||
self._opt_type,
|
||||
self._orig_opt.impl_get_display_name(subconfig, with_quote=True),
|
||||
self._name,
|
||||
prop_msg,
|
||||
properties_msg,
|
||||
)
|
||||
self.msg = _(msg).format(self._opt_type,
|
||||
self._orig_opt.impl_get_display_name(),
|
||||
self._name,
|
||||
prop_msg,
|
||||
properties_msg)
|
||||
else:
|
||||
self.msg = msg.format(self._opt_type, self._name, prop_msg, properties_msg)
|
||||
self.msg = _(msg).format(self._opt_type,
|
||||
self._name,
|
||||
prop_msg,
|
||||
properties_msg)
|
||||
del self._opt_type, self._name
|
||||
del self._settings, self._orig_opt
|
||||
return self.msg
|
||||
|
||||
|
||||
# ____________________________________________________________
|
||||
#____________________________________________________________
|
||||
# Exceptions for a Config
|
||||
class ConfigError(Exception):
|
||||
"""attempt to change an option's owner without a value
|
||||
or in case of `_descr` is None
|
||||
or if a calculation cannot be carried out"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
exp,
|
||||
ori_err=None,
|
||||
):
|
||||
def __init__(self,
|
||||
exp,
|
||||
ori_err=None,
|
||||
):
|
||||
super().__init__(exp)
|
||||
self.ori_err = ori_err
|
||||
|
||||
|
@ -155,8 +142,8 @@ class ConflictError(Exception):
|
|||
pass
|
||||
|
||||
|
||||
# ____________________________________________________________
|
||||
# miscellaneous exceptions
|
||||
#____________________________________________________________
|
||||
# miscellaneous exceptions
|
||||
class LeadershipError(Exception):
|
||||
"problem with a leadership's value length"
|
||||
pass
|
||||
|
@ -168,11 +155,16 @@ class ConstError(TypeError):
|
|||
|
||||
|
||||
class _CommonError:
|
||||
def __init__(self, subconfig, val, display_type, opt, err_msg, index):
|
||||
def __init__(self,
|
||||
val,
|
||||
display_type,
|
||||
opt,
|
||||
err_msg,
|
||||
index):
|
||||
self.val = val
|
||||
self.display_type = display_type
|
||||
self.opt = weakref.ref(opt)
|
||||
self.name = opt.impl_get_display_name(subconfig)
|
||||
self.name = opt.impl_get_display_name()
|
||||
self.err_msg = err_msg
|
||||
self.index = index
|
||||
super().__init__(self.err_msg)
|
||||
|
@ -181,24 +173,24 @@ class _CommonError:
|
|||
try:
|
||||
msg = self.prefix
|
||||
except AttributeError:
|
||||
self.prefix = self.tmpl.format(self.val, _(self.display_type), self.name)
|
||||
self.prefix = self.tmpl.format(self.val,
|
||||
self.display_type,
|
||||
self.name)
|
||||
msg = self.prefix
|
||||
if self.err_msg:
|
||||
if msg:
|
||||
msg += ", {}".format(self.err_msg)
|
||||
msg += ', {}'.format(self.err_msg)
|
||||
else:
|
||||
msg = self.err_msg
|
||||
if not msg:
|
||||
msg = _("invalid value")
|
||||
msg = _('invalid value')
|
||||
return msg
|
||||
|
||||
|
||||
class ValueWarning(_CommonError, UserWarning):
|
||||
tmpl = None
|
||||
tmpl = _('attention, "{0}" could be an invalid {1} for "{2}"')
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
if ValueWarning.tmpl is None:
|
||||
ValueWarning.tmpl = _('attention, "{0}" could be an invalid {1} for "{2}"')
|
||||
if len(args) == 1 and not kwargs:
|
||||
self.msg = args[0]
|
||||
else:
|
||||
|
@ -212,18 +204,8 @@ class ValueWarning(_CommonError, UserWarning):
|
|||
|
||||
|
||||
class ValueOptionError(_CommonError, ValueError):
|
||||
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)
|
||||
tmpl = _('"{0}" is an invalid {1} for "{2}"')
|
||||
|
||||
|
||||
class ValueErrorWarning(ValueWarning):
|
||||
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)
|
||||
tmpl = _('"{0}" is an invalid {1} for "{2}"')
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright (C) 2018-2024 Team tiramisu (see AUTHORS for all contributors)
|
||||
# Copyright (C) 2018-2023 Team tiramisu (see AUTHORS for all contributors)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by the
|
||||
|
@ -23,7 +23,6 @@ from .error import display_list
|
|||
|
||||
|
||||
FUNCTION_WAITING_FOR_DICT = []
|
||||
FUNCTION_WAITING_FOR_ERROR = []
|
||||
|
||||
|
||||
def function_waiting_for_dict(function):
|
||||
|
@ -37,94 +36,74 @@ def function_waiting_for_dict(function):
|
|||
return function
|
||||
|
||||
|
||||
def function_waiting_for_error(function):
|
||||
"""functions (calculation or validation) receive by default only the value of other options
|
||||
set PropertyError too
|
||||
"""
|
||||
name = function.__name__
|
||||
if name not in FUNCTION_WAITING_FOR_ERROR:
|
||||
FUNCTION_WAITING_FOR_ERROR.append(name)
|
||||
return function
|
||||
|
||||
|
||||
@function_waiting_for_dict
|
||||
def valid_network_netmask(
|
||||
network: dict,
|
||||
netmask: dict,
|
||||
):
|
||||
def valid_network_netmask(network: dict,
|
||||
netmask: dict,
|
||||
):
|
||||
"""
|
||||
validates if network and netmask are coherent
|
||||
this validator must be set to netmask option
|
||||
"""
|
||||
if None in [network["value"], netmask["value"]]:
|
||||
if None in [network['value'], netmask['value']]:
|
||||
return
|
||||
try:
|
||||
ip_network(f'{network["value"]}/{netmask["value"]}')
|
||||
except ValueError as err:
|
||||
raise ValueError(
|
||||
_('network "{0}" ({1}) does not match with this netmask').format(
|
||||
network["value"], network["name"]
|
||||
)
|
||||
) from err
|
||||
raise ValueError(_(f'network "{network["value"]}" ({network["name"]}) does not match '
|
||||
'with this netmask')) from err
|
||||
|
||||
|
||||
@function_waiting_for_dict
|
||||
def valid_ip_netmask(
|
||||
ip: dict, # pylint: disable=invalid-name
|
||||
netmask: dict,
|
||||
):
|
||||
def valid_ip_netmask(ip: dict, # pylint: disable=invalid-name
|
||||
netmask: dict,
|
||||
):
|
||||
"""validates if ip and netmask are coherent
|
||||
this validator must be set to netmask option
|
||||
"""
|
||||
if None in [ip["value"], netmask["value"]]:
|
||||
if None in [ip['value'], netmask['value']]:
|
||||
return
|
||||
ip_netmask = ip_interface(f'{ip["value"]}/{netmask["value"]}')
|
||||
if ip_netmask.ip == ip_netmask.network.network_address:
|
||||
msg = _('IP "{0}" ({1}) with this netmask is in fact a network address').format(
|
||||
ip["value"], ip["name"]
|
||||
)
|
||||
msg = _(f'IP "{ip["value"]}" ({ip["name"]}) with this netmask is '
|
||||
'in fact a network address')
|
||||
raise ValueError(msg)
|
||||
if ip_netmask.ip == ip_netmask.network.broadcast_address:
|
||||
msg = _(
|
||||
'IP "{0}" ({1}) with this netmask is in fact a broadcast address'
|
||||
).format(ip["value"], ip["name"])
|
||||
msg = _(f'IP "{ip["value"]}" ({ip["name"]}) with this netmask is '
|
||||
'in fact a broacast address')
|
||||
raise ValueError(msg)
|
||||
|
||||
|
||||
@function_waiting_for_dict
|
||||
def valid_broadcast(
|
||||
network: dict,
|
||||
netmask: dict,
|
||||
broadcast: dict,
|
||||
):
|
||||
"""validates if the broadcast is coherent with network and netmask"""
|
||||
if None in [network["value"], netmask["value"], broadcast["value"]]:
|
||||
def valid_broadcast(network: dict,
|
||||
netmask: dict,
|
||||
broadcast: dict,
|
||||
):
|
||||
"""validates if the broadcast is coherent with network and netmask
|
||||
"""
|
||||
if None in [network['value'], netmask['value'], broadcast['value']]:
|
||||
return
|
||||
if ip_network(
|
||||
f'{network["value"]}/{netmask["value"]}'
|
||||
).broadcast_address != ip_address(broadcast["value"]):
|
||||
msg = _(
|
||||
"broadcast invalid with network {0} ({1}) and netmask {2} ({3})"
|
||||
).format(network["value"], network["name"], netmask["value"], netmask["name"])
|
||||
if ip_network(f'{network["value"]}/{netmask["value"]}').broadcast_address != \
|
||||
ip_address(broadcast['value']):
|
||||
msg = _(f'broadcast invalid with network {network["value"]} ({network["name"]}) '
|
||||
f'and netmask {netmask["value"]} ({netmask["name"]})')
|
||||
raise ValueError(msg)
|
||||
|
||||
|
||||
@function_waiting_for_dict
|
||||
def valid_in_network(
|
||||
ip: dict, # pylint: disable=invalid-name
|
||||
network: dict,
|
||||
netmask=Optional[dict],
|
||||
):
|
||||
def valid_in_network(ip: dict, # pylint: disable=invalid-name
|
||||
network: dict,
|
||||
netmask=Optional[dict],
|
||||
):
|
||||
"""validates if an IP is in a network
|
||||
this validator must be set to ip option
|
||||
"""
|
||||
if None in [ip["value"], network["value"]]:
|
||||
if None in [ip['value'], network['value']]:
|
||||
return
|
||||
if "/" in network["value"]:
|
||||
if '/' in network['value']:
|
||||
# it's a CIDR network
|
||||
network_value = network["value"]
|
||||
network_value = network['value']
|
||||
else:
|
||||
if netmask is None or netmask["value"] is None:
|
||||
if netmask is None or netmask['value'] is None:
|
||||
return
|
||||
network_value = f'{network["value"]}/{netmask["value"]}'
|
||||
network_obj = ip_network(network_value)
|
||||
|
@ -133,63 +112,56 @@ def valid_in_network(
|
|||
if netmask is None:
|
||||
msg = _('this IP is not in network {network["value"]} ({network["name"]})')
|
||||
else:
|
||||
msg = _(
|
||||
'this IP is not in network {network["value"]} ({network["name"]}) '
|
||||
'with netmask {netmask["value"]} ({netmask["name"]})'
|
||||
)
|
||||
msg = _('this IP is not in network {network["value"]} ({network["name"]}) '
|
||||
'with netmask {netmask["value"]} ({netmask["name"]})')
|
||||
raise ValueError(msg)
|
||||
# test if ip is not network/broadcast IP
|
||||
if ip_netmask.ip == ip_netmask.network.network_address:
|
||||
msg = _(
|
||||
"this IP with the network {0} ({1}) is in fact a network address"
|
||||
).format(network["value"], network["name"])
|
||||
msg = _(f'this IP with the network {network["value"]} ({network["value"]} '
|
||||
'is in fact a network address')
|
||||
raise ValueError(msg)
|
||||
if ip_netmask.ip == ip_netmask.network.broadcast_address:
|
||||
msg = _(
|
||||
"this IP with the network {0} ({1}) is in fact a broadcast address"
|
||||
).format(network["value"], network["value"])
|
||||
msg = _(f'this IP with the network {network["value"]} ({network["value"]} '
|
||||
'is in fact a broadcast address')
|
||||
raise ValueError(msg)
|
||||
|
||||
|
||||
@function_waiting_for_dict
|
||||
def valid_not_equal(*values):
|
||||
"""valid that two options have not same value"""
|
||||
"""valid that two options have not same value
|
||||
"""
|
||||
equal = set()
|
||||
for val in values[1:]:
|
||||
if "propertyerror" in val:
|
||||
if 'propertyerror' in val:
|
||||
continue
|
||||
if values[0]["value"] == val["value"] is not None:
|
||||
equal.add(val["name"])
|
||||
if values[0]['value'] == val['value'] is not None:
|
||||
equal.add(val['name'])
|
||||
if not equal:
|
||||
return
|
||||
msg = _("value is identical to {0}").format(
|
||||
display_list(list(equal), add_quote=True)
|
||||
)
|
||||
msg = _(f'value is identical to {display_list(list(equal), add_quote=True)}')
|
||||
raise ValueError(msg)
|
||||
|
||||
|
||||
class CalcValue:
|
||||
"""class to calc_value with different functions"""
|
||||
|
||||
"""class to calc_value with different functions
|
||||
"""
|
||||
# pylint: disable=too-many-instance-attributes
|
||||
def __call__(
|
||||
self,
|
||||
*args: List[Any],
|
||||
multi: bool = False,
|
||||
default: Any = undefined,
|
||||
condition: Any = undefined,
|
||||
no_condition_is_invalid: bool = False,
|
||||
expected: Any = undefined,
|
||||
condition_operator: str = "AND",
|
||||
reverse_condition: bool = False,
|
||||
allow_none: bool = False,
|
||||
remove_duplicate_value: bool = False,
|
||||
join: Optional[str] = None,
|
||||
min_args_len: Optional[int] = None,
|
||||
operator: Optional[str] = None,
|
||||
index: Optional[int] = None,
|
||||
**kwargs,
|
||||
) -> Any:
|
||||
def __call__(self,
|
||||
*args: List[Any],
|
||||
multi: bool=False,
|
||||
default: Any=undefined,
|
||||
condition: Any=undefined,
|
||||
no_condition_is_invalid: bool=False,
|
||||
expected: Any=undefined,
|
||||
condition_operator: str='AND',
|
||||
reverse_condition: bool=False,
|
||||
allow_none: bool=False,
|
||||
remove_duplicate_value: bool=False,
|
||||
join: Optional[str]=None,
|
||||
min_args_len: Optional[int]=None,
|
||||
operator: Optional[str]=None,
|
||||
index: Optional[int]=None,
|
||||
**kwargs) -> Any:
|
||||
# pylint: disable=too-many-statements,too-many-branches,too-many-nested-blocks,too-many-locals
|
||||
"""calculate value
|
||||
:param args: list of value
|
||||
|
@ -353,13 +325,10 @@ class CalcValue:
|
|||
self.condition_operator = condition_operator
|
||||
self.reverse_condition = reverse_condition
|
||||
self.kwargs = kwargs
|
||||
self.no_condition_is_invalid = (
|
||||
no_condition_is_invalid # pylint: disable=attribute-defined-outside-init
|
||||
)
|
||||
value = self.get_value(
|
||||
default,
|
||||
min_args_len,
|
||||
)
|
||||
self.no_condition_is_invalid = no_condition_is_invalid # pylint: disable=attribute-defined-outside-init
|
||||
value = self.get_value(default,
|
||||
min_args_len,
|
||||
)
|
||||
if not multi:
|
||||
if join is not None:
|
||||
if None not in value:
|
||||
|
@ -368,12 +337,11 @@ class CalcValue:
|
|||
value = None
|
||||
elif value and operator:
|
||||
new_value = value[0]
|
||||
oper = {
|
||||
"mul": mul,
|
||||
"add": add,
|
||||
"div": truediv,
|
||||
"sub": sub,
|
||||
}[operator]
|
||||
oper = {'mul': mul,
|
||||
'add': add,
|
||||
'div': truediv,
|
||||
'sub': sub,
|
||||
}[operator]
|
||||
for val in value[1:]:
|
||||
new_value = oper(new_value, val)
|
||||
value = new_value
|
||||
|
@ -397,9 +365,8 @@ class CalcValue:
|
|||
break
|
||||
lval = len(val)
|
||||
if length_val is not None and length_val != lval:
|
||||
msg = _(
|
||||
'unexpected value in calc_value with join attribute "{0}" with invalid length "{1}"'
|
||||
).format(val, length_val)
|
||||
msg = _('unexpected value in calc_value with join attribute '
|
||||
f'"{val}" with invalid length "{length_val}"')
|
||||
raise ValueError(msg)
|
||||
length_val = lval
|
||||
new_value = []
|
||||
|
@ -425,16 +392,19 @@ class CalcValue:
|
|||
value = new_value
|
||||
return value
|
||||
|
||||
def value_from_kwargs(
|
||||
self, value: Any, pattern: str, to_dict: bool = False, empty_test=undefined
|
||||
) -> Any:
|
||||
"""get value from kwargs"""
|
||||
def value_from_kwargs(self,
|
||||
value: Any,
|
||||
pattern: str,
|
||||
to_dict: bool=False,
|
||||
empty_test=undefined) -> Any:
|
||||
"""get value from kwargs
|
||||
"""
|
||||
# pylint: disable=too-many-branches
|
||||
# if value attribute exist return it's value
|
||||
# otherwise pattern_0, pattern_1, ...
|
||||
# otherwise undefined
|
||||
if value is not empty_test:
|
||||
if to_dict == "all":
|
||||
if to_dict == 'all':
|
||||
returns = {None: value}
|
||||
else:
|
||||
returns = value
|
||||
|
@ -445,7 +415,7 @@ class CalcValue:
|
|||
if key.startswith(pattern):
|
||||
index = int(key[len_pattern:])
|
||||
if isinstance(pattern_value, dict):
|
||||
pattern_value = pattern_value["value"]
|
||||
pattern_value = pattern_value['value']
|
||||
kwargs_matches[index] = pattern_value
|
||||
if not kwargs_matches:
|
||||
returns = undefined
|
||||
|
@ -462,47 +432,38 @@ class CalcValue:
|
|||
returns.append(kwargs_matches[key])
|
||||
return returns
|
||||
|
||||
def is_condition_matches(
|
||||
self,
|
||||
condition_value,
|
||||
):
|
||||
"""verify the condition"""
|
||||
def is_condition_matches(self,
|
||||
condition_value,
|
||||
):
|
||||
"""verify the condition
|
||||
"""
|
||||
# pylint: disable=too-many-branches
|
||||
calculated_conditions = self.value_from_kwargs(
|
||||
condition_value,
|
||||
"condition_",
|
||||
to_dict="all",
|
||||
)
|
||||
calculated_conditions = self.value_from_kwargs(condition_value,
|
||||
'condition_',
|
||||
to_dict='all',
|
||||
)
|
||||
if calculated_conditions is undefined:
|
||||
is_matches = not self.no_condition_is_invalid
|
||||
else:
|
||||
is_matches = None
|
||||
calculated_expected = self.value_from_kwargs(
|
||||
self.expected,
|
||||
"expected_",
|
||||
to_dict=True,
|
||||
)
|
||||
calculated_reverse = self.value_from_kwargs(
|
||||
self.reverse_condition,
|
||||
"reverse_condition_",
|
||||
to_dict=True,
|
||||
empty_test=False,
|
||||
)
|
||||
calculated_expected = self.value_from_kwargs(self.expected,
|
||||
'expected_',
|
||||
to_dict=True,
|
||||
)
|
||||
calculated_reverse = self.value_from_kwargs(self.reverse_condition,
|
||||
'reverse_condition_',
|
||||
to_dict=True,
|
||||
empty_test=False,
|
||||
)
|
||||
for idx, calculated_condition in calculated_conditions.items():
|
||||
if isinstance(calculated_expected, dict):
|
||||
if idx is not None:
|
||||
if isinstance(calculated_expected[idx], list):
|
||||
current_matches = (
|
||||
calculated_condition in calculated_expected[idx]
|
||||
)
|
||||
current_matches = calculated_condition in calculated_expected[idx]
|
||||
else:
|
||||
current_matches = (
|
||||
calculated_condition == calculated_expected[idx]
|
||||
)
|
||||
current_matches = calculated_condition == calculated_expected[idx]
|
||||
else:
|
||||
current_matches = (
|
||||
calculated_condition in calculated_expected.values()
|
||||
)
|
||||
current_matches = calculated_condition in calculated_expected.values()
|
||||
else:
|
||||
current_matches = calculated_condition == calculated_expected
|
||||
if isinstance(calculated_reverse, dict) and idx in calculated_reverse:
|
||||
|
@ -511,41 +472,36 @@ class CalcValue:
|
|||
reverse_condition = False
|
||||
if is_matches is None:
|
||||
is_matches = current_matches
|
||||
if self.condition_operator == "AND":
|
||||
if self.condition_operator == 'AND':
|
||||
is_matches = is_matches and current_matches
|
||||
if reverse_condition:
|
||||
is_matches = not is_matches
|
||||
if not is_matches:
|
||||
break
|
||||
elif self.condition_operator == "OR":
|
||||
elif self.condition_operator == 'OR':
|
||||
is_matches = is_matches or current_matches
|
||||
if reverse_condition:
|
||||
is_matches = not is_matches
|
||||
if is_matches:
|
||||
break
|
||||
else:
|
||||
msg = _(
|
||||
"unexpected {0} condition_operator " "in calc_value"
|
||||
).format(self.condition_operator)
|
||||
msg = _(f'unexpected {self.condition_operator} condition_operator '
|
||||
'in calc_value')
|
||||
raise ValueError(msg)
|
||||
is_matches = (
|
||||
is_matches
|
||||
and not self.reverse_condition
|
||||
or not is_matches
|
||||
and self.reverse_condition
|
||||
)
|
||||
is_matches = is_matches and not self.reverse_condition \
|
||||
or not is_matches and self.reverse_condition
|
||||
return is_matches
|
||||
|
||||
def get_value(
|
||||
self,
|
||||
default,
|
||||
min_args_len,
|
||||
):
|
||||
"""get the value from arguments"""
|
||||
def get_value(self,
|
||||
default,
|
||||
min_args_len,
|
||||
):
|
||||
"""get the value from arguments
|
||||
"""
|
||||
# retrieve the condition
|
||||
if isinstance(self.condition, dict):
|
||||
if "value" in self.condition:
|
||||
condition_value = self.condition["value"]
|
||||
if 'value' in self.condition:
|
||||
condition_value = self.condition['value']
|
||||
else:
|
||||
condition_value = undefined
|
||||
else:
|
||||
|
@ -560,10 +516,9 @@ class CalcValue:
|
|||
value = []
|
||||
if not value:
|
||||
# default value
|
||||
new_default = self.value_from_kwargs(
|
||||
default,
|
||||
"default_",
|
||||
)
|
||||
new_default = self.value_from_kwargs(default,
|
||||
'default_',
|
||||
)
|
||||
if new_default is not undefined:
|
||||
if not isinstance(new_default, list):
|
||||
value = [new_default]
|
||||
|
@ -572,32 +527,34 @@ class CalcValue:
|
|||
return value
|
||||
|
||||
def get_args(self):
|
||||
"""get all arguments"""
|
||||
"""get all arguments
|
||||
"""
|
||||
return list(self.args)
|
||||
|
||||
|
||||
class CalcValuePropertyHelp(CalcValue):
|
||||
"""special class to display property error"""
|
||||
|
||||
"""special class to display property error
|
||||
"""
|
||||
def get_name(self):
|
||||
"""get the condition name"""
|
||||
return self.condition["name"]
|
||||
"""get the condition name
|
||||
"""
|
||||
return self.condition['name']
|
||||
|
||||
def get_indexed_name(self, index: int) -> str:
|
||||
"""get name for a specified index"""
|
||||
condition_index = self.kwargs.get(f"condition_{index}")
|
||||
"""get name for a specified index
|
||||
"""
|
||||
condition_index = self.kwargs.get(f'condition_{index}')
|
||||
if condition_index is not None and not isinstance(condition_index, dict):
|
||||
raise ValueError(
|
||||
_('unexpected condition_{0} must have "todict" argument').format(index)
|
||||
)
|
||||
return condition_index["name"]
|
||||
raise ValueError(_(f'unexpected condition_{index} must have "todict" argument'))
|
||||
return condition_index['name']
|
||||
|
||||
def build_property_message(
|
||||
self,
|
||||
name: str,
|
||||
value: Any,
|
||||
) -> str:
|
||||
"""prepare message to display error message if needed"""
|
||||
|
||||
def build_property_message(self,
|
||||
name: str,
|
||||
value: Any,
|
||||
) -> str:
|
||||
"""prepare message to display error message if needed
|
||||
"""
|
||||
if not self.reverse_condition:
|
||||
msg = _('the value of "{0}" is {1}').format(name, value)
|
||||
else:
|
||||
|
@ -607,36 +564,34 @@ class CalcValuePropertyHelp(CalcValue):
|
|||
def get_args(self):
|
||||
args = super().get_args()
|
||||
action = args[0]
|
||||
calculated_expected = self.value_from_kwargs(
|
||||
self.expected, "expected_", to_dict=True
|
||||
)
|
||||
calculated_expected = self.value_from_kwargs(self.expected,
|
||||
'expected_',
|
||||
to_dict=True)
|
||||
if self.condition is not undefined:
|
||||
if "propertyerror" in self.condition:
|
||||
msg = self.condition["propertyerror"]
|
||||
if 'propertyerror' in self.condition:
|
||||
msg = self.condition['propertyerror']
|
||||
else:
|
||||
name = self.get_name()
|
||||
if isinstance(calculated_expected, dict):
|
||||
calc_values = calculated_expected.values()
|
||||
else:
|
||||
calc_values = [calculated_expected]
|
||||
display_value = display_list(
|
||||
[str(val) for val in calc_values], separator="or", add_quote=True
|
||||
)
|
||||
display_value = display_list([str(val) for val in calc_values],
|
||||
'or',
|
||||
add_quote=True)
|
||||
msg = self.build_property_message(name, display_value)
|
||||
else:
|
||||
msgs = []
|
||||
for key, value in calculated_expected.items():
|
||||
name = self.get_indexed_name(key)
|
||||
msgs.append(self.build_property_message(name, f'"{value}"'))
|
||||
msg = display_list(msgs, separator=self.condition_operator.lower())
|
||||
msg = display_list(msgs, self.condition_operator.lower())
|
||||
return [(action, f'"{action}" ({msg})')]
|
||||
|
||||
|
||||
calc_value = CalcValue()
|
||||
calc_value.__name__ = "calc_value" # pylint: disable=attribute-defined-outside-init
|
||||
calc_value.__name__ = 'calc_value' # pylint: disable=attribute-defined-outside-init
|
||||
# function_waiting_for_dict(calc_value)
|
||||
calc_value_property_help = CalcValuePropertyHelp()
|
||||
calc_value_property_help.__name__ = (
|
||||
"calc_value_property_help" # pylint: disable=attribute-defined-outside-init
|
||||
)
|
||||
calc_value_property_help.__name__ = 'calc_value_property_help' # pylint: disable=attribute-defined-outside-init
|
||||
function_waiting_for_dict(calc_value_property_help)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -*- coding: UTF-8 -*-
|
||||
# Copyright (C) 2012-2024 Team tiramisu (see AUTHORS for all contributors)
|
||||
# Copyright (C) 2012-2023 Team tiramisu (see AUTHORS for all contributors)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by the
|
||||
|
@ -18,9 +18,55 @@
|
|||
# the rough gus of pypy: pypy: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||
# the whole pypy projet is under MIT licence
|
||||
"internationalisation utilities"
|
||||
from gettext import translation
|
||||
from pathlib import Path
|
||||
from .log import log
|
||||
|
||||
t = translation("tiramisu", str(Path(__file__).parent / "locale"), fallback=True)
|
||||
from gettext import translation, NullTranslations
|
||||
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()
|
||||
|
|
Binary file not shown.
1192
tiramisu/locale/fr/LC_MESSAGES/tiramisu.po
Normal file
1192
tiramisu/locale/fr/LC_MESSAGES/tiramisu.po
Normal file
File diff suppressed because it is too large
Load diff
711
tiramisu/locale/tiramisu.pot
Normal file
711
tiramisu/locale/tiramisu.pot
Normal file
|
@ -0,0 +1,711 @@
|
|||
# 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 "suffixes in dynoptiondescription has to be a calculation"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/dynoptiondescription.py:109
|
||||
msgid "invalid suffix \"{}\" 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()}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/value.py:695
|
||||
msgid "information's item not found: {0}"
|
||||
msgstr ""
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"logger for tiramisu"
|
||||
# Copyright (C) 2019-2024 Team tiramisu (see AUTHORS for all contributors)
|
||||
# Copyright (C) 2019-2023 Team tiramisu (see AUTHORS for all contributors)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by the
|
||||
|
@ -19,12 +19,12 @@ from logging import getLogger, DEBUG, StreamHandler, Formatter
|
|||
import os
|
||||
|
||||
|
||||
log = getLogger("tiramisu")
|
||||
if os.environ.get("TIRAMISU_DEBUG") == "True": # pragma: no cover
|
||||
log = getLogger('tiramisu')
|
||||
if os.environ.get('TIRAMISU_DEBUG') == 'True': # pragma: no cover
|
||||
log.setLevel(DEBUG)
|
||||
handler = StreamHandler()
|
||||
handler.setLevel(DEBUG)
|
||||
formatter = Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
|
||||
formatter = Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||
handler.setFormatter(formatter)
|
||||
|
||||
log.addHandler(handler)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2014-2024 Team tiramisu (see AUTHORS for all contributors)
|
||||
# Copyright (C) 2014-2023 Team tiramisu (see AUTHORS for all contributors)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by the
|
||||
|
@ -25,8 +25,7 @@ from .dynoptiondescription import DynOptionDescription
|
|||
from .leadership import Leadership
|
||||
from .baseoption import submulti
|
||||
from .symlinkoption import SymLinkOption
|
||||
|
||||
# from .syndynoption import SynDynOption, SynDynOptionDescription, SynDynLeadership
|
||||
#from .syndynoption import SynDynOption, SynDynOptionDescription, SynDynLeadership
|
||||
from .option import Option
|
||||
from .choiceoption import ChoiceOption
|
||||
from .booloption import BoolOption
|
||||
|
@ -49,33 +48,12 @@ from .macoption import MACOption
|
|||
from .permissionsoption import PermissionsOption
|
||||
|
||||
|
||||
__all__ = (
|
||||
"Leadership",
|
||||
"OptionDescription",
|
||||
"DynOptionDescription",
|
||||
# 'SynDynOptionDescription', 'SynDynLeadership','SynDynOption',
|
||||
"Option",
|
||||
"SymLinkOption",
|
||||
"ChoiceOption",
|
||||
"BoolOption",
|
||||
"DateOption",
|
||||
"IntOption",
|
||||
"FloatOption",
|
||||
"StrOption",
|
||||
"IPOption",
|
||||
"PortOption",
|
||||
"NetworkOption",
|
||||
"NetmaskOption",
|
||||
"BroadcastOption",
|
||||
"DomainnameOption",
|
||||
"EmailOption",
|
||||
"URLOption",
|
||||
"UsernameOption",
|
||||
"GroupnameOption",
|
||||
"FilenameOption",
|
||||
"PasswordOption",
|
||||
"submulti",
|
||||
"RegexpOption",
|
||||
"MACOption",
|
||||
"PermissionsOption",
|
||||
)
|
||||
__all__ = ('Leadership', 'OptionDescription', 'DynOptionDescription',
|
||||
# 'SynDynOptionDescription', 'SynDynLeadership','SynDynOption',
|
||||
'Option', 'SymLinkOption',
|
||||
'ChoiceOption', 'BoolOption', 'DateOption',
|
||||
'IntOption', 'FloatOption', 'StrOption',
|
||||
'IPOption', 'PortOption', 'NetworkOption', 'NetmaskOption',
|
||||
'BroadcastOption', 'DomainnameOption', 'EmailOption', 'URLOption',
|
||||
'UsernameOption', 'GroupnameOption', 'FilenameOption', 'PasswordOption', 'submulti',
|
||||
'RegexpOption', 'MACOption', 'PermissionsOption')
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2014-2024 Team tiramisu (see AUTHORS for all contributors)
|
||||
# Copyright (C) 2014-2023 Team tiramisu (see AUTHORS for all contributors)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by the
|
||||
|
@ -20,14 +20,14 @@
|
|||
# ____________________________________________________________
|
||||
"""base option
|
||||
"""
|
||||
from typing import FrozenSet, Set, Any, List, Optional, Dict
|
||||
from typing import FrozenSet, Set, Any, List
|
||||
import weakref
|
||||
from itertools import chain
|
||||
|
||||
|
||||
from ..i18n import _
|
||||
from ..setting import undefined
|
||||
from ..autolib import Calculation, ParamOption, ParamInformation, ParamSelfInformation
|
||||
from ..autolib import Calculation, ParamOption
|
||||
|
||||
STATIC_TUPLE = frozenset()
|
||||
|
||||
|
@ -36,41 +36,36 @@ submulti = 2
|
|||
|
||||
|
||||
def valid_name(name):
|
||||
"""valid option name"""
|
||||
"""valid option name
|
||||
"""
|
||||
if not isinstance(name, str):
|
||||
return False
|
||||
if "." in name:
|
||||
if '.' in name:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
# ____________________________________________________________
|
||||
#____________________________________________________________
|
||||
#
|
||||
class Base:
|
||||
"""Base use by all *Option* classes (Option, OptionDescription, SymLinkOption, ...)"""
|
||||
"""Base use by all *Option* classes (Option, OptionDescription, SymLinkOption, ...)
|
||||
"""
|
||||
__slots__ = ('_name',
|
||||
'_path',
|
||||
'_informations',
|
||||
'_subdyns',
|
||||
'_properties',
|
||||
'_has_dependency',
|
||||
'_dependencies',
|
||||
'_suffixes_dependencies',
|
||||
'__weakref__'
|
||||
)
|
||||
|
||||
__slots__ = (
|
||||
"_name",
|
||||
"_path",
|
||||
"_informations",
|
||||
"_subdyns",
|
||||
"_properties",
|
||||
"_has_dependency",
|
||||
"_dependencies",
|
||||
"_dependencies_information",
|
||||
"_identifiers_dependencies",
|
||||
"__weakref__",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
doc: str,
|
||||
informations: Optional[Dict],
|
||||
*,
|
||||
properties=None,
|
||||
is_multi: bool = False,
|
||||
) -> None:
|
||||
def __init__(self,
|
||||
name: str,
|
||||
doc: str,
|
||||
properties=None,
|
||||
is_multi: bool=False) -> None:
|
||||
if not valid_name(name):
|
||||
raise ValueError(_('"{0}" is an invalid name for an option').format(name))
|
||||
if properties is None:
|
||||
|
@ -81,99 +76,77 @@ class Base:
|
|||
# if option is a multi, it cannot be 'empty' (None not allowed in the list)
|
||||
# and cannot have multiple time the same value
|
||||
# 'empty' and 'unique' are removed for follower's option
|
||||
if "notunique" not in properties:
|
||||
properties = properties | {"unique"}
|
||||
if "notempty" not in properties:
|
||||
properties = properties | {"empty"}
|
||||
assert isinstance(properties, frozenset), _(
|
||||
"invalid properties type {0} for {1}," " must be a frozenset"
|
||||
).format(type(properties), name)
|
||||
_setattr = object.__setattr__
|
||||
_setattr(self, "_name", name)
|
||||
_setattr(self, "_informations", {"doc": doc})
|
||||
if 'notunique' not in properties:
|
||||
properties = properties | {'unique'}
|
||||
if 'notempty' not in properties:
|
||||
properties = properties | {'empty'}
|
||||
assert isinstance(properties, frozenset), _('invalid properties type {0} for {1},'
|
||||
' must be a frozenset').format(type(properties),
|
||||
name)
|
||||
for prop in properties:
|
||||
if not isinstance(prop, str):
|
||||
if not isinstance(prop, Calculation):
|
||||
raise ValueError(
|
||||
_(
|
||||
"invalid property type {0} for {1}, must be a string or a "
|
||||
"Calculation"
|
||||
).format(type(prop), name)
|
||||
)
|
||||
raise ValueError(_('invalid property type {0} for {1}, must be a string or a '
|
||||
'Calculation').format(type(prop), name))
|
||||
for param in chain(prop.params.args, prop.params.kwargs.values()):
|
||||
if isinstance(param, ParamOption):
|
||||
param.option._add_dependency(self)
|
||||
_setattr = object.__setattr__
|
||||
_setattr(self, '_name', name)
|
||||
_setattr(self, '_informations', {'doc': doc})
|
||||
if properties:
|
||||
_setattr(self, "_properties", properties)
|
||||
self.set_informations(informations)
|
||||
_setattr(self, '_properties', properties)
|
||||
|
||||
def set_informations(
|
||||
self,
|
||||
informations: Optional[Dict],
|
||||
) -> None:
|
||||
if not informations:
|
||||
return
|
||||
for key, value in informations.items():
|
||||
self._set_information(
|
||||
key,
|
||||
value,
|
||||
)
|
||||
|
||||
def impl_has_dependency(
|
||||
self,
|
||||
self_is_dep: bool = True,
|
||||
) -> bool:
|
||||
"""this has dependency"""
|
||||
def impl_has_dependency(self,
|
||||
self_is_dep: bool=True,
|
||||
) -> bool:
|
||||
"""this has dependency
|
||||
"""
|
||||
if self_is_dep is True:
|
||||
return getattr(self, "_has_dependency", False)
|
||||
return hasattr(self, "_dependencies")
|
||||
return getattr(self, '_has_dependency', False)
|
||||
return hasattr(self, '_dependencies')
|
||||
|
||||
def get_dependencies(
|
||||
self,
|
||||
context_od,
|
||||
) -> Set[str]:
|
||||
ret = set(getattr(self, "_dependencies", STATIC_TUPLE))
|
||||
if context_od and hasattr(context_od, "_dependencies"):
|
||||
def get_dependencies(self,
|
||||
context_od,
|
||||
) -> Set[str]:
|
||||
ret = set(getattr(self, '_dependencies', STATIC_TUPLE))
|
||||
if context_od and hasattr(context_od, '_dependencies'):
|
||||
# add options that have context is set in calculation
|
||||
return (
|
||||
set(context_od._dependencies) | ret
|
||||
) # pylint: disable=protected-access
|
||||
return set(context_od._dependencies) | ret # pylint: disable=protected-access
|
||||
return ret
|
||||
|
||||
def _get_identifiers_dependencies(self) -> Set[str]:
|
||||
return getattr(self, "_identifiers_dependencies", STATIC_TUPLE)
|
||||
def _get_suffixes_dependencies(self) -> Set[str]:
|
||||
return getattr(self, '_suffixes_dependencies', STATIC_TUPLE)
|
||||
|
||||
def _add_dependency(
|
||||
self,
|
||||
option,
|
||||
is_identifier: bool = False,
|
||||
) -> None:
|
||||
def _add_dependency(self,
|
||||
option,
|
||||
is_suffix: bool=False,
|
||||
) -> None:
|
||||
woption = weakref.ref(option)
|
||||
options = self.get_dependencies(None)
|
||||
options.add(woption)
|
||||
self._dependencies = tuple(
|
||||
options
|
||||
) # pylint: disable=attribute-defined-outside-init
|
||||
if is_identifier:
|
||||
options = list(self._get_identifiers_dependencies())
|
||||
self._dependencies = tuple(options) # pylint: disable=attribute-defined-outside-init
|
||||
if is_suffix:
|
||||
options = list(self._get_suffixes_dependencies())
|
||||
options.append(woption)
|
||||
self._identifiers_dependencies = tuple(
|
||||
options
|
||||
) # pylint: disable=attribute-defined-outside-init
|
||||
self._suffixes_dependencies = tuple(options) # pylint: disable=attribute-defined-outside-init
|
||||
|
||||
def impl_is_optiondescription(self) -> bool:
|
||||
"""option is an option description"""
|
||||
"""option is an option description
|
||||
"""
|
||||
return False
|
||||
|
||||
def impl_is_dynoptiondescription(self) -> bool:
|
||||
"""option is not a dyn option description"""
|
||||
"""option is not a dyn option description
|
||||
"""
|
||||
return False
|
||||
|
||||
def impl_is_sub_dyn_optiondescription(self):
|
||||
return False
|
||||
|
||||
def impl_getname(self) -> str:
|
||||
"""get name"""
|
||||
"""get name
|
||||
"""
|
||||
return self._name # pylint: disable=no-member
|
||||
|
||||
def _set_readonly(self) -> None:
|
||||
|
@ -182,39 +155,40 @@ class Base:
|
|||
dico = self._informations # pylint: disable=no-member
|
||||
keys = tuple(dico.keys())
|
||||
if len(keys) == 1:
|
||||
dico = dico["doc"]
|
||||
dico = dico['doc']
|
||||
else:
|
||||
dico = tuple([keys, tuple(dico.values())])
|
||||
_setattr(self, "_informations", dico)
|
||||
extra = getattr(self, "_extra", None)
|
||||
_setattr(self, '_informations', dico)
|
||||
extra = getattr(self, '_extra', None)
|
||||
if extra is not None:
|
||||
_setattr(
|
||||
self, "_extra", tuple([tuple(extra.keys()), tuple(extra.values())])
|
||||
)
|
||||
_setattr(self, '_extra', tuple([tuple(extra.keys()), tuple(extra.values())]))
|
||||
|
||||
def impl_is_readonly(self) -> str:
|
||||
"""the option is readonly"""
|
||||
return hasattr(self, "_path")
|
||||
"""the option is readonly
|
||||
"""
|
||||
return hasattr(self, '_path')
|
||||
|
||||
def impl_getproperties(self) -> FrozenSet[str]:
|
||||
"""get properties"""
|
||||
return getattr(self, "_properties", frozenset())
|
||||
"""get properties
|
||||
"""
|
||||
return getattr(self, '_properties', frozenset())
|
||||
|
||||
def _setsubdyn(
|
||||
self,
|
||||
subdyn,
|
||||
) -> None:
|
||||
def _setsubdyn(self,
|
||||
subdyn,
|
||||
) -> None:
|
||||
# pylint: disable=attribute-defined-outside-init
|
||||
if getattr(self, "_subdyns", None) is None:
|
||||
if getattr(self, '_subdyns', None) is None:
|
||||
self._subdyns = []
|
||||
self._subdyns.append(subdyn)
|
||||
|
||||
def issubdyn(self) -> bool:
|
||||
"""is sub dynoption"""
|
||||
return getattr(self, "_subdyns", None) is not None
|
||||
"""is sub dynoption
|
||||
"""
|
||||
return getattr(self, '_subdyns', None) is not None
|
||||
|
||||
def getsubdyn(self):
|
||||
"""get sub dynoption"""
|
||||
"""get sub dynoption
|
||||
"""
|
||||
return self._subdyns[0]()
|
||||
|
||||
def get_sub_dyns(self):
|
||||
|
@ -222,12 +196,10 @@ class Base:
|
|||
|
||||
# ____________________________________________________________
|
||||
# information
|
||||
def _get_information(
|
||||
self,
|
||||
subconfig: "SubConfig",
|
||||
key: str,
|
||||
default: Any = undefined,
|
||||
) -> Any:
|
||||
def impl_get_information(self,
|
||||
key: str,
|
||||
default: Any=undefined,
|
||||
) -> Any:
|
||||
"""retrieves one information's item
|
||||
|
||||
:param key: the item string (ex: "help")
|
||||
|
@ -237,7 +209,7 @@ class Base:
|
|||
if key in dico[0]:
|
||||
return dico[1][dico[0].index(key)]
|
||||
elif isinstance(dico, str):
|
||||
if key == "doc":
|
||||
if key == 'doc':
|
||||
return dico
|
||||
elif isinstance(dico, dict):
|
||||
if key in dico:
|
||||
|
@ -245,17 +217,13 @@ class Base:
|
|||
if default is not undefined:
|
||||
return default
|
||||
# pylint: disable=no-member
|
||||
raise ValueError(
|
||||
_('information\'s item for {0} not found: "{1}"').format(
|
||||
self.impl_get_display_name(subconfig, with_quote=True), key
|
||||
)
|
||||
)
|
||||
raise ValueError(_(f'information\'s item for "{self.impl_get_display_name()}" '
|
||||
f'not found: "{key}"'))
|
||||
|
||||
def _set_information(
|
||||
self,
|
||||
key: str,
|
||||
value: Any,
|
||||
) -> None:
|
||||
def impl_set_information(self,
|
||||
key: str,
|
||||
value: Any,
|
||||
) -> None:
|
||||
"""updates the information's attribute
|
||||
(which is a dictionary)
|
||||
|
||||
|
@ -263,20 +231,20 @@ class Base:
|
|||
:param value: information's value (ex: "the help string")
|
||||
"""
|
||||
if self.impl_is_readonly():
|
||||
raise AttributeError(
|
||||
_("'{0}' ({1}) object attribute '{2}' is" " read-only").format(
|
||||
self.__class__.__name__, self, key
|
||||
)
|
||||
)
|
||||
raise AttributeError(_("'{0}' ({1}) object attribute '{2}' is"
|
||||
" read-only").format(self.__class__.__name__,
|
||||
self,
|
||||
key))
|
||||
self._informations[key] = value # pylint: disable=no-member
|
||||
|
||||
def _list_information(self) -> Any:
|
||||
"""get the list of information keys"""
|
||||
def impl_list_information(self) -> Any:
|
||||
"""get the list of information keys
|
||||
"""
|
||||
dico = self._informations # pylint: disable=no-member
|
||||
if isinstance(dico, tuple):
|
||||
return list(dico[0])
|
||||
if not isinstance(dico, dict):
|
||||
return ["doc"]
|
||||
if isinstance(dico, str):
|
||||
return ['doc']
|
||||
# it's a dict
|
||||
return list(dico.keys())
|
||||
|
||||
|
@ -286,14 +254,12 @@ class BaseOption(Base):
|
|||
in options that have to be set only once, it is of course done in the
|
||||
__setattr__ method
|
||||
"""
|
||||
__slots__ = ('_display_name_function',)
|
||||
|
||||
__slots__ = ("_display_name_function",)
|
||||
|
||||
def __setattr__(
|
||||
self,
|
||||
name: str,
|
||||
value: Any,
|
||||
) -> Any:
|
||||
def __setattr__(self,
|
||||
name: str,
|
||||
value: Any,
|
||||
) -> Any:
|
||||
"""set once and only once some attributes in the option,
|
||||
like `_name`. `_name` cannot be changed once the option is
|
||||
pushed in the :class:`tiramisu.option.OptionDescription`.
|
||||
|
@ -304,111 +270,85 @@ class BaseOption(Base):
|
|||
"""
|
||||
# never change _name in an option or attribute when object is readonly
|
||||
if self.impl_is_readonly():
|
||||
raise AttributeError(
|
||||
_('"{}" ({}) object attribute "{}" is' " read-only").format(
|
||||
self.__class__.__name__, self.impl_get_display_name(None), name
|
||||
)
|
||||
)
|
||||
raise AttributeError(_('"{}" ({}) object attribute "{}" is'
|
||||
' read-only').format(self.__class__.__name__,
|
||||
self.impl_get_display_name(),
|
||||
name))
|
||||
super().__setattr__(name, value)
|
||||
|
||||
def impl_getpath(self) -> str:
|
||||
"""get the path of the option"""
|
||||
"""get the path of the option
|
||||
"""
|
||||
try:
|
||||
return self._path
|
||||
except AttributeError as err:
|
||||
raise AttributeError(
|
||||
_("{0} not part of any Config").format(
|
||||
self.impl_get_display_name(None, with_quote=True)
|
||||
)
|
||||
) from err
|
||||
raise AttributeError(_(f'"{self.impl_get_display_name()}" not part of any Config')) \
|
||||
from err
|
||||
|
||||
def impl_get_display_name(
|
||||
self,
|
||||
subconfig: "SubConfig",
|
||||
*,
|
||||
with_quote: bool = False,
|
||||
) -> str:
|
||||
"""get display name"""
|
||||
if hasattr(self, "_display_name_function"):
|
||||
return self._display_name_function(
|
||||
self,
|
||||
subconfig,
|
||||
with_quote=with_quote,
|
||||
)
|
||||
name = self._get_information(subconfig, "doc", None)
|
||||
if name is None or name == "":
|
||||
if subconfig and subconfig.path:
|
||||
name = subconfig.path.rsplit(".", 1)[-1]
|
||||
else:
|
||||
name = self._name
|
||||
if with_quote:
|
||||
return f'"{name}"'
|
||||
def impl_get_display_name(self,
|
||||
dynopt=None,
|
||||
) -> str:
|
||||
"""get display name
|
||||
"""
|
||||
if dynopt is None:
|
||||
dynopt = self
|
||||
if hasattr(self, '_display_name_function'):
|
||||
return self._display_name_function(dynopt)
|
||||
name = self.impl_get_information('doc', None)
|
||||
if name is None or name == '':
|
||||
name = dynopt.impl_getname()
|
||||
return name
|
||||
|
||||
def reset_cache(
|
||||
self,
|
||||
path: str,
|
||||
config_bag: "OptionBag",
|
||||
resetted_opts: List[Base], # pylint: disable=unused-argument
|
||||
) -> None:
|
||||
"""reset cache"""
|
||||
def reset_cache(self,
|
||||
path: str,
|
||||
config_bag: 'OptionBag',
|
||||
resetted_opts: List[Base], # pylint: disable=unused-argument
|
||||
) -> None:
|
||||
"""reset cache
|
||||
"""
|
||||
context = config_bag.context
|
||||
context.properties_cache.delcache(path)
|
||||
context._impl_permissives_cache.delcache(
|
||||
path
|
||||
) # pylint: disable=protected-access
|
||||
context._impl_permissives_cache.delcache(path) # pylint: disable=protected-access
|
||||
if not self.impl_is_optiondescription():
|
||||
context.get_values_cache().delcache(
|
||||
path
|
||||
) # pylint: disable=protected-access
|
||||
context.get_values_cache().delcache(path) # pylint: disable=protected-access
|
||||
|
||||
def impl_is_symlinkoption(self) -> bool:
|
||||
"""the option is not a symlinkoption"""
|
||||
"""the option is not a symlinkoption
|
||||
"""
|
||||
return False
|
||||
|
||||
def get_dependencies_information(self) -> List[str]:
|
||||
"""get dependencies information"""
|
||||
return getattr(self, "_dependencies_information", {})
|
||||
"""get dependencies information
|
||||
"""
|
||||
return getattr(self, '_dependencies_information', {})
|
||||
|
||||
def value_dependencies(
|
||||
self,
|
||||
value: Any,
|
||||
is_identifier: bool = False,
|
||||
) -> Any:
|
||||
"""parse dependancies to add dependencies"""
|
||||
if isinstance(value, list):
|
||||
for val in value:
|
||||
if isinstance(value, list):
|
||||
self.value_dependencies(val, is_identifier)
|
||||
elif isinstance(value, Calculation):
|
||||
self.value_dependency(val, is_identifier)
|
||||
elif isinstance(value, Calculation):
|
||||
self.value_dependency(value, is_identifier)
|
||||
|
||||
def value_dependency(
|
||||
self,
|
||||
value: Any,
|
||||
is_identifier: bool = False,
|
||||
) -> Any:
|
||||
"""parse dependancy to add dependencies"""
|
||||
for param in chain(value.params.args, value.params.kwargs.values()):
|
||||
if isinstance(param, ParamOption):
|
||||
# pylint: disable=protected-access
|
||||
param.option._add_dependency(self, is_identifier=is_identifier)
|
||||
self._has_dependency = True
|
||||
elif isinstance(param, ParamInformation):
|
||||
dest = self
|
||||
if isinstance(param, ParamSelfInformation):
|
||||
opt = weakref.ref(self)
|
||||
elif param.option:
|
||||
dest = param.option
|
||||
opt = weakref.ref(self)
|
||||
else:
|
||||
param.set_self_option(self)
|
||||
opt = None
|
||||
if not getattr(dest, "_dependencies_information", {}):
|
||||
dest._dependencies_information = {None: []}
|
||||
dest._dependencies_information[None].append(param)
|
||||
dest._dependencies_information.setdefault(
|
||||
param.information_name, []
|
||||
).append(opt)
|
||||
def to_sub_dyoption(self,
|
||||
suffixes: list[str],
|
||||
):
|
||||
sub_dyn = self
|
||||
# retrieve all subdyn options
|
||||
sub_dyns = []
|
||||
while True:
|
||||
sub_dyn = sub_dyn.getsubdyn()
|
||||
sub_dyns.append(sub_dyn)
|
||||
if not sub_dyn.issubdyn():
|
||||
break
|
||||
paths = []
|
||||
parent_path = self.impl_getpath().rsplit('.', 1)[0]
|
||||
suffix_idx = len(sub_dyns) - 1
|
||||
for sub_dyn in sub_dyns:
|
||||
dyn_path = sub_dyn.impl_getpath()
|
||||
if dyn_path.count('.') == parent_path.count('.'):
|
||||
*root_paths, dyn_path_ = parent_path.split('.', dyn_path.count('.') + 1)
|
||||
else:
|
||||
*root_paths, dyn_path_, child_path = parent_path.split('.', dyn_path.count('.') + 1)
|
||||
paths.insert(0, child_path)
|
||||
paths.insert(0, sub_dyn.impl_getname(suffixes[suffix_idx]))
|
||||
suffix_idx -= 1
|
||||
parent_path = '.'.join(root_paths)
|
||||
if parent_path:
|
||||
paths.insert(0, parent_path)
|
||||
full_parent_path = '.'.join(paths)
|
||||
return self.to_dynoption(full_parent_path,
|
||||
suffixes,
|
||||
)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2017-2024 Team tiramisu (see AUTHORS for all contributors)
|
||||
# Copyright (C) 2017-2023 Team tiramisu (see AUTHORS for all contributors)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by the
|
||||
|
@ -26,15 +26,15 @@ from .option import Option
|
|||
|
||||
|
||||
class BoolOption(Option):
|
||||
"""represents a choice between ``True`` and ``False``"""
|
||||
|
||||
"""represents a choice between ``True`` and ``False``
|
||||
"""
|
||||
__slots__ = tuple()
|
||||
_type = "boolean"
|
||||
_type = _('boolean')
|
||||
|
||||
def validate(
|
||||
self,
|
||||
value: bool,
|
||||
) -> None:
|
||||
"""validate value"""
|
||||
def validate(self,
|
||||
value: bool,
|
||||
) -> None:
|
||||
"""validate value
|
||||
"""
|
||||
if not isinstance(value, bool):
|
||||
raise ValueError()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2017-2024 Team tiramisu (see AUTHORS for all contributors)
|
||||
# Copyright (C) 2017-2023 Team tiramisu (see AUTHORS for all contributors)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by the
|
||||
|
@ -27,21 +27,21 @@ from .option import Option
|
|||
|
||||
|
||||
class BroadcastOption(Option):
|
||||
"""represents the choice of a broadcast"""
|
||||
|
||||
"""represents the choice of a broadcast
|
||||
"""
|
||||
__slots__ = tuple()
|
||||
_type = "broadcast address"
|
||||
_type = _('broadcast address')
|
||||
|
||||
def validate(
|
||||
self,
|
||||
value: str,
|
||||
) -> None:
|
||||
"""validate"""
|
||||
def validate(self,
|
||||
value: str,
|
||||
) -> None:
|
||||
"""validate
|
||||
"""
|
||||
if not isinstance(value, str):
|
||||
raise ValueError(_("invalid string"))
|
||||
if value.count(".") != 3:
|
||||
raise ValueError(_('invalid string'))
|
||||
if value.count('.') != 3:
|
||||
raise ValueError()
|
||||
for val in value.split("."):
|
||||
for val in value.split('.'):
|
||||
if val.startswith("0") and len(val) > 1:
|
||||
raise ValueError()
|
||||
try:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2017-2024 Team tiramisu (see AUTHORS for all contributors)
|
||||
# Copyright (C) 2017-2023 Team tiramisu (see AUTHORS for all contributors)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by the
|
||||
|
@ -25,7 +25,7 @@ from typing import Any
|
|||
from ..setting import undefined
|
||||
from ..i18n import _
|
||||
from .option import Option
|
||||
from ..autolib import Calculation, get_calculated_value
|
||||
from ..autolib import Calculation
|
||||
from ..error import ConfigError, display_list
|
||||
|
||||
|
||||
|
@ -34,73 +34,67 @@ class ChoiceOption(Option):
|
|||
|
||||
The option can also have the value ``None``
|
||||
"""
|
||||
|
||||
__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
|
||||
"""
|
||||
if not isinstance(values, (Calculation, tuple)):
|
||||
raise TypeError(
|
||||
_("values must be a tuple or a calculation for {0}").format(name)
|
||||
)
|
||||
raise TypeError(_('values must be a tuple or a calculation for {0}'
|
||||
).format(name))
|
||||
self._choice_values = values
|
||||
super().__init__(name, doc, *args, **kwargs)
|
||||
super().__init__(name,
|
||||
doc,
|
||||
*args,
|
||||
**kwargs)
|
||||
|
||||
def impl_get_values(
|
||||
self,
|
||||
subconfig: "SubConfig",
|
||||
uncalculated: bool = False,
|
||||
):
|
||||
"""get values allowed by option"""
|
||||
choices = self._choice_values
|
||||
if isinstance(choices, tuple):
|
||||
choices = list(choices)
|
||||
if uncalculated:
|
||||
return choices
|
||||
values = get_calculated_value(
|
||||
subconfig,
|
||||
choices,
|
||||
)[0]
|
||||
|
||||
if values != undefined and not isinstance(values, (list, tuple)):
|
||||
raise ConfigError(
|
||||
_('the calculated values "{0}" for "{1}" is not a list' "").format(
|
||||
values, self.impl_getname()
|
||||
)
|
||||
)
|
||||
def impl_get_values(self,
|
||||
subconfig: "SubConfig",
|
||||
):
|
||||
"""get values allowed by option
|
||||
"""
|
||||
if isinstance(self._choice_values, Calculation):
|
||||
values = self._choice_values.execute(subconfig)
|
||||
if values is not undefined and not isinstance(values, list):
|
||||
raise ConfigError(_('the calculated values "{0}" for "{1}" is not a list'
|
||||
'').format(values, self.impl_getname()))
|
||||
else:
|
||||
values = self._choice_values
|
||||
return values
|
||||
|
||||
def validate(
|
||||
self,
|
||||
value: Any,
|
||||
) -> None:
|
||||
"""nothing to valide"""
|
||||
def validate(self,
|
||||
value: Any,
|
||||
) -> None:
|
||||
"""nothing to valide
|
||||
"""
|
||||
|
||||
def validate_with_option(
|
||||
self,
|
||||
value: Any,
|
||||
subconfig: "SubConfig",
|
||||
loaded: bool,
|
||||
) -> None:
|
||||
def validate_with_option(self,
|
||||
value: Any,
|
||||
subconfig: "SubConfig",
|
||||
loaded: bool,
|
||||
) -> None:
|
||||
if loaded and isinstance(self._choice_values, Calculation):
|
||||
return
|
||||
values = self.impl_get_values(subconfig)
|
||||
self.validate_values(value, values)
|
||||
|
||||
def validate_values(
|
||||
self,
|
||||
value,
|
||||
values,
|
||||
) -> None:
|
||||
"""validate values"""
|
||||
def validate_values(self,
|
||||
value,
|
||||
values,
|
||||
) -> None:
|
||||
"""validate values
|
||||
"""
|
||||
if values is not undefined and value not in values:
|
||||
if len(values) == 1:
|
||||
raise ValueError(_('only "{0}" is allowed' "").format(values[0]))
|
||||
raise ValueError(
|
||||
_("only {0} are allowed" "").format(
|
||||
display_list(values, add_quote=True)
|
||||
)
|
||||
)
|
||||
raise ValueError(_('only "{0}" is allowed'
|
||||
'').format(values[0]))
|
||||
raise ValueError(_('only {0} are allowed'
|
||||
'').format(display_list(values, add_quote=True)))
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2017-2024 Team tiramisu (see AUTHORS for all contributors)
|
||||
# Copyright (C) 2017-2023 Team tiramisu (see AUTHORS for all contributors)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by the
|
||||
|
@ -27,12 +27,13 @@ from .stroption import StrOption
|
|||
|
||||
|
||||
class DateOption(StrOption):
|
||||
"""represents the choice of a date"""
|
||||
|
||||
"""represents the choice of a date
|
||||
"""
|
||||
__slots__ = tuple()
|
||||
_type = "date"
|
||||
_type = _('date')
|
||||
|
||||
def validate(self, value: str) -> None:
|
||||
def validate(self,
|
||||
value: str) -> None:
|
||||
super().validate(value)
|
||||
try:
|
||||
datetime.strptime(value, "%Y-%m-%d")
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2017-2024 Team tiramisu (see AUTHORS for all contributors)
|
||||
# Copyright (C) 2017-2023 Team tiramisu (see AUTHORS for all contributors)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by the
|
||||
|
@ -39,139 +39,131 @@ class DomainnameOption(StrOption):
|
|||
domainname:
|
||||
fqdn: with tld, not supported yet
|
||||
"""
|
||||
|
||||
__slots__ = tuple()
|
||||
_type = "domain name"
|
||||
_type = _('domain name')
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
doc: str,
|
||||
*args,
|
||||
allow_ip: bool = False,
|
||||
allow_cidr_network: bool = False,
|
||||
type: str = "domainname",
|
||||
allow_without_dot: bool = False,
|
||||
allow_startswith_dot: bool = False,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
def __init__(self,
|
||||
name: str,
|
||||
doc: str,
|
||||
default: Any=undefined,
|
||||
default_multi: Any=None,
|
||||
multi: bool=False,
|
||||
validators: Optional[List[Calculation]]=None,
|
||||
properties: Optional[List[str]]=None,
|
||||
warnings_only: bool=False,
|
||||
allow_ip: bool=False,
|
||||
allow_cidr_network: bool=False,
|
||||
type: str='domainname',
|
||||
allow_without_dot: bool=False,
|
||||
allow_startswith_dot: bool=False,
|
||||
) -> None:
|
||||
# pylint: disable=too-many-branches,too-many-locals,too-many-arguments
|
||||
if type not in ["netbios", "hostname", "domainname"]:
|
||||
raise ValueError(_("unknown type {0} for hostname").format(type))
|
||||
extra = {"_dom_type": type}
|
||||
if type not in ['netbios', 'hostname', 'domainname']:
|
||||
raise ValueError(_('unknown type {0} for hostname').format(type))
|
||||
extra = {'_dom_type': type}
|
||||
if not isinstance(allow_ip, bool):
|
||||
raise ValueError(_("allow_ip must be a boolean"))
|
||||
raise ValueError(_('allow_ip must be a boolean'))
|
||||
if not isinstance(allow_cidr_network, bool):
|
||||
raise ValueError(_("allow_cidr_network must be a boolean"))
|
||||
raise ValueError(_('allow_cidr_network must be a boolean'))
|
||||
if not isinstance(allow_without_dot, bool):
|
||||
raise ValueError(_("allow_without_dot must be a boolean"))
|
||||
raise ValueError(_('allow_without_dot must be a boolean'))
|
||||
if not isinstance(allow_startswith_dot, bool):
|
||||
raise ValueError(_("allow_startswith_dot must be a boolean"))
|
||||
extra["_allow_without_dot"] = allow_without_dot
|
||||
if type == "domainname":
|
||||
raise ValueError(_('allow_startswith_dot must be a boolean'))
|
||||
extra['_allow_without_dot'] = allow_without_dot
|
||||
if type == 'domainname':
|
||||
if allow_without_dot:
|
||||
min_time = 0
|
||||
else:
|
||||
min_time = 1
|
||||
regexp = r"((?!-)[a-z0-9-]{{{1},{0}}}\.){{{1},}}[a-z0-9-]{{1,{0}}}".format(
|
||||
self._get_len(type), min_time
|
||||
)
|
||||
regexp = r'((?!-)[a-z0-9-]{{{1},{0}}}\.){{{1},}}[a-z0-9-]{{1,{0}}}'.format(self._get_len(type), min_time)
|
||||
else:
|
||||
regexp = r"((?!-)[a-z0-9-]{{1,{0}}})".format(self._get_len(type))
|
||||
msg = _(
|
||||
'must start with lowercase characters followed by lowercase characters, number, "-" and "." characters are allowed'
|
||||
)
|
||||
msg_warning = _(
|
||||
'must start with lowercase characters followed by lowercase characters, number, "-" and "." characters are recommanded'
|
||||
)
|
||||
regexp = r'((?!-)[a-z0-9-]{{1,{0}}})'.format(self._get_len(type))
|
||||
msg = _('must start with lowercase characters followed by lowercase characters, number, "-" and "." characters are allowed')
|
||||
msg_warning = _('must start with lowercase characters followed by lowercase characters, number, "-" and "." characters are recommanded')
|
||||
if allow_ip:
|
||||
msg = _("could be a IP, otherwise {}").format(msg)
|
||||
msg_warning = _("could be a IP, otherwise {}").format(msg_warning)
|
||||
msg = _('could be a IP, otherwise {}').format(msg)
|
||||
msg_warning = _('could be a IP, otherwise {}').format(msg_warning)
|
||||
if not allow_cidr_network:
|
||||
regexp = r"(?:{0}|(?:(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){{3}}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)))".format(
|
||||
regexp
|
||||
)
|
||||
regexp = r'(?:{0}|(?:(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){{3}}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)))'.format(regexp)
|
||||
else:
|
||||
regexp = r"(?:{0}|(?:(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){{3}}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/[0-9][0-9]))".format(
|
||||
regexp
|
||||
)
|
||||
regexp = r"^{0}$".format(regexp)
|
||||
extra["_domain_re"] = re.compile(regexp)
|
||||
extra["_domain_re_message"] = msg
|
||||
extra["_domain_re_message_warning"] = msg_warning
|
||||
extra["_has_upper"] = re.compile("[A-Z]")
|
||||
regexp = r'(?:{0}|(?:(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){{3}}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/[0-9][0-9]))'.format(regexp)
|
||||
regexp = r'^{0}$'.format(regexp)
|
||||
extra['_domain_re'] = re.compile(regexp)
|
||||
extra['_domain_re_message'] = msg
|
||||
extra['_domain_re_message_warning'] = msg_warning
|
||||
extra['_has_upper'] = re.compile('[A-Z]')
|
||||
if allow_ip:
|
||||
extra["_ip"] = IPOption(
|
||||
name,
|
||||
doc,
|
||||
)
|
||||
extra["_allow_ip"] = allow_ip
|
||||
extra['_ip'] = IPOption(name,
|
||||
doc)
|
||||
extra['_allow_ip'] = allow_ip
|
||||
if allow_cidr_network:
|
||||
extra["_network"] = NetworkOption(
|
||||
name,
|
||||
doc,
|
||||
cidr=True,
|
||||
)
|
||||
extra["_allow_cidr_network"] = allow_cidr_network
|
||||
extra["_allow_startswith_dot"] = allow_startswith_dot
|
||||
extra['_network'] = NetworkOption(name,
|
||||
doc,
|
||||
cidr=True)
|
||||
extra['_allow_cidr_network'] = allow_cidr_network
|
||||
extra['_allow_startswith_dot'] = allow_startswith_dot
|
||||
|
||||
super().__init__(
|
||||
name,
|
||||
doc,
|
||||
*args,
|
||||
extra=extra,
|
||||
**kwargs,
|
||||
)
|
||||
super().__init__(name,
|
||||
doc,
|
||||
default=default,
|
||||
default_multi=default_multi,
|
||||
multi=multi,
|
||||
validators=validators,
|
||||
properties=properties,
|
||||
warnings_only=warnings_only,
|
||||
extra=extra)
|
||||
|
||||
def _get_len(self, type_):
|
||||
if type_ == "netbios":
|
||||
if type_ == 'netbios':
|
||||
return 15
|
||||
return 63
|
||||
|
||||
def _validate_domain(self, value: str) -> None:
|
||||
def _validate_domain(self,
|
||||
value: str) -> None:
|
||||
def _valid_length(val):
|
||||
if len(val) < 1:
|
||||
raise ValueError(_("invalid length (min 1)"))
|
||||
if len(val) > part_name_length:
|
||||
raise ValueError(
|
||||
_("invalid length (max {0})" "").format(part_name_length)
|
||||
)
|
||||
raise ValueError(_("invalid length (max {0})"
|
||||
"").format(part_name_length))
|
||||
|
||||
part_name_length = self._get_len(self.impl_get_extra("_dom_type"))
|
||||
if self.impl_get_extra("_dom_type") == "domainname":
|
||||
if not self.impl_get_extra("_allow_without_dot") and not "." in value:
|
||||
part_name_length = self._get_len(self.impl_get_extra('_dom_type'))
|
||||
if self.impl_get_extra('_dom_type') == 'domainname':
|
||||
if not self.impl_get_extra('_allow_without_dot') and not "." in value:
|
||||
raise ValueError(_("must have dot"))
|
||||
if len(value) > 255:
|
||||
raise ValueError(_("invalid length (max 255)"))
|
||||
if self.impl_get_extra("_allow_startswith_dot") and value.startswith("."):
|
||||
if self.impl_get_extra('_allow_startswith_dot') and value.startswith('.'):
|
||||
val = value[1:]
|
||||
else:
|
||||
val = value
|
||||
if val.endswith("."):
|
||||
if val.endswith('.'):
|
||||
nval = val[:-1]
|
||||
else:
|
||||
nval = val
|
||||
for dom in nval.split("."):
|
||||
for dom in nval.split('.'):
|
||||
_valid_length(dom)
|
||||
else:
|
||||
_valid_length(value)
|
||||
|
||||
def _validate_ip_network(self, value: str) -> None:
|
||||
allow_ip = self.impl_get_extra("_allow_ip")
|
||||
allow_cidr_network = self.impl_get_extra("_allow_cidr_network")
|
||||
def _validate_ip_network(self,
|
||||
value: str) -> None:
|
||||
allow_ip = self.impl_get_extra('_allow_ip')
|
||||
allow_cidr_network = self.impl_get_extra('_allow_cidr_network')
|
||||
if allow_ip is False and allow_cidr_network is False:
|
||||
raise ValueError(_("must not be an IP"))
|
||||
raise ValueError(_('must not be an IP'))
|
||||
if allow_ip is True:
|
||||
try:
|
||||
self.impl_get_extra("_ip").validate(value)
|
||||
self.impl_get_extra('_ip').validate(value)
|
||||
return
|
||||
except ValueError as err:
|
||||
if allow_cidr_network is False:
|
||||
raise err
|
||||
if allow_cidr_network is True:
|
||||
self.impl_get_extra("_network").validate(value)
|
||||
self.impl_get_extra('_network').validate(value)
|
||||
|
||||
def validate(self, value: str) -> None:
|
||||
def validate(self,
|
||||
value: str) -> None:
|
||||
super().validate(value)
|
||||
try:
|
||||
# check if it's an IP or network
|
||||
|
@ -181,40 +173,42 @@ class DomainnameOption(StrOption):
|
|||
else:
|
||||
self._validate_ip_network(value)
|
||||
|
||||
def _second_level_validation_domain(self, value: str, warnings_only: bool) -> None:
|
||||
if self.impl_get_extra("_has_upper").search(value):
|
||||
raise ValueError(_("some characters are uppercase"))
|
||||
if self.impl_get_extra("_allow_startswith_dot") and value.startswith("."):
|
||||
def _second_level_validation_domain(self,
|
||||
value: str,
|
||||
warnings_only: bool) -> None:
|
||||
if self.impl_get_extra('_has_upper').search(value):
|
||||
raise ValueError(_('some characters are uppercase'))
|
||||
if self.impl_get_extra('_allow_startswith_dot') and value.startswith('.'):
|
||||
val = value[1:]
|
||||
else:
|
||||
val = value
|
||||
if val.endswith("."):
|
||||
if val.endswith('.'):
|
||||
nval = val[:-1]
|
||||
else:
|
||||
nval = val
|
||||
if not self.impl_get_extra("_domain_re").search(nval):
|
||||
if not self.impl_get_extra('_domain_re').search(nval):
|
||||
if warnings_only:
|
||||
raise ValueError(self.impl_get_extra("_domain_re_message_warning"))
|
||||
raise ValueError(self.impl_get_extra("_domain_re_message"))
|
||||
raise ValueError(self.impl_get_extra('_domain_re_message_warning'))
|
||||
raise ValueError(self.impl_get_extra('_domain_re_message'))
|
||||
|
||||
def _second_level_validation_ip_network(
|
||||
self, value: str, warnings_only: bool
|
||||
) -> None:
|
||||
allow_ip = self.impl_get_extra("_allow_ip")
|
||||
allow_cidr_network = self.impl_get_extra("_allow_cidr_network")
|
||||
def _second_level_validation_ip_network(self,
|
||||
value: str,
|
||||
warnings_only: bool) -> None:
|
||||
allow_ip = self.impl_get_extra('_allow_ip')
|
||||
allow_cidr_network = self.impl_get_extra('_allow_cidr_network')
|
||||
# it's an IP so validate with IPOption
|
||||
if allow_ip is True and allow_cidr_network is False:
|
||||
try:
|
||||
self.impl_get_extra("_ip").second_level_validation(value, warnings_only)
|
||||
self.impl_get_extra('_ip').second_level_validation(value, warnings_only)
|
||||
return
|
||||
except ValueError as err:
|
||||
raise err
|
||||
if allow_cidr_network is True:
|
||||
self.impl_get_extra("_network").second_level_validation(
|
||||
value, warnings_only
|
||||
)
|
||||
self.impl_get_extra('_network').second_level_validation(value, warnings_only)
|
||||
|
||||
def second_level_validation(self, value: str, warnings_only: bool) -> None:
|
||||
def second_level_validation(self,
|
||||
value: str,
|
||||
warnings_only: bool) -> None:
|
||||
try:
|
||||
# check if it's an IP or network
|
||||
ip_interface(value)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2017-2024 Team tiramisu (see AUTHORS for all contributors)
|
||||
# Copyright (C) 2017-2023 Team tiramisu (see AUTHORS for all contributors)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by the
|
||||
|
@ -20,135 +20,81 @@
|
|||
# ____________________________________________________________
|
||||
"""DynOptionDescription
|
||||
"""
|
||||
import re
|
||||
import weakref
|
||||
from typing import List, Any, Optional, Dict
|
||||
from typing import List, Any, Optional
|
||||
from itertools import chain
|
||||
from ..autolib import ParamOption
|
||||
|
||||
|
||||
from ..i18n import _
|
||||
from .optiondescription import OptionDescription
|
||||
from .syndynoption import CommonDyn #, SynDynLeadership
|
||||
from .baseoption import BaseOption
|
||||
from ..setting import ConfigBag, undefined
|
||||
from ..error import ConfigError
|
||||
from ..autolib import Calculation, get_calculated_value
|
||||
from ..autolib import Calculation
|
||||
|
||||
|
||||
NAME_REGEXP = re.compile(r"^[a-zA-Z\d\-_]*$")
|
||||
class DynOptionDescription(OptionDescription, CommonDyn):
|
||||
"""dyn option description
|
||||
"""
|
||||
__slots__ = ('_suffixes',
|
||||
'_subdyns',
|
||||
)
|
||||
|
||||
|
||||
class DynOptionDescription(OptionDescription):
|
||||
"""dyn option description"""
|
||||
|
||||
__slots__ = (
|
||||
"_identifiers",
|
||||
"_subdyns",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
doc: str,
|
||||
children: List[BaseOption],
|
||||
identifiers: Calculation,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
def __init__(self,
|
||||
name: str,
|
||||
doc: str,
|
||||
children: List[BaseOption],
|
||||
suffixes: Calculation,
|
||||
properties=None,
|
||||
) -> None:
|
||||
# pylint: disable=too-many-arguments
|
||||
super().__init__(
|
||||
name,
|
||||
doc,
|
||||
children,
|
||||
**kwargs,
|
||||
)
|
||||
super().__init__(name,
|
||||
doc,
|
||||
children,
|
||||
properties,
|
||||
)
|
||||
# check children + set relation to this dynoptiondescription
|
||||
wself = weakref.ref(self)
|
||||
for child in children:
|
||||
child._setsubdyn(wself)
|
||||
# add identifiers
|
||||
self.value_dependencies(identifiers, is_identifier=True)
|
||||
self._identifiers = identifiers
|
||||
# add suffixes
|
||||
if __debug__ and not isinstance(suffixes, Calculation):
|
||||
raise ConfigError(_('suffixes in dynoptiondescription has to be a calculation'))
|
||||
for param in chain(suffixes.params.args, suffixes.params.kwargs.values()):
|
||||
if isinstance(param, ParamOption):
|
||||
param.option._add_dependency(self,
|
||||
is_suffix=True,
|
||||
)
|
||||
self._suffixes = suffixes
|
||||
|
||||
def convert_identifier_to_path(
|
||||
self,
|
||||
identifier: Any,
|
||||
) -> str:
|
||||
"""convert identifier to use it to a path"""
|
||||
if identifier is None:
|
||||
def convert_suffix_to_path(self,
|
||||
suffix: Any,
|
||||
) -> str:
|
||||
"""convert suffix to use it to a path
|
||||
"""
|
||||
if suffix is None:
|
||||
return None
|
||||
if not isinstance(identifier, str):
|
||||
identifier = str(identifier)
|
||||
if "." in identifier:
|
||||
identifier = identifier.replace(".", "_")
|
||||
return identifier
|
||||
if not isinstance(suffix, str):
|
||||
suffix = str(suffix)
|
||||
if '.' in suffix:
|
||||
suffix = suffix.replace('.', '_')
|
||||
return suffix
|
||||
|
||||
def impl_is_dynoptiondescription(self) -> bool:
|
||||
return True
|
||||
|
||||
def option_is_self(
|
||||
self,
|
||||
option,
|
||||
) -> bool:
|
||||
def option_is_self(self,
|
||||
option,
|
||||
) -> bool:
|
||||
return option == self
|
||||
|
||||
def impl_getname(self, identifier=None) -> str:
|
||||
"""get name"""
|
||||
def impl_getname(self, suffix=None) -> str:
|
||||
"""get name
|
||||
"""
|
||||
name = super().impl_getname()
|
||||
if identifier is None:
|
||||
if suffix is None:
|
||||
return name
|
||||
path_identifier = self.convert_identifier_to_path(identifier)
|
||||
return name + path_identifier
|
||||
|
||||
def get_identifiers(
|
||||
self,
|
||||
parent: "SubConfig",
|
||||
*,
|
||||
uncalculated: bool = False,
|
||||
) -> List[str]:
|
||||
"""get dynamic identifiers"""
|
||||
subconfig = parent.get_child(
|
||||
self,
|
||||
None,
|
||||
False,
|
||||
properties=None,
|
||||
)
|
||||
identifiers = self._identifiers
|
||||
if isinstance(identifiers, list):
|
||||
identifiers = identifiers.copy()
|
||||
if uncalculated:
|
||||
return identifiers
|
||||
values = get_calculated_value(
|
||||
subconfig,
|
||||
identifiers,
|
||||
validate_properties=False,
|
||||
)[0]
|
||||
if values is None:
|
||||
values = []
|
||||
values_ = []
|
||||
if __debug__:
|
||||
if not isinstance(values, list):
|
||||
raise ValueError(
|
||||
_(
|
||||
"DynOptionDescription identifiers for option {0}, is not a list ({1})"
|
||||
).format(
|
||||
self.impl_get_display_name(subconfig, with_quote=True), values
|
||||
)
|
||||
)
|
||||
for val in values:
|
||||
cval = self.convert_identifier_to_path(val)
|
||||
if not isinstance(cval, str) or re.match(NAME_REGEXP, cval) is None:
|
||||
if __debug__ and cval is not None:
|
||||
raise ValueError(
|
||||
_('invalid identifier "{}" for option {}' "").format(
|
||||
cval, self.impl_get_display_name(subconfig, with_quote=True)
|
||||
)
|
||||
)
|
||||
else:
|
||||
values_.append(val)
|
||||
if __debug__ and len(values_) > len(set(values_)):
|
||||
raise ValueError(
|
||||
_(
|
||||
'DynOptionDescription "{0}" identifiers return a list with same values "{1}"'
|
||||
).format(self._name, values_)
|
||||
)
|
||||
return values_
|
||||
path_suffix = self.convert_suffix_to_path(suffix)
|
||||
return name + path_suffix
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2017-2024 Team tiramisu (see AUTHORS for all contributors)
|
||||
# Copyright (C) 2017-2023 Team tiramisu (see AUTHORS for all contributors)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by the
|
||||
|
@ -27,10 +27,8 @@ from .stroption import RegexpOption
|
|||
|
||||
|
||||
class EmailOption(RegexpOption):
|
||||
"""represents a choice of an email"""
|
||||
|
||||
"""represents a choice of an email
|
||||
"""
|
||||
__slots__ = tuple()
|
||||
_regexp = re.compile(
|
||||
r"^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$"
|
||||
)
|
||||
_type = "email address"
|
||||
_regexp = re.compile(r"^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$")
|
||||
_type = _('email address')
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2017-2024 Team tiramisu (see AUTHORS for all contributors)
|
||||
# Copyright (C) 2017-2023 Team tiramisu (see AUTHORS for all contributors)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by the
|
||||
|
@ -20,62 +20,19 @@
|
|||
# ____________________________________________________________
|
||||
"""FilenameOption
|
||||
"""
|
||||
from pathlib import Path
|
||||
|
||||
from ..i18n import _
|
||||
from ..error import display_list
|
||||
from .stroption import StrOption
|
||||
|
||||
|
||||
class FilenameOption(StrOption):
|
||||
"""validate file or directory name"""
|
||||
|
||||
"""represents a choice of a file name
|
||||
"""
|
||||
__slots__ = tuple()
|
||||
_type = "file name"
|
||||
_type = _('file name')
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
*args,
|
||||
allow_relative=False,
|
||||
test_existence=False,
|
||||
types=["file", "directory"],
|
||||
**kwargs,
|
||||
):
|
||||
if not isinstance(types, list):
|
||||
raise ValueError(
|
||||
_('types parameter must be a list, not "{0}" for "{1}"').format(
|
||||
types, name
|
||||
)
|
||||
)
|
||||
for typ in types:
|
||||
if typ not in ["file", "directory"]:
|
||||
raise ValueError(f'unknown type "{typ}" for "{name}"')
|
||||
extra = {
|
||||
"_allow_relative": allow_relative,
|
||||
"_test_existence": test_existence,
|
||||
"_types": types,
|
||||
}
|
||||
super().__init__(name, *args, extra=extra, **kwargs)
|
||||
|
||||
def validate(
|
||||
self,
|
||||
value: str,
|
||||
) -> None:
|
||||
def validate(self,
|
||||
value: str,
|
||||
) -> None:
|
||||
super().validate(value)
|
||||
if not self.impl_get_extra("_allow_relative") and not value.startswith("/"):
|
||||
if not value.startswith('/'):
|
||||
raise ValueError(_('must starts with "/"'))
|
||||
if value is not None and self.impl_get_extra("_test_existence"):
|
||||
types = self.impl_get_extra("_types")
|
||||
file = Path(value)
|
||||
found = False
|
||||
if "file" in types and file.is_file():
|
||||
found = True
|
||||
if not found and "directory" in types and file.is_dir():
|
||||
found = True
|
||||
if not found:
|
||||
raise ValueError(
|
||||
_('cannot find {0} "{1}"').format(
|
||||
display_list(types, separator="or"), value
|
||||
)
|
||||
)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2017-2024 Team tiramisu (see AUTHORS for all contributors)
|
||||
# Copyright (C) 2017-2023 Team tiramisu (see AUTHORS for all contributors)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by the
|
||||
|
@ -26,11 +26,12 @@ from .option import Option
|
|||
|
||||
|
||||
class FloatOption(Option):
|
||||
"""represents a choice of a floating point number"""
|
||||
|
||||
"""represents a choice of a floating point number
|
||||
"""
|
||||
__slots__ = tuple()
|
||||
_type = "float"
|
||||
_type = _('float')
|
||||
|
||||
def validate(self, value: float) -> None:
|
||||
def validate(self,
|
||||
value: float) -> None:
|
||||
if not isinstance(value, float):
|
||||
raise ValueError()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2017-2024 Team tiramisu (see AUTHORS for all contributors)
|
||||
# Copyright (C) 2017-2023 Team tiramisu (see AUTHORS for all contributors)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by the
|
||||
|
@ -28,35 +28,40 @@ from .option import Option
|
|||
class IntOption(Option):
|
||||
"represents a choice of an integer"
|
||||
__slots__ = tuple()
|
||||
_type = "integer"
|
||||
_type = _('integer')
|
||||
|
||||
def __init__(self, *args, min_number=None, max_number=None, **kwargs):
|
||||
def __init__(self,
|
||||
*args,
|
||||
min_number=None,
|
||||
max_number=None,
|
||||
**kwargs):
|
||||
extra = {}
|
||||
if min_number is not None:
|
||||
extra["min_number"] = min_number
|
||||
extra['min_number'] = min_number
|
||||
if max_number is not None:
|
||||
extra["max_number"] = max_number
|
||||
extra['max_number'] = max_number
|
||||
super().__init__(*args, extra=extra, **kwargs)
|
||||
|
||||
def validate(
|
||||
self,
|
||||
value: int,
|
||||
) -> None:
|
||||
def validate(self,
|
||||
value: int,
|
||||
) -> None:
|
||||
if not isinstance(value, int):
|
||||
raise ValueError()
|
||||
|
||||
def second_level_validation(self, value, warnings_only):
|
||||
min_number = self.impl_get_extra("min_number")
|
||||
def second_level_validation(self,
|
||||
value,
|
||||
warnings_only):
|
||||
min_number = self.impl_get_extra('min_number')
|
||||
if min_number is not None and value < min_number:
|
||||
if warnings_only:
|
||||
msg = _('value should be equal or greater than "{0}"')
|
||||
msg = 'value should be greater than "{0}"'
|
||||
else:
|
||||
msg = _('value must be equal or greater than "{0}"')
|
||||
raise ValueError(msg.format(min_number))
|
||||
max_number = self.impl_get_extra("max_number")
|
||||
msg = 'value must be greater than "{0}"'
|
||||
raise ValueError(_(msg).format(min_number))
|
||||
max_number = self.impl_get_extra('max_number')
|
||||
if max_number is not None and value > max_number:
|
||||
if warnings_only:
|
||||
msg = _('value should be less than "{0}"')
|
||||
msg = 'value should be less than "{0}"'
|
||||
else:
|
||||
msg = _('value must be less than "{0}"')
|
||||
raise ValueError(msg.format(max_number))
|
||||
msg = 'value must be less than "{0}"'
|
||||
raise ValueError(_(msg).format(max_number))
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2017-2024 Team tiramisu (see AUTHORS for all contributors)
|
||||
# Copyright (C) 2017-2023 Team tiramisu (see AUTHORS for all contributors)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by the
|
||||
|
@ -27,26 +27,26 @@ from .stroption import StrOption
|
|||
|
||||
|
||||
class IPOption(StrOption):
|
||||
"""represents the choice of an ip"""
|
||||
|
||||
"""represents the choice of an ip
|
||||
"""
|
||||
__slots__ = tuple()
|
||||
_type = "IP"
|
||||
_type = _('IP')
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*args,
|
||||
private_only=False,
|
||||
allow_reserved=False,
|
||||
cidr=False,
|
||||
extra=None,
|
||||
**kwargs,
|
||||
):
|
||||
def __init__(self,
|
||||
*args,
|
||||
private_only=False,
|
||||
allow_reserved=False,
|
||||
cidr=False,
|
||||
extra=None,
|
||||
**kwargs):
|
||||
if extra is None:
|
||||
extra = {}
|
||||
extra["_private_only"] = private_only
|
||||
extra["_allow_reserved"] = allow_reserved
|
||||
extra["_cidr"] = cidr
|
||||
super().__init__(*args, extra=extra, **kwargs)
|
||||
extra['_private_only'] = private_only
|
||||
extra['_allow_reserved'] = allow_reserved
|
||||
extra['_cidr'] = cidr
|
||||
super().__init__(*args,
|
||||
extra=extra,
|
||||
**kwargs)
|
||||
|
||||
def _validate_cidr(self, value):
|
||||
try:
|
||||
|
@ -64,24 +64,27 @@ class IPOption(StrOption):
|
|||
except ValueError as err:
|
||||
raise ValueError() from err
|
||||
|
||||
def validate(self, value: str) -> None:
|
||||
def validate(self,
|
||||
value: str) -> None:
|
||||
super().validate(value)
|
||||
if self.impl_get_extra("_cidr"):
|
||||
if "/" not in value:
|
||||
if self.impl_get_extra('_cidr'):
|
||||
if '/' not in value:
|
||||
raise ValueError(_('CIDR address must have a "/"'))
|
||||
self._validate_cidr(value)
|
||||
else:
|
||||
self._validate_ip(value)
|
||||
|
||||
def second_level_validation(self, value: str, warnings_only: bool) -> None:
|
||||
def second_level_validation(self,
|
||||
value: str,
|
||||
warnings_only: bool) -> None:
|
||||
ip_obj = ip_interface(value)
|
||||
if not self.impl_get_extra("_allow_reserved") and ip_obj.is_reserved:
|
||||
if not self.impl_get_extra('_allow_reserved') and ip_obj.is_reserved:
|
||||
if warnings_only:
|
||||
msg = _("shouldn't be reserved IP")
|
||||
else:
|
||||
msg = _("mustn't be reserved IP")
|
||||
raise ValueError(msg)
|
||||
if self.impl_get_extra("_private_only") and not ip_obj.is_private:
|
||||
if self.impl_get_extra('_private_only') and not ip_obj.is_private:
|
||||
if warnings_only:
|
||||
msg = _("should be private IP")
|
||||
else:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"Leadership support"
|
||||
# Copyright (C) 2014-2024 Team tiramisu (see AUTHORS for all contributors)
|
||||
# Copyright (C) 2014-2023 Team tiramisu (see AUTHORS for all contributors)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by the
|
||||
|
@ -26,7 +26,6 @@ from typing import List, Iterator, Optional
|
|||
from ..i18n import _
|
||||
from ..setting import groups, undefined, ALLOWED_LEADER_PROPERTIES
|
||||
from .optiondescription import OptionDescription
|
||||
|
||||
# from .syndynoption import SynDynLeadership
|
||||
from .baseoption import BaseOption
|
||||
from .option import Option
|
||||
|
@ -35,95 +34,58 @@ from ..autolib import Calculation
|
|||
|
||||
|
||||
class Leadership(OptionDescription):
|
||||
"""Leadership"""
|
||||
|
||||
"""Leadership
|
||||
"""
|
||||
# pylint: disable=too-many-arguments
|
||||
__slots__ = (
|
||||
"leader",
|
||||
"followers",
|
||||
)
|
||||
__slots__ = ('leader',
|
||||
'followers',
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
doc,
|
||||
children: List[BaseOption],
|
||||
**kwargs,
|
||||
) -> None:
|
||||
if "group_type" in kwargs:
|
||||
raise LeadershipError(
|
||||
_('cannot set "group_type" attribute for a Leadership')
|
||||
)
|
||||
super().__init__(
|
||||
name,
|
||||
doc,
|
||||
children,
|
||||
**kwargs,
|
||||
)
|
||||
def __init__(self,
|
||||
name: str,
|
||||
doc: str,
|
||||
children: List[BaseOption],
|
||||
properties=None) -> None:
|
||||
super().__init__(name,
|
||||
doc,
|
||||
children,
|
||||
properties=properties)
|
||||
self._group_type = groups.leadership
|
||||
followers = []
|
||||
if len(children) < 2:
|
||||
raise ValueError(
|
||||
_(
|
||||
'a leader and a follower are mandatories in leadership "{}"' ""
|
||||
).format(name)
|
||||
)
|
||||
raise ValueError(_('a leader and a follower are mandatories in leadership "{}"'
|
||||
'').format(name))
|
||||
leader = children[0]
|
||||
for idx, child in enumerate(children):
|
||||
if __debug__:
|
||||
self._check_child_is_valid(child, idx, children)
|
||||
self._check_child_is_valid(child)
|
||||
if idx != 0:
|
||||
if __debug__:
|
||||
self._check_default_value(child)
|
||||
# remove empty property for follower
|
||||
child._properties = frozenset(child._properties - {"empty", "unique"})
|
||||
child._properties = frozenset(child._properties - {'empty', 'unique'})
|
||||
followers.append(child)
|
||||
child._add_dependency(self)
|
||||
child._leadership = weakref.ref(self)
|
||||
if __debug__:
|
||||
leader = children[0]
|
||||
for prop in leader.impl_getproperties():
|
||||
if prop not in ALLOWED_LEADER_PROPERTIES and not isinstance(
|
||||
prop, Calculation
|
||||
):
|
||||
raise LeadershipError(
|
||||
_('leader cannot have "{}" property').format(prop)
|
||||
)
|
||||
if prop not in ALLOWED_LEADER_PROPERTIES and not isinstance(prop, Calculation):
|
||||
raise LeadershipError(_('leader cannot have "{}" property').format(prop))
|
||||
|
||||
def _check_child_is_valid(
|
||||
self,
|
||||
child: BaseOption,
|
||||
index: int,
|
||||
children: [BaseOption],
|
||||
) -> None:
|
||||
def _check_child_is_valid(self, child: BaseOption):
|
||||
if child.impl_is_symlinkoption():
|
||||
if not index:
|
||||
raise ValueError(
|
||||
_("leadership {0} shall not have " "a symlinkoption").format(
|
||||
self.impl_get_display_name(None, with_quote=True)
|
||||
)
|
||||
)
|
||||
return
|
||||
raise ValueError(_('leadership "{0}" shall not have '
|
||||
"a symlinkoption").format(self.impl_get_display_name()))
|
||||
if not isinstance(child, Option):
|
||||
raise ValueError(
|
||||
_("leadership {0} shall not have " "a subgroup").format(
|
||||
self.impl_get_display_name(None, with_quote=True)
|
||||
)
|
||||
)
|
||||
raise ValueError(_('leadership "{0}" shall not have '
|
||||
'a subgroup').format(self.impl_get_display_name()))
|
||||
if not child.impl_is_multi():
|
||||
raise ValueError(
|
||||
_(
|
||||
"only multi option allowed in leadership {0} but option "
|
||||
"{1} is not a multi"
|
||||
""
|
||||
).format(
|
||||
self.impl_get_display_name(None, with_quote=True),
|
||||
child.impl_get_display_name(None, with_quote=True),
|
||||
)
|
||||
)
|
||||
raise ValueError(_('only multi option allowed in leadership "{0}" but option '
|
||||
'"{1}" is not a multi'
|
||||
'').format(self.impl_get_display_name(),
|
||||
child.impl_get_display_name()))
|
||||
|
||||
def _check_default_value(self, child: BaseOption):
|
||||
if child.impl_is_symlinkoption():
|
||||
return
|
||||
default = child.impl_getdefault()
|
||||
if default != []:
|
||||
if child.impl_is_submulti() and isinstance(default, (list, tuple)):
|
||||
|
@ -137,115 +99,111 @@ class Leadership(OptionDescription):
|
|||
else:
|
||||
calculation = isinstance(default, Calculation)
|
||||
if not calculation:
|
||||
raise ValueError(
|
||||
_(
|
||||
"not allowed default value for follower option {0} in leadership {1}"
|
||||
).format(
|
||||
child.impl_get_display_name(None, with_quote=True),
|
||||
self.impl_get_display_name(None, with_quote=True),
|
||||
)
|
||||
)
|
||||
raise ValueError(_('not allowed default value for follower option '
|
||||
f'"{child.impl_get_display_name()}" in leadership '
|
||||
f'"{self.impl_get_display_name()}"'))
|
||||
|
||||
def _setsubdyn(
|
||||
self,
|
||||
subdyn,
|
||||
) -> None:
|
||||
def _setsubdyn(self,
|
||||
subdyn,
|
||||
) -> None:
|
||||
for chld in self._children[1]:
|
||||
chld._setsubdyn(subdyn)
|
||||
super()._setsubdyn(subdyn)
|
||||
|
||||
def is_leader(
|
||||
self,
|
||||
opt: Option,
|
||||
) -> bool:
|
||||
"""the option is the leader"""
|
||||
def is_leader(self,
|
||||
opt: Option,
|
||||
) -> bool:
|
||||
"""the option is the leader
|
||||
"""
|
||||
leader = self.get_leader()
|
||||
if opt.impl_is_dynsymlinkoption():
|
||||
opt = opt.opt
|
||||
return opt == leader
|
||||
|
||||
def get_leader(self) -> Option:
|
||||
"""get leader"""
|
||||
"""get leader
|
||||
"""
|
||||
return self._children[1][0]
|
||||
|
||||
def get_followers(self) -> Iterator[Option]:
|
||||
"""get all followers"""
|
||||
"""get all followers
|
||||
"""
|
||||
for follower in self._children[1][1:]:
|
||||
yield follower
|
||||
|
||||
def in_same_leadership(
|
||||
self,
|
||||
opt: Option,
|
||||
) -> bool:
|
||||
"""check if followers are in same leadership"""
|
||||
def in_same_leadership(self,
|
||||
opt: Option,
|
||||
) -> bool:
|
||||
"""check if followers are in same leadership
|
||||
"""
|
||||
if opt.impl_is_dynsymlinkoption():
|
||||
opt = opt.opt
|
||||
return opt in self._children[1]
|
||||
|
||||
def reset(self, parent: "SubConfig") -> None:
|
||||
"""reset follower value"""
|
||||
"""reset follower value
|
||||
"""
|
||||
#config_bag = parent.option_bag.config_bag
|
||||
values = parent.config_bag.context.get_values()
|
||||
#config_bag = config_bag.copy()
|
||||
#config_bag.remove_validation()
|
||||
for follower in self.get_followers():
|
||||
subconfig_follower = parent.get_child(
|
||||
follower,
|
||||
None,
|
||||
False,
|
||||
)
|
||||
values.reset(
|
||||
subconfig_follower,
|
||||
validate=False,
|
||||
)
|
||||
subconfig_follower = parent.get_child(follower,
|
||||
None,
|
||||
False,
|
||||
)
|
||||
# OptionBag(follower,
|
||||
# None,
|
||||
# config_bag,
|
||||
# )
|
||||
values.reset(subconfig_follower)
|
||||
#
|
||||
# def follower_force_store_value(self,
|
||||
# value,
|
||||
# config_bag: 'ConfigBag',
|
||||
# owner,
|
||||
# dyn=None,
|
||||
# ) -> None:
|
||||
# """apply force_store_value to follower
|
||||
# """
|
||||
# if value:
|
||||
# if dyn is None:
|
||||
# dyn = self
|
||||
# values = config_bag.context.get_values()
|
||||
# for idx, follower in enumerate(dyn.get_children(config_bag)):
|
||||
# if not idx:
|
||||
# # it's a master
|
||||
# apply_requires = True
|
||||
# indexes = [None]
|
||||
# else:
|
||||
# apply_requires = False
|
||||
# indexes = range(len(value))
|
||||
# foption_bag = OptionBag(follower,
|
||||
# None,
|
||||
# config_bag,
|
||||
# apply_requires=apply_requires,
|
||||
# )
|
||||
# if 'force_store_value' not in foption_bag.properties:
|
||||
# continue
|
||||
# for index in indexes:
|
||||
# foption_bag_index = OptionBag(follower,
|
||||
# index,
|
||||
# config_bag,
|
||||
# )
|
||||
# values.set_storage_value(foption_bag_index.path,
|
||||
# index,
|
||||
# values.get_value(foption_bag_index)[0],
|
||||
# owner,
|
||||
# )
|
||||
|
||||
def follower_force_store_value(
|
||||
self,
|
||||
value,
|
||||
subconfig: "SubConfig",
|
||||
owner,
|
||||
) -> None:
|
||||
"""apply force_store_value to follower"""
|
||||
if not value:
|
||||
return
|
||||
config_bag = subconfig.config_bag
|
||||
values = config_bag.context.get_values()
|
||||
for idx, follower in enumerate(self.get_children()):
|
||||
sub_subconfig = subconfig.get_child(
|
||||
follower,
|
||||
None,
|
||||
False,
|
||||
config_bag=config_bag,
|
||||
)
|
||||
if "force_store_value" not in sub_subconfig.properties:
|
||||
continue
|
||||
self_path = sub_subconfig.path
|
||||
if not idx:
|
||||
# it's a master
|
||||
apply_requires = True
|
||||
indexes = [None]
|
||||
else:
|
||||
apply_requires = False
|
||||
indexes = range(len(value))
|
||||
for index in indexes:
|
||||
i_sub_subconfig = subconfig.get_child(
|
||||
follower,
|
||||
index,
|
||||
False,
|
||||
config_bag=config_bag,
|
||||
)
|
||||
values.set_storage_value(
|
||||
self_path,
|
||||
index,
|
||||
values.get_value(i_sub_subconfig)[0],
|
||||
owner,
|
||||
)
|
||||
|
||||
def pop(
|
||||
self,
|
||||
subconfig: "SubConfig",
|
||||
index: int,
|
||||
*,
|
||||
followers: Optional[List[Option]] = undefined,
|
||||
) -> None:
|
||||
"""pop leader value and follower's one"""
|
||||
def pop(self,
|
||||
subconfig: 'SubConfig',
|
||||
index: int,
|
||||
*,
|
||||
followers: Optional[List[Option]]=undefined,
|
||||
) -> None:
|
||||
"""pop leader value and follower's one
|
||||
"""
|
||||
if followers is undefined:
|
||||
# followers are not undefined only in SynDynLeadership
|
||||
followers = self.get_followers()
|
||||
|
@ -253,58 +211,60 @@ class Leadership(OptionDescription):
|
|||
config_bag.remove_validation()
|
||||
values = config_bag.context.get_values()
|
||||
for follower in followers:
|
||||
sub_subconfig = subconfig.parent.get_child(
|
||||
follower,
|
||||
index,
|
||||
True,
|
||||
properties=set(), # do not check force_default_on_freeze
|
||||
# or force_metaconfig_on_freeze
|
||||
config_bag=config_bag,
|
||||
)
|
||||
sub_subconfig = subconfig.parent.get_child(follower,
|
||||
index,
|
||||
True,
|
||||
properties=set(), # do not check force_default_on_freeze
|
||||
# or force_metaconfig_on_freeze
|
||||
config_bag=config_bag,
|
||||
)
|
||||
values.reduce_index(sub_subconfig)
|
||||
|
||||
def reset_cache(
|
||||
self,
|
||||
path: str,
|
||||
config_bag: "ConfigBag",
|
||||
resetted_opts: List[Option],
|
||||
) -> None:
|
||||
self._reset_cache(
|
||||
path,
|
||||
self.get_leader(),
|
||||
self.get_followers(),
|
||||
config_bag,
|
||||
resetted_opts,
|
||||
)
|
||||
def reset_cache(self,
|
||||
path: str,
|
||||
config_bag: 'ConfigBag',
|
||||
resetted_opts: List[Option],
|
||||
) -> None:
|
||||
self._reset_cache(path,
|
||||
self.get_leader(),
|
||||
self.get_followers(),
|
||||
config_bag,
|
||||
resetted_opts,
|
||||
)
|
||||
|
||||
def _reset_cache(
|
||||
self,
|
||||
path: str,
|
||||
leader: Option,
|
||||
followers: List[Option],
|
||||
config_bag: "ConfigBag",
|
||||
resetted_opts: List[Option],
|
||||
) -> None:
|
||||
super().reset_cache(
|
||||
path,
|
||||
config_bag,
|
||||
resetted_opts,
|
||||
)
|
||||
def _reset_cache(self,
|
||||
path: str,
|
||||
leader: Option,
|
||||
followers: List[Option],
|
||||
config_bag: 'ConfigBag',
|
||||
resetted_opts: List[Option],
|
||||
) -> None:
|
||||
super().reset_cache(path,
|
||||
config_bag,
|
||||
resetted_opts,
|
||||
)
|
||||
leader_path = leader.impl_getpath()
|
||||
if leader_path not in resetted_opts:
|
||||
leader.reset_cache(
|
||||
leader_path,
|
||||
config_bag,
|
||||
resetted_opts,
|
||||
)
|
||||
leader.reset_cache(leader_path,
|
||||
config_bag,
|
||||
resetted_opts,
|
||||
)
|
||||
for follower in followers:
|
||||
follower_path = follower.impl_getpath()
|
||||
if follower_path not in resetted_opts:
|
||||
follower.reset_cache(
|
||||
follower_path,
|
||||
config_bag,
|
||||
resetted_opts,
|
||||
)
|
||||
follower.reset_cache(follower_path,
|
||||
config_bag,
|
||||
resetted_opts,
|
||||
)
|
||||
|
||||
def impl_is_leadership(self) -> None:
|
||||
return True
|
||||
#
|
||||
# def to_dynoption(self,
|
||||
# rootpath: str,
|
||||
# suffixes: Optional[list],
|
||||
# ) -> SynDynLeadership:
|
||||
# return SynDynLeadership(self,
|
||||
# rootpath,
|
||||
# suffixes,
|
||||
# )
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2020-2024 Team tiramisu (see AUTHORS for all contributors)
|
||||
# Copyright (C) 2020-2023 Team tiramisu (see AUTHORS for all contributors)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by the
|
||||
|
@ -27,8 +27,8 @@ from .stroption import RegexpOption
|
|||
|
||||
|
||||
class MACOption(RegexpOption):
|
||||
"""represents the choice of a mac address"""
|
||||
|
||||
"""represents the choice of a mac address
|
||||
"""
|
||||
__slots__ = tuple()
|
||||
_regexp = re.compile(r"^([0-9A-Fa-f]{2}[:]){5}([0-9A-Fa-f]{2})$")
|
||||
_type = "mac address"
|
||||
_type = _('mac address')
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2017-2024 Team tiramisu (see AUTHORS for all contributors)
|
||||
# Copyright (C) 2017-2023 Team tiramisu (see AUTHORS for all contributors)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by the
|
||||
|
@ -26,17 +26,18 @@ from .stroption import StrOption
|
|||
|
||||
|
||||
class NetmaskOption(StrOption):
|
||||
"""represents the choice of a netmask"""
|
||||
|
||||
"""represents the choice of a netmask
|
||||
"""
|
||||
__slots__ = tuple()
|
||||
_type = "netmask address"
|
||||
_type = _('netmask address')
|
||||
|
||||
def validate(self, value: str) -> None:
|
||||
def validate(self,
|
||||
value: str) -> None:
|
||||
super().validate(value)
|
||||
for val in value.split("."):
|
||||
for val in value.split('.'):
|
||||
if val.startswith("0") and len(val) > 1:
|
||||
raise ValueError()
|
||||
try:
|
||||
ip_network(f"0.0.0.0/{value}")
|
||||
ip_network(f'0.0.0.0/{value}')
|
||||
except ValueError as err:
|
||||
raise ValueError() from err
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2017-2024 Team tiramisu (see AUTHORS for all contributors)
|
||||
# Copyright (C) 2017-2023 Team tiramisu (see AUTHORS for all contributors)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by the
|
||||
|
@ -29,24 +29,30 @@ from .stroption import StrOption
|
|||
class NetworkOption(StrOption):
|
||||
"represents the choice of a network"
|
||||
__slots__ = tuple()
|
||||
_type = "network address"
|
||||
_type = _('network address')
|
||||
|
||||
def __init__(self, *args, cidr=False, **kwargs):
|
||||
extra = {"_cidr": cidr}
|
||||
super().__init__(*args, extra=extra, **kwargs)
|
||||
def __init__(self,
|
||||
*args,
|
||||
cidr=False,
|
||||
**kwargs):
|
||||
extra = {'_cidr': cidr}
|
||||
super().__init__(*args,
|
||||
extra=extra,
|
||||
**kwargs)
|
||||
|
||||
def validate(self, value: str) -> None:
|
||||
def validate(self,
|
||||
value: str) -> None:
|
||||
super().validate(value)
|
||||
if value.count(".") != 3:
|
||||
if value.count('.') != 3:
|
||||
raise ValueError()
|
||||
cidr = self.impl_get_extra("_cidr")
|
||||
cidr = self.impl_get_extra('_cidr')
|
||||
if cidr:
|
||||
if "/" not in value:
|
||||
raise ValueError(_("must use CIDR notation"))
|
||||
value_ = value.split("/")[0]
|
||||
if '/' not in value:
|
||||
raise ValueError(_('must use CIDR notation'))
|
||||
value_ = value.split('/')[0]
|
||||
else:
|
||||
value_ = value
|
||||
for val in value_.split("."):
|
||||
for val in value_.split('.'):
|
||||
if val.startswith("0") and len(val) > 1:
|
||||
raise ValueError()
|
||||
try:
|
||||
|
@ -54,7 +60,9 @@ class NetworkOption(StrOption):
|
|||
except ValueError as err:
|
||||
raise ValueError() from err
|
||||
|
||||
def second_level_validation(self, value: str, warnings_only: bool) -> None:
|
||||
def second_level_validation(self,
|
||||
value: str,
|
||||
warnings_only: bool) -> None:
|
||||
if ip_network(value).network_address.is_reserved:
|
||||
if warnings_only:
|
||||
msg = _("shouldn't be reserved network")
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"option types and option description"
|
||||
# Copyright (C) 2012-2024 Team tiramisu (see AUTHORS for all contributors)
|
||||
# Copyright (C) 2012-2023 Team tiramisu (see AUTHORS for all contributors)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by the
|
||||
|
@ -26,8 +26,9 @@ from itertools import chain
|
|||
from .baseoption import BaseOption, submulti
|
||||
from ..i18n import _
|
||||
from ..setting import undefined
|
||||
from ..autolib import Calculation
|
||||
from ..autolib import Calculation, ParamOption, ParamInformation, ParamSelfInformation
|
||||
from ..error import ValueWarning, ValueErrorWarning, ValueOptionError
|
||||
from .syndynoption import SynDynOption
|
||||
|
||||
|
||||
class Option(BaseOption):
|
||||
|
@ -37,43 +38,36 @@ class Option(BaseOption):
|
|||
|
||||
Reminder: an Option object is **not** a container for the value.
|
||||
"""
|
||||
__slots__ = (
|
||||
"_extra",
|
||||
"_warnings_only",
|
||||
# multi
|
||||
"_multi",
|
||||
# value
|
||||
"_default",
|
||||
"_default_multi",
|
||||
#
|
||||
"_validators",
|
||||
#
|
||||
"_leadership",
|
||||
"_choice_values",
|
||||
"_choice_values_params",
|
||||
)
|
||||
__slots__ = ('_extra',
|
||||
'_warnings_only',
|
||||
# multi
|
||||
'_multi',
|
||||
# value
|
||||
'_default',
|
||||
'_default_multi',
|
||||
#
|
||||
'_validators',
|
||||
#
|
||||
'_dependencies_information',
|
||||
'_leadership',
|
||||
'_choice_values',
|
||||
'_choice_values_params',
|
||||
)
|
||||
_type = None
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
doc: str,
|
||||
default: Any = undefined,
|
||||
default_multi: Any = None,
|
||||
multi: bool = False,
|
||||
validators: Optional[List[Calculation]] = None,
|
||||
properties: Optional[List[str]] = None,
|
||||
warnings_only: bool = False,
|
||||
extra: Optional[Dict] = None,
|
||||
informations: Optional[Dict] = None,
|
||||
):
|
||||
def __init__(self,
|
||||
name: str,
|
||||
doc: str,
|
||||
default: Any=undefined,
|
||||
default_multi: Any=None,
|
||||
multi: bool=False,
|
||||
validators: Optional[List[Calculation]]=None,
|
||||
properties: Optional[List[str]]=None,
|
||||
warnings_only: bool=False,
|
||||
extra: Optional[Dict]=None):
|
||||
_setattr = object.__setattr__
|
||||
if not multi and default_multi is not None:
|
||||
raise ValueError(
|
||||
_(
|
||||
"default_multi is set whereas multi is False" " in option: {0}"
|
||||
).format(name)
|
||||
)
|
||||
raise ValueError(_("default_multi is set whereas multi is False"
|
||||
" in option: {0}").format(name))
|
||||
if default is undefined:
|
||||
if multi is False:
|
||||
default = None
|
||||
|
@ -89,140 +83,152 @@ class Option(BaseOption):
|
|||
is_multi = True
|
||||
_multi = submulti
|
||||
else:
|
||||
raise ValueError(
|
||||
_('invalid multi type "{}" for "{}"').format(
|
||||
multi,
|
||||
name,
|
||||
)
|
||||
)
|
||||
raise ValueError(_('invalid multi type "{}" for "{}"').format(multi,
|
||||
name,
|
||||
))
|
||||
if _multi != 1:
|
||||
_setattr(self, "_multi", _multi)
|
||||
_setattr(self, '_multi', _multi)
|
||||
if multi is not False and default is None:
|
||||
default = []
|
||||
super().__init__(
|
||||
name,
|
||||
doc,
|
||||
informations,
|
||||
properties=properties,
|
||||
is_multi=is_multi,
|
||||
)
|
||||
super().__init__(name,
|
||||
doc,
|
||||
properties=properties,
|
||||
is_multi=is_multi)
|
||||
if validators is not None:
|
||||
if __debug__ and not isinstance(validators, list):
|
||||
raise ValueError(
|
||||
_('validators must be a list of Calculation for "{0}"').format(name)
|
||||
)
|
||||
raise ValueError(_(f'validators must be a list of Calculation for "{name}"'))
|
||||
for validator in validators:
|
||||
if __debug__ and not isinstance(validator, Calculation):
|
||||
raise ValueError(
|
||||
_('validators must be a Calculation for "{0}"').format(name)
|
||||
)
|
||||
raise ValueError(_('validators must be a Calculation for "{}"').format(name))
|
||||
self.value_dependency(validator)
|
||||
self._validators = tuple(validators)
|
||||
if extra is not None and extra != {}:
|
||||
_setattr(self, "_extra", extra)
|
||||
_setattr(self, '_extra', extra)
|
||||
if warnings_only is True:
|
||||
_setattr(self, "_warnings_only", warnings_only)
|
||||
_setattr(self, '_warnings_only', warnings_only)
|
||||
if is_multi and default_multi is not None:
|
||||
|
||||
def test_multi_value(value):
|
||||
if isinstance(value, Calculation):
|
||||
return
|
||||
# option_bag = OptionBag(self,
|
||||
# None,
|
||||
# undefined,
|
||||
# properties=None,
|
||||
# )
|
||||
# option_bag = OptionBag(self,
|
||||
# None,
|
||||
# undefined,
|
||||
# properties=None,
|
||||
# )
|
||||
try:
|
||||
self.validate(value)
|
||||
self.validate_with_option(
|
||||
value,
|
||||
None,
|
||||
loaded=True,
|
||||
)
|
||||
self.validate_with_option(value,
|
||||
None,
|
||||
loaded=True,
|
||||
)
|
||||
except ValueError as err:
|
||||
str_err = str(err)
|
||||
if not str_err:
|
||||
raise ValueError(
|
||||
_(
|
||||
'invalid default_multi value "{0}" ' "for option {1}"
|
||||
).format(
|
||||
str(value),
|
||||
self.impl_get_display_name(None, with_quote=True),
|
||||
)
|
||||
) 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
|
||||
|
||||
raise ValueError(_('invalid default_multi value "{0}" '
|
||||
'for option "{1}"').format(str(value),
|
||||
self.impl_get_display_name())
|
||||
) from err
|
||||
raise ValueError(_(f'invalid default_multi value "{value}" for option '
|
||||
f'"{self.impl_get_display_name()}", {str_err}')
|
||||
) from err
|
||||
if _multi is submulti:
|
||||
if not isinstance(default_multi, Calculation):
|
||||
if not isinstance(default_multi, list):
|
||||
raise ValueError(
|
||||
_(
|
||||
'invalid default_multi value "{0}" '
|
||||
"for option {1}, must be a list for a submulti"
|
||||
""
|
||||
).format(
|
||||
str(default_multi),
|
||||
self.impl_get_display_name(None, with_quote=True),
|
||||
)
|
||||
)
|
||||
raise ValueError(_('invalid default_multi value "{0}" '
|
||||
'for option "{1}", must be a list for a submulti'
|
||||
'').format(str(default_multi),
|
||||
self.impl_get_display_name()))
|
||||
for value in default_multi:
|
||||
test_multi_value(value)
|
||||
else:
|
||||
test_multi_value(default_multi)
|
||||
_setattr(self, "_default_multi", default_multi)
|
||||
# option_bag = OptionBag(self,
|
||||
# None,
|
||||
# undefined,
|
||||
# properties=None,
|
||||
# )
|
||||
self.impl_validate(
|
||||
None,
|
||||
default,
|
||||
loaded=True,
|
||||
)
|
||||
self.impl_validate(
|
||||
None,
|
||||
default,
|
||||
check_error=False,
|
||||
loaded=True,
|
||||
)
|
||||
_setattr(self, '_default_multi', default_multi)
|
||||
# option_bag = OptionBag(self,
|
||||
# None,
|
||||
# undefined,
|
||||
# properties=None,
|
||||
# )
|
||||
self.impl_validate(None,
|
||||
default,
|
||||
loaded=True,
|
||||
)
|
||||
self.impl_validate(None,
|
||||
default,
|
||||
check_error=False,
|
||||
loaded=True,
|
||||
)
|
||||
self.value_dependencies(default)
|
||||
if (is_multi and default != []) or (not is_multi and default is not None):
|
||||
if (is_multi and default != []) or \
|
||||
(not is_multi and default is not None):
|
||||
if is_multi and isinstance(default, list):
|
||||
default = tuple(default)
|
||||
_setattr(self, "_default", default)
|
||||
_setattr(self, '_default', default)
|
||||
|
||||
# __________________________________________________________________________
|
||||
def value_dependencies(self,
|
||||
value: Any,
|
||||
) -> Any:
|
||||
"""parse dependancies to add dependencies
|
||||
"""
|
||||
if isinstance(value, list):
|
||||
for val in value:
|
||||
if isinstance(value, list):
|
||||
self.value_dependencies(val)
|
||||
elif isinstance(value, Calculation):
|
||||
self.value_dependency(val)
|
||||
elif isinstance(value, Calculation):
|
||||
self.value_dependency(value)
|
||||
|
||||
def value_dependency(self,
|
||||
value: Any,
|
||||
) -> Any:
|
||||
"""parse dependancy to add dependencies
|
||||
"""
|
||||
for param in chain(value.params.args, value.params.kwargs.values()):
|
||||
if isinstance(param, ParamOption):
|
||||
# pylint: disable=protected-access
|
||||
param.option._add_dependency(self)
|
||||
self._has_dependency = True
|
||||
elif isinstance(param, ParamInformation):
|
||||
dest = self
|
||||
if isinstance(param, ParamSelfInformation):
|
||||
opt = self
|
||||
elif param.option:
|
||||
dest = param.option
|
||||
opt = self
|
||||
else:
|
||||
opt = None
|
||||
if not getattr(dest, '_dependencies_information', {}):
|
||||
dest._dependencies_information = {}
|
||||
dest._dependencies_information.setdefault(param.information_name, []).append(opt)
|
||||
|
||||
#__________________________________________________________________________
|
||||
# option's information
|
||||
|
||||
def impl_is_multi(self) -> bool:
|
||||
"""is it a multi option"""
|
||||
return getattr(self, "_multi", 1) != 1
|
||||
"""is it a multi option
|
||||
"""
|
||||
return getattr(self, '_multi', 1) != 1
|
||||
|
||||
def impl_is_submulti(self) -> bool:
|
||||
"""is it a submulti option"""
|
||||
return getattr(self, "_multi", 1) == 2
|
||||
"""is it a submulti option
|
||||
"""
|
||||
return getattr(self, '_multi', 1) == 2
|
||||
|
||||
def impl_is_dynsymlinkoption(self) -> bool:
|
||||
"""is a dynsymlinkoption?"""
|
||||
"""is a dynsymlinkoption?
|
||||
"""
|
||||
return False
|
||||
|
||||
def get_type(self) -> str:
|
||||
"""get the type of option"""
|
||||
"""get the type of option
|
||||
"""
|
||||
return self._type
|
||||
|
||||
def impl_getdefault(self) -> Any:
|
||||
"""accessing the default value"""
|
||||
"""accessing the default value
|
||||
"""
|
||||
is_multi = self.impl_is_multi()
|
||||
default = getattr(self, "_default", undefined)
|
||||
default = getattr(self, '_default', undefined)
|
||||
if default is undefined:
|
||||
if is_multi:
|
||||
default = []
|
||||
|
@ -233,186 +239,162 @@ class Option(BaseOption):
|
|||
return default
|
||||
|
||||
def impl_getdefault_multi(self) -> Any:
|
||||
"""accessing the default value for a multi"""
|
||||
"""accessing the default value for a multi
|
||||
"""
|
||||
if self.impl_is_submulti():
|
||||
default_value = []
|
||||
else:
|
||||
default_value = None
|
||||
return getattr(self, "_default_multi", default_value)
|
||||
return getattr(self, '_default_multi', default_value)
|
||||
|
||||
def impl_get_extra(
|
||||
self,
|
||||
key: str,
|
||||
) -> Any:
|
||||
"""if extra parameters are store get it"""
|
||||
extra = getattr(self, "_extra", {})
|
||||
def impl_get_extra(self,
|
||||
key: str,
|
||||
) -> Any:
|
||||
"""if extra parameters are store get it
|
||||
"""
|
||||
extra = getattr(self, '_extra', {})
|
||||
if isinstance(extra, tuple):
|
||||
if key in extra[0]:
|
||||
return extra[1][extra[0].index(key)]
|
||||
return None
|
||||
return extra.get(key)
|
||||
|
||||
# __________________________________________________________________________
|
||||
#__________________________________________________________________________
|
||||
# validator
|
||||
def impl_validate(
|
||||
self,
|
||||
subconfig: Optional["SubConfig"],
|
||||
value: Any,
|
||||
*,
|
||||
check_error: bool = True,
|
||||
loaded: bool = False,
|
||||
) -> bool:
|
||||
def impl_validate(self,
|
||||
subconfig: Optional["SubConfig"],
|
||||
value: Any,
|
||||
*,
|
||||
check_error: bool=True,
|
||||
loaded: bool=False,
|
||||
) -> bool:
|
||||
"""Return True if value is really valid
|
||||
If not validate or invalid return it returns False
|
||||
"""
|
||||
if (
|
||||
check_error
|
||||
and subconfig
|
||||
and not "validator" in subconfig.config_bag.properties
|
||||
):
|
||||
if check_error and subconfig and \
|
||||
not 'validator' in subconfig.config_bag.properties:
|
||||
return False
|
||||
if subconfig:
|
||||
force_index = subconfig.index
|
||||
else:
|
||||
force_index = None
|
||||
is_warnings_only = getattr(self, "_warnings_only", False)
|
||||
is_warnings_only = getattr(self, '_warnings_only', False)
|
||||
|
||||
def _is_not_unique(value):
|
||||
# if set(value) has not same length than value
|
||||
if not subconfig or not check_error or "unique" not in subconfig.properties:
|
||||
if not subconfig or not check_error or \
|
||||
'unique' not in subconfig.properties:
|
||||
return
|
||||
lvalue = [val for val in value if val is not None]
|
||||
if len(set(lvalue)) == len(lvalue):
|
||||
return
|
||||
for idx, val in enumerate(value):
|
||||
if val not in value[idx + 1 :]:
|
||||
if val not in value[idx+1:]:
|
||||
continue
|
||||
raise ValueError(_('the value "{}" is not unique' "").format(val))
|
||||
raise ValueError(_('the value "{}" is not unique'
|
||||
'').format(val))
|
||||
|
||||
def calculation_validator(
|
||||
val,
|
||||
_index,
|
||||
):
|
||||
for validator in getattr(self, "_validators", []):
|
||||
calc_is_warnings_only = (
|
||||
hasattr(validator, "warnings_only") and validator.warnings_only
|
||||
)
|
||||
if (check_error and not calc_is_warnings_only) or (
|
||||
not check_error and calc_is_warnings_only
|
||||
):
|
||||
def calculation_validator(val,
|
||||
_index,
|
||||
):
|
||||
for validator in getattr(self, '_validators', []):
|
||||
calc_is_warnings_only = hasattr(validator, 'warnings_only') and \
|
||||
validator.warnings_only
|
||||
if ((check_error and not calc_is_warnings_only) or
|
||||
(not check_error and calc_is_warnings_only)):
|
||||
try:
|
||||
kwargs = {
|
||||
"allow_value_error": True,
|
||||
"force_value_warning": calc_is_warnings_only,
|
||||
}
|
||||
kwargs = {'allow_value_error': True,
|
||||
'force_value_warning': calc_is_warnings_only,
|
||||
}
|
||||
if _index is not None and subconfig.index == _index:
|
||||
lsubconfig = subconfig
|
||||
else:
|
||||
identifier = subconfig.identifiers
|
||||
if identifier is not None:
|
||||
identifier = identifier[-1]
|
||||
lsubconfig = subconfig.parent.get_child(
|
||||
subconfig.option,
|
||||
_index,
|
||||
False,
|
||||
properties=subconfig.properties,
|
||||
identifier=identifier,
|
||||
name=subconfig.path.rsplit(".", 1)[-1],
|
||||
check_index=False,
|
||||
)
|
||||
kwargs["orig_value"] = value
|
||||
suffix = subconfig.suffixes
|
||||
if suffix is not None:
|
||||
suffix = suffix[-1]
|
||||
lsubconfig = subconfig.parent.get_child(subconfig.option,
|
||||
_index,
|
||||
False,
|
||||
properties=subconfig.properties,
|
||||
suffix=suffix,
|
||||
name=subconfig.path.rsplit('.', 1)[-1],
|
||||
check_index=False,
|
||||
)
|
||||
kwargs['orig_value'] = value
|
||||
|
||||
validator.execute(
|
||||
lsubconfig,
|
||||
**kwargs,
|
||||
)
|
||||
validator.execute(lsubconfig,
|
||||
**kwargs,
|
||||
)
|
||||
except ValueWarning as warn:
|
||||
warnings.warn_explicit(
|
||||
ValueWarning(
|
||||
subconfig,
|
||||
val,
|
||||
_(self.get_type()),
|
||||
self,
|
||||
str(warn),
|
||||
_index,
|
||||
),
|
||||
ValueWarning,
|
||||
self.__class__.__name__,
|
||||
319,
|
||||
)
|
||||
warnings.warn_explicit(ValueWarning(val,
|
||||
self.get_type(),
|
||||
self,
|
||||
str(warn),
|
||||
_index,
|
||||
),
|
||||
ValueWarning,
|
||||
self.__class__.__name__, 319)
|
||||
|
||||
def do_validation(
|
||||
_value,
|
||||
_index,
|
||||
):
|
||||
def do_validation(_value,
|
||||
_index,
|
||||
):
|
||||
#
|
||||
if _value is None:
|
||||
return
|
||||
if isinstance(_value, list):
|
||||
raise ValueError(_("which must not be a list"))
|
||||
raise ValueError(_('which must not be a list').format(_value,
|
||||
self.impl_get_display_name()),
|
||||
)
|
||||
if isinstance(_value, Calculation) and not subconfig:
|
||||
return
|
||||
# option validation
|
||||
if check_error:
|
||||
self.validate(_value)
|
||||
self.validate_with_option(
|
||||
_value,
|
||||
subconfig,
|
||||
loaded=loaded,
|
||||
)
|
||||
self.validate_with_option(_value,
|
||||
subconfig,
|
||||
loaded=loaded,
|
||||
)
|
||||
# second level validation
|
||||
if (check_error and not is_warnings_only) or (
|
||||
not check_error and is_warnings_only
|
||||
):
|
||||
if (check_error and not is_warnings_only) or (not check_error and is_warnings_only):
|
||||
try:
|
||||
self.second_level_validation(_value, is_warnings_only)
|
||||
self.second_level_validation(_value,
|
||||
is_warnings_only)
|
||||
except ValueError as err:
|
||||
if is_warnings_only:
|
||||
warnings.warn_explicit(
|
||||
ValueWarning(
|
||||
subconfig,
|
||||
_value,
|
||||
_(self.get_type()),
|
||||
self,
|
||||
str(err),
|
||||
_index,
|
||||
),
|
||||
ValueWarning,
|
||||
self.__class__.__name__,
|
||||
0,
|
||||
)
|
||||
warnings.warn_explicit(ValueWarning(_value,
|
||||
self.get_type(),
|
||||
self,
|
||||
str(err),
|
||||
_index),
|
||||
ValueWarning,
|
||||
self.__class__.__name__, 0)
|
||||
else:
|
||||
raise err from err
|
||||
# ?
|
||||
if not loaded:
|
||||
calculation_validator(
|
||||
_value,
|
||||
_index,
|
||||
)
|
||||
|
||||
calculation_validator(_value,
|
||||
_index,
|
||||
)
|
||||
val = value
|
||||
err_index = force_index
|
||||
try:
|
||||
if not self.impl_is_multi():
|
||||
do_validation(
|
||||
val,
|
||||
None,
|
||||
)
|
||||
do_validation(val,
|
||||
None,
|
||||
)
|
||||
elif force_index is not None:
|
||||
if self.impl_is_submulti():
|
||||
if not isinstance(value, list):
|
||||
raise ValueError(_("which must be a list"))
|
||||
raise ValueError(_('which must be a list'))
|
||||
for val in value:
|
||||
do_validation(
|
||||
val,
|
||||
force_index,
|
||||
)
|
||||
do_validation(val,
|
||||
force_index,
|
||||
)
|
||||
_is_not_unique(value)
|
||||
else:
|
||||
do_validation(
|
||||
val,
|
||||
force_index,
|
||||
)
|
||||
do_validation(val,
|
||||
force_index,
|
||||
)
|
||||
elif isinstance(value, Calculation) and not subconfig:
|
||||
pass
|
||||
elif self.impl_is_submulti():
|
||||
|
@ -420,79 +402,91 @@ class Option(BaseOption):
|
|||
if isinstance(lval, Calculation):
|
||||
continue
|
||||
if not isinstance(lval, list):
|
||||
raise ValueError(
|
||||
_('which "{}" must be a list of list' "").format(lval)
|
||||
)
|
||||
raise ValueError(_('which "{}" must be a list of list'
|
||||
'').format(lval))
|
||||
for val in lval:
|
||||
do_validation(val, err_index)
|
||||
do_validation(val,
|
||||
err_index)
|
||||
_is_not_unique(lval)
|
||||
elif not isinstance(value, list):
|
||||
raise ValueError(_("which must be a list"))
|
||||
raise ValueError(_('which must be a list'))
|
||||
else:
|
||||
# FIXME suboptimal, not several time for whole=True!
|
||||
for err_index, val in enumerate(value):
|
||||
do_validation(
|
||||
val,
|
||||
err_index,
|
||||
)
|
||||
do_validation(val,
|
||||
err_index,
|
||||
)
|
||||
_is_not_unique(value)
|
||||
except ValueError as err:
|
||||
if (
|
||||
not subconfig
|
||||
or "demoting_error_warning" not in subconfig.config_bag.properties
|
||||
):
|
||||
raise ValueOptionError(
|
||||
subconfig, val, _(self.get_type()), self, str(err), err_index
|
||||
) from err
|
||||
warnings.warn_explicit(
|
||||
ValueErrorWarning(
|
||||
subconfig, val, _(self.get_type()), self, str(err), err_index
|
||||
),
|
||||
ValueErrorWarning,
|
||||
self.__class__.__name__,
|
||||
0,
|
||||
)
|
||||
if not subconfig or \
|
||||
'demoting_error_warning' not in subconfig.config_bag.properties:
|
||||
raise ValueOptionError(val,
|
||||
self.get_type(),
|
||||
self,
|
||||
str(err),
|
||||
err_index) from err
|
||||
warnings.warn_explicit(ValueErrorWarning(val,
|
||||
self.get_type(),
|
||||
self,
|
||||
str(err),
|
||||
err_index),
|
||||
ValueErrorWarning,
|
||||
self.__class__.__name__, 0)
|
||||
return False
|
||||
return True
|
||||
|
||||
def validate_with_option(
|
||||
self,
|
||||
value: Any,
|
||||
subconfig: "SubConfig",
|
||||
*,
|
||||
loaded: bool,
|
||||
) -> None:
|
||||
"""validation function with option"""
|
||||
def validate_with_option(self,
|
||||
value: Any,
|
||||
subconfig: "SubConfig",
|
||||
*,
|
||||
loaded: bool,
|
||||
) -> None:
|
||||
"""validation function with option
|
||||
"""
|
||||
|
||||
def second_level_validation(
|
||||
self,
|
||||
value: Any,
|
||||
warnings_only: bool,
|
||||
) -> None:
|
||||
"""less import validation function"""
|
||||
def second_level_validation(self,
|
||||
value: Any,
|
||||
warnings_only: bool,
|
||||
) -> None:
|
||||
"""less import validation function
|
||||
"""
|
||||
|
||||
def impl_is_leader(self):
|
||||
"""check if option is a leader in a leadership"""
|
||||
"""check if option is a leader in a leadership
|
||||
"""
|
||||
leadership = self.impl_get_leadership()
|
||||
if leadership is None:
|
||||
return False
|
||||
return leadership.is_leader(self)
|
||||
|
||||
def impl_is_follower(self):
|
||||
"""check if option is a leader in a follower"""
|
||||
"""check if option is a leader in a follower
|
||||
"""
|
||||
leadership = self.impl_get_leadership()
|
||||
if leadership is None:
|
||||
return False
|
||||
return not leadership.is_leader(self)
|
||||
|
||||
def impl_get_leadership(self):
|
||||
"""get leadership"""
|
||||
leadership = getattr(self, "_leadership", None)
|
||||
"""get leadership
|
||||
"""
|
||||
leadership = getattr(self, '_leadership', None)
|
||||
if leadership is None:
|
||||
return leadership
|
||||
# pylint: disable=not-callable
|
||||
#pylint: disable=not-callable
|
||||
return leadership()
|
||||
|
||||
def to_dynoption(self,
|
||||
rootpath: str,
|
||||
suffixes: list[str],
|
||||
) -> SynDynOption:
|
||||
"""tranforme a dynoption to a syndynoption
|
||||
"""
|
||||
return SynDynOption(self,
|
||||
rootpath,
|
||||
suffixes,
|
||||
)
|
||||
def validate(self, value: Any):
|
||||
"""option needs a validate function"""
|
||||
"""option needs a validate function
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2014-2024 Team tiramisu (see AUTHORS for all contributors)
|
||||
# Copyright (C) 2014-2023 Team tiramisu (see AUTHORS for all contributors)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by the
|
||||
|
@ -21,40 +21,39 @@
|
|||
"""OptionDescription
|
||||
"""
|
||||
import weakref
|
||||
from typing import Optional, Iterator, Union, List, Dict
|
||||
from typing import Optional, Iterator, Union, List
|
||||
|
||||
|
||||
from ..i18n import _
|
||||
from ..setting import ConfigBag, groups, undefined, owners, Undefined
|
||||
from .baseoption import BaseOption
|
||||
|
||||
# from .syndynoption import SubDynOptionDescription, SynDynOptionDescription
|
||||
from ..error import ConfigError, ConflictError
|
||||
|
||||
|
||||
class CacheOptionDescription(BaseOption):
|
||||
"""manage cache for option description"""
|
||||
|
||||
__slots__ = (
|
||||
"_cache_force_store_values",
|
||||
"_cache_dependencies_information",
|
||||
)
|
||||
"""manage cache for option description
|
||||
"""
|
||||
__slots__ = ('_cache_force_store_values',
|
||||
'_cache_dependencies_information',
|
||||
)
|
||||
|
||||
def impl_already_build_caches(self) -> bool:
|
||||
"""is a readonly option?"""
|
||||
"""is a readonly option?
|
||||
"""
|
||||
return self.impl_is_readonly()
|
||||
|
||||
def _build_cache(
|
||||
self,
|
||||
display_name,
|
||||
_consistencies=None,
|
||||
_consistencies_id=0,
|
||||
currpath: List[str] = None,
|
||||
cache_option=None,
|
||||
force_store_values=None,
|
||||
dependencies_information=None,
|
||||
) -> None:
|
||||
"""validate options and set option has readonly option"""
|
||||
def _build_cache(self,
|
||||
display_name,
|
||||
_consistencies=None,
|
||||
_consistencies_id=0,
|
||||
currpath: List[str]=None,
|
||||
cache_option=None,
|
||||
force_store_values=None,
|
||||
dependencies_information=None,
|
||||
) -> None:
|
||||
"""validate options and set option has readonly option
|
||||
"""
|
||||
# pylint: disable=too-many-branches,too-many-arguments
|
||||
# _consistencies is None only when we start to build cache
|
||||
if _consistencies is None:
|
||||
|
@ -70,247 +69,202 @@ class CacheOptionDescription(BaseOption):
|
|||
|
||||
if self.impl_is_readonly():
|
||||
# cache already set
|
||||
raise ConfigError(
|
||||
_("option description seems to be part of an other " "config")
|
||||
)
|
||||
raise ConfigError(_('option description seems to be part of an other '
|
||||
'config'))
|
||||
for option in self.get_children():
|
||||
if __debug__:
|
||||
cache_option.append(option)
|
||||
sub_currpath = currpath + [option.impl_getname()]
|
||||
subpath = ".".join(sub_currpath)
|
||||
subpath = '.'.join(sub_currpath)
|
||||
if isinstance(option, OptionDescription):
|
||||
# pylint: disable=protected-access
|
||||
option._build_cache(
|
||||
display_name,
|
||||
_consistencies,
|
||||
_consistencies_id,
|
||||
sub_currpath,
|
||||
cache_option,
|
||||
force_store_values,
|
||||
dependencies_information,
|
||||
)
|
||||
elif not option.impl_is_symlinkoption():
|
||||
informations = option.get_dependencies_information()
|
||||
if informations:
|
||||
for param in informations.pop(None):
|
||||
del param.self_option
|
||||
for (
|
||||
information,
|
||||
options,
|
||||
) in option.get_dependencies_information().items():
|
||||
option._build_cache(display_name,
|
||||
_consistencies,
|
||||
_consistencies_id,
|
||||
sub_currpath,
|
||||
cache_option,
|
||||
force_store_values,
|
||||
dependencies_information,
|
||||
)
|
||||
else:
|
||||
for information, options in option.get_dependencies_information().items():
|
||||
if None in options:
|
||||
dependencies_information.setdefault(information, []).append(
|
||||
option
|
||||
)
|
||||
properties = option.impl_getproperties()
|
||||
if "force_store_value" in properties:
|
||||
force_store_values.append(option)
|
||||
dependencies_information.setdefault(information, []).append(option)
|
||||
if not option.impl_is_symlinkoption():
|
||||
properties = option.impl_getproperties()
|
||||
if 'force_store_value' in properties:
|
||||
force_store_values.append(option)
|
||||
if option.impl_is_readonly():
|
||||
raise ConflictError(_("duplicate option: {0}").format(option))
|
||||
raise ConflictError(_('duplicate option: {0}').format(option))
|
||||
if not self.impl_is_readonly() and display_name:
|
||||
option._display_name_function = (
|
||||
display_name # pylint: disable=protected-access
|
||||
)
|
||||
option._display_name_function = display_name # pylint: disable=protected-access
|
||||
option._path = subpath # pylint: disable=protected-access
|
||||
option._set_readonly() # pylint: disable=protected-access
|
||||
if init:
|
||||
self._cache_force_store_values = (
|
||||
force_store_values # pylint: disable=attribute-defined-outside-init
|
||||
)
|
||||
self._cache_force_store_values = force_store_values # pylint: disable=attribute-defined-outside-init
|
||||
self._cache_dependencies_information = dependencies_information # pylint: disable=attribute-defined-outside-init
|
||||
self._path = (
|
||||
None # pylint: disable=attribute-defined-outside-init,no-member
|
||||
)
|
||||
self._path = None # pylint: disable=attribute-defined-outside-init,no-member
|
||||
self._set_readonly()
|
||||
|
||||
def impl_build_force_store_values(
|
||||
self,
|
||||
config_bag: ConfigBag,
|
||||
) -> None:
|
||||
"""set value to force_store_values option"""
|
||||
# pylint: disable=too-many-branches
|
||||
context = config_bag.context
|
||||
if "force_store_value" not in config_bag.properties:
|
||||
return
|
||||
|
||||
values = config_bag.context.get_values()
|
||||
for option in self._cache_force_store_values:
|
||||
if option.issubdyn():
|
||||
paths = option.impl_getpath().split(".")
|
||||
parents = [config_bag.context.get_root(config_bag)]
|
||||
for name in paths:
|
||||
new_parents = []
|
||||
for parent in parents:
|
||||
doption = parent.option.get_child(
|
||||
name,
|
||||
config_bag,
|
||||
parent,
|
||||
allow_dynoption=True,
|
||||
)
|
||||
if doption.impl_is_dynoptiondescription():
|
||||
new_parents.extend(
|
||||
parent.dyn_to_subconfig(
|
||||
doption,
|
||||
True,
|
||||
)
|
||||
)
|
||||
else:
|
||||
new_parents.append(
|
||||
parent.get_child(
|
||||
doption,
|
||||
None,
|
||||
True,
|
||||
name=name,
|
||||
)
|
||||
)
|
||||
parents = new_parents
|
||||
subconfigs = new_parents
|
||||
else:
|
||||
subconfigs = [
|
||||
context.get_sub_config(
|
||||
config_bag,
|
||||
option.impl_getpath(),
|
||||
None,
|
||||
properties=None,
|
||||
validate_properties=False,
|
||||
)
|
||||
]
|
||||
|
||||
if option.impl_is_follower():
|
||||
for follower_subconfig in subconfigs:
|
||||
parent = follower_subconfig.parent
|
||||
follower_len = parent.get_length_leadership()
|
||||
for index in range(follower_len):
|
||||
if values.hasvalue(
|
||||
follower_subconfig.path,
|
||||
index=index,
|
||||
):
|
||||
continue
|
||||
idx_follower_subconfig = parent.get_child(
|
||||
follower_subconfig.option,
|
||||
index,
|
||||
validate_properties=False,
|
||||
)
|
||||
|
||||
value = values.get_value(idx_follower_subconfig)[0]
|
||||
if value is None:
|
||||
continue
|
||||
values.set_storage_value(
|
||||
follower_subconfig.path,
|
||||
index,
|
||||
value,
|
||||
owners.forced,
|
||||
)
|
||||
else:
|
||||
for subconfig in subconfigs:
|
||||
subconfig.properties = frozenset()
|
||||
value = values.get_value(subconfig)[0]
|
||||
if value is None:
|
||||
continue
|
||||
if values.hasvalue(subconfig.path):
|
||||
continue
|
||||
values.set_storage_value(
|
||||
subconfig.path,
|
||||
None,
|
||||
value,
|
||||
owners.forced,
|
||||
)
|
||||
#
|
||||
# def impl_build_force_store_values(self,
|
||||
# config_bag: ConfigBag,
|
||||
# ) -> None:
|
||||
# """set value to force_store_values option
|
||||
# """
|
||||
# # pylint: disable=too-many-branches
|
||||
# def do_option_bags(option):
|
||||
# if option.issubdyn():
|
||||
# dynopt = option.getsubdyn()
|
||||
# yield from dynopt.get_sub_children(option,
|
||||
# config_bag,
|
||||
# index=None,
|
||||
# )
|
||||
# else:
|
||||
# yield OptionBag(option,
|
||||
# None,
|
||||
# config_bag,
|
||||
# properties=None,
|
||||
# )
|
||||
# if 'force_store_value' not in config_bag.properties:
|
||||
# return
|
||||
# values = config_bag.context.get_values()
|
||||
# for option in self._cache_force_store_values:
|
||||
# if option.impl_is_follower():
|
||||
# leader = option.impl_get_leadership().get_leader()
|
||||
# for leader_option_bag in do_option_bags(leader):
|
||||
# leader_option_bag.properties = frozenset()
|
||||
# follower_len = len(values.get_value(leader_option_bag)[0])
|
||||
# if option.issubdyn():
|
||||
# doption = option.to_dynoption(leader_option_bag.option.rootpath,
|
||||
# leader_option_bag.option.get_current_suffixes(),
|
||||
# )
|
||||
# else:
|
||||
# doption = option
|
||||
# subpath = doption.impl_getpath()
|
||||
# for index in range(follower_len):
|
||||
# option_bag = OptionBag(doption,
|
||||
# index,
|
||||
# config_bag,
|
||||
# properties=frozenset(),
|
||||
# )
|
||||
# if values.hasvalue(subpath, index=index):
|
||||
# continue
|
||||
# value = values.get_value(option_bag)[0]
|
||||
# if value is None:
|
||||
# continue
|
||||
# values.set_storage_value(subpath,
|
||||
# index,
|
||||
# value,
|
||||
# owners.forced,
|
||||
# )
|
||||
# else:
|
||||
# for option_bag in do_option_bags(option):
|
||||
# option_bag.properties = frozenset()
|
||||
# value = values.get_value(option_bag)[0]
|
||||
# if value is None:
|
||||
# continue
|
||||
# if values.hasvalue(option_bag.path):
|
||||
# continue
|
||||
# values.set_storage_value(option_bag.path,
|
||||
# None,
|
||||
# value,
|
||||
# owners.forced,
|
||||
# )
|
||||
|
||||
|
||||
class OptionDescriptionWalk(CacheOptionDescription):
|
||||
"""get child of option description"""
|
||||
"""get child of option description
|
||||
"""
|
||||
__slots__ = ('_children',)
|
||||
|
||||
__slots__ = ("_children",)
|
||||
|
||||
def get_path(
|
||||
self,
|
||||
config_bag,
|
||||
):
|
||||
if config_bag is undefined or config_bag.context.get_description() == self:
|
||||
return ""
|
||||
def get_path(self,
|
||||
config_bag,
|
||||
):
|
||||
if config_bag is undefined or \
|
||||
config_bag.context.get_description() == self:
|
||||
return ''
|
||||
return self.impl_getpath()
|
||||
|
||||
def get_child_not_dynamic(
|
||||
self,
|
||||
name,
|
||||
allow_dynoption,
|
||||
):
|
||||
def get_child_not_dynamic(self,
|
||||
name,
|
||||
allow_dynoption,
|
||||
):
|
||||
if name in self._children[0]: # pylint: disable=no-member
|
||||
option = self._children[1][
|
||||
self._children[0].index(name)
|
||||
] # pylint: disable=no-member
|
||||
option = self._children[1][self._children[0].index(name)] # pylint: disable=no-member
|
||||
if option.impl_is_dynoptiondescription() and not allow_dynoption:
|
||||
raise AttributeError(
|
||||
_(
|
||||
'unknown option "{0}" in root optiondescription (it\'s a dynamic option)'
|
||||
).format(name)
|
||||
)
|
||||
raise AttributeError(_(f'unknown option "{name}" '
|
||||
"in root optiondescription (it's a dynamic option)"
|
||||
))
|
||||
return option
|
||||
|
||||
def get_child(
|
||||
self,
|
||||
name: str,
|
||||
config_bag: ConfigBag,
|
||||
parent: "SubConfig",
|
||||
*,
|
||||
with_identifier: bool = False,
|
||||
allow_dynoption: bool = False,
|
||||
) -> Union[BaseOption]:
|
||||
"""get a child"""
|
||||
def get_child(self,
|
||||
name: str,
|
||||
config_bag: ConfigBag,
|
||||
parent: 'SubConfig',
|
||||
*,
|
||||
with_suffix: bool=False,
|
||||
allow_dynoption: bool=False,
|
||||
) -> Union[BaseOption]:
|
||||
"""get a child
|
||||
"""
|
||||
# if not dyn
|
||||
option = self.get_child_not_dynamic(
|
||||
name,
|
||||
allow_dynoption,
|
||||
)
|
||||
option = self.get_child_not_dynamic(name,
|
||||
allow_dynoption,
|
||||
)
|
||||
if option:
|
||||
return option
|
||||
# if dyn
|
||||
for child in self._children[1]: # pylint: disable=no-member
|
||||
if not child.impl_is_dynoptiondescription():
|
||||
continue
|
||||
for identifier in child.get_identifiers(parent):
|
||||
if name != child.impl_getname(identifier):
|
||||
for suffix in child.get_suffixes(parent):
|
||||
if name != child.impl_getname(suffix):
|
||||
continue
|
||||
if not with_identifier:
|
||||
if not with_suffix:
|
||||
return child
|
||||
return identifier, child
|
||||
return suffix, child
|
||||
if self.impl_get_group_type() == groups.root: # pylint: disable=no-member
|
||||
raise AttributeError(
|
||||
_('unknown option "{0}" in root optiondescription').format(name)
|
||||
)
|
||||
raise AttributeError(
|
||||
_('unknown option "{0}" in optiondescription {1}').format(
|
||||
name, self.impl_get_display_name(parent, with_quote=True)
|
||||
)
|
||||
)
|
||||
raise AttributeError(_(f'unknown option "{name}" '
|
||||
'in root optiondescription'
|
||||
))
|
||||
raise AttributeError(_(f'unknown option "{name}" '
|
||||
f'in optiondescription "{self.impl_get_display_name()}"'
|
||||
))
|
||||
|
||||
def get_children(self) -> List[BaseOption]:
|
||||
"""get children"""
|
||||
"""get children
|
||||
"""
|
||||
return self._children[1]
|
||||
# for child in self._children[1]:
|
||||
# if config_bag is not undefined and child.impl_is_dynoptiondescription():
|
||||
# yield from self.get_suffixed_children([],
|
||||
# config_bag,
|
||||
# child,
|
||||
# )
|
||||
# else:
|
||||
# yield child
|
||||
|
||||
def get_children_recursively(
|
||||
self,
|
||||
bytype: Optional[BaseOption],
|
||||
byname: Optional[str],
|
||||
config_bag: ConfigBag,
|
||||
self_opt: BaseOption = None,
|
||||
*,
|
||||
option_identifiers: Optional[list] = None,
|
||||
) -> Iterator[Union[BaseOption]]:
|
||||
"""get children recursively"""
|
||||
def get_children_recursively(self,
|
||||
bytype: Optional[BaseOption],
|
||||
byname: Optional[str],
|
||||
config_bag: ConfigBag,
|
||||
self_opt: BaseOption=None,
|
||||
*,
|
||||
option_suffixes: Optional[list]=None
|
||||
) -> Iterator[Union[BaseOption]]:
|
||||
"""get children recursively
|
||||
"""
|
||||
if self_opt is None:
|
||||
self_opt = self
|
||||
for option in self_opt.get_children():
|
||||
if option.impl_is_optiondescription():
|
||||
for subopt in option.get_children_recursively(
|
||||
bytype,
|
||||
byname,
|
||||
config_bag,
|
||||
):
|
||||
for subopt in option.get_children_recursively(bytype,
|
||||
byname,
|
||||
config_bag,
|
||||
):
|
||||
yield subopt
|
||||
elif (byname is None or option.impl_getname() == byname) and (
|
||||
bytype is None or isinstance(option, bytype)
|
||||
):
|
||||
elif (byname is None or option.impl_getname() == byname) and \
|
||||
(bytype is None or isinstance(option, bytype)):
|
||||
yield option
|
||||
|
||||
|
||||
|
@ -318,32 +272,22 @@ class OptionDescription(OptionDescriptionWalk):
|
|||
"""Config's schema (organisation, group) and container of Options
|
||||
The `OptionsDescription` objects lives in the `tiramisu.config.Config`.
|
||||
"""
|
||||
__slots__ = ('_group_type',)
|
||||
|
||||
__slots__ = ("_group_type",)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
doc: str,
|
||||
children: List[BaseOption],
|
||||
*,
|
||||
properties=None,
|
||||
informations: Optional[Dict] = None,
|
||||
group_type: Optional[groups.GroupType] = groups.default,
|
||||
) -> None:
|
||||
def __init__(self,
|
||||
name: str,
|
||||
doc: str,
|
||||
children: List[BaseOption],
|
||||
properties=None) -> None:
|
||||
"""
|
||||
:param children: a list of options (including optiondescriptions)
|
||||
|
||||
"""
|
||||
assert isinstance(children, list), _(
|
||||
'children in optiondescription "{}" ' "must be a list"
|
||||
).format(name)
|
||||
super().__init__(
|
||||
name,
|
||||
doc,
|
||||
informations,
|
||||
properties=properties,
|
||||
)
|
||||
assert isinstance(children, list), _('children in optiondescription "{}" '
|
||||
'must be a list').format(name)
|
||||
super().__init__(name,
|
||||
doc=doc,
|
||||
properties=properties)
|
||||
child_names = []
|
||||
if __debug__:
|
||||
dynopt_names = []
|
||||
|
@ -362,72 +306,83 @@ class OptionDescription(OptionDescriptionWalk):
|
|||
old = None
|
||||
for child in child_names:
|
||||
if child == old:
|
||||
raise ConflictError(
|
||||
_("duplicate option name: " '"{0}"').format(child)
|
||||
)
|
||||
raise ConflictError(_('duplicate option name: '
|
||||
'"{0}"').format(child))
|
||||
if dynopt_names:
|
||||
for dynopt in dynopt_names:
|
||||
if child != dynopt and child.startswith(dynopt):
|
||||
raise ConflictError(
|
||||
_(
|
||||
'the option\'s name "{0}" start as the dynoptiondescription\'s name "{1}"'
|
||||
).format(child, dynopt)
|
||||
)
|
||||
raise ConflictError(_(f'the option\'s name "{child}" start as '
|
||||
f'the dynoptiondescription\'s name "{dynopt}"'))
|
||||
old = child
|
||||
self._children = children_
|
||||
# the group_type is useful for filtering OptionDescriptions in a config
|
||||
self._group_type = None
|
||||
self.impl_set_group_type(group_type)
|
||||
self._group_type = groups.default
|
||||
|
||||
def _setsubdyn(
|
||||
self,
|
||||
subdyn,
|
||||
) -> None:
|
||||
def _setsubdyn(self,
|
||||
subdyn,
|
||||
) -> None:
|
||||
for child in self._children[1]:
|
||||
child._setsubdyn(subdyn)
|
||||
super()._setsubdyn(subdyn)
|
||||
|
||||
def impl_is_optiondescription(self) -> bool:
|
||||
"""the option is an option description"""
|
||||
"""the option is an option description
|
||||
"""
|
||||
return True
|
||||
|
||||
def impl_is_dynoptiondescription(self) -> bool:
|
||||
"""the option is not dynamic"""
|
||||
"""the option is not dynamic
|
||||
"""
|
||||
return False
|
||||
|
||||
def impl_is_leadership(self) -> bool:
|
||||
"""the option is not a leadership"""
|
||||
"""the option is not a leadership
|
||||
"""
|
||||
return False
|
||||
|
||||
# ____________________________________________________________
|
||||
def impl_set_group_type(
|
||||
self,
|
||||
group_type: groups.GroupType,
|
||||
) -> None:
|
||||
def impl_set_group_type(self,
|
||||
group_type: groups.GroupType,
|
||||
) -> None:
|
||||
"""sets a given group object to an OptionDescription
|
||||
|
||||
:param group_type: an instance of `GroupType` or `LeadershipGroupType`
|
||||
that lives in `setting.groups`
|
||||
"""
|
||||
if __debug__:
|
||||
if self._group_type is not None and self._group_type != groups.default:
|
||||
raise ValueError(
|
||||
_(
|
||||
"cannot change group_type if already set " "(old {0}, new {1})"
|
||||
).format(self._group_type, group_type)
|
||||
)
|
||||
if self._group_type != groups.default:
|
||||
raise ValueError(_('cannot change group_type if already set '
|
||||
'(old {0}, new {1})').format(self._group_type,
|
||||
group_type))
|
||||
if not isinstance(group_type, groups.GroupType):
|
||||
raise ValueError(_("group_type: {0}" " not allowed").format(group_type))
|
||||
raise ValueError(_('group_type: {0}'
|
||||
' not allowed').format(group_type))
|
||||
if isinstance(group_type, groups.LeadershipGroupType):
|
||||
raise ConfigError(
|
||||
"please use Leadership object instead of OptionDescription"
|
||||
)
|
||||
raise ConfigError('please use Leadership object instead of OptionDescription')
|
||||
self._group_type = group_type
|
||||
|
||||
def impl_get_group_type(self) -> groups.GroupType:
|
||||
"""get the group type of option description"""
|
||||
"""get the group type of option description
|
||||
"""
|
||||
return self._group_type
|
||||
#
|
||||
# def to_dynoption(self,
|
||||
# rootpath: str,
|
||||
# suffixes: Optional[list],
|
||||
# #ori_dyn,
|
||||
# ) -> Union[SubDynOptionDescription]:
|
||||
# """get syn dyn option description
|
||||
# """
|
||||
# if self.impl_is_dynoptiondescription():
|
||||
# obj = SynDynOptionDescription
|
||||
# else:
|
||||
# obj = SubDynOptionDescription
|
||||
# return obj(self,
|
||||
# rootpath,
|
||||
# suffixes,
|
||||
# )
|
||||
|
||||
def impl_is_dynsymlinkoption(self) -> bool:
|
||||
"""option is not a dyn symlink option"""
|
||||
"""option is not a dyn symlink option
|
||||
"""
|
||||
return False
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2017-2024 Team tiramisu (see AUTHORS for all contributors)
|
||||
# Copyright (C) 2017-2023 Team tiramisu (see AUTHORS for all contributors)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by the
|
||||
|
@ -22,39 +22,11 @@
|
|||
"""
|
||||
|
||||
from ..i18n import _
|
||||
from ..error import display_list
|
||||
from .stroption import StrOption
|
||||
|
||||
|
||||
class PasswordOption(StrOption):
|
||||
"""represents the choice of a password"""
|
||||
|
||||
"""represents the choice of a password
|
||||
"""
|
||||
__slots__ = tuple()
|
||||
_type = "password"
|
||||
|
||||
def __init__(self, *args, min_len=None, max_len=None, forbidden_char=[], **kwargs):
|
||||
extra = {}
|
||||
if min_len is not None:
|
||||
extra["min_len"] = min_len
|
||||
if max_len is not None:
|
||||
extra["max_len"] = max_len
|
||||
if forbidden_char:
|
||||
extra["forbidden_char"] = set(forbidden_char)
|
||||
super().__init__(*args, extra=extra, **kwargs)
|
||||
|
||||
def validate(self, value: str) -> None:
|
||||
super().validate(value)
|
||||
min_len = self.impl_get_extra("min_len")
|
||||
if min_len and len(value) < min_len:
|
||||
raise ValueError(_("at least {0} characters are required").format(min_len))
|
||||
max_len = self.impl_get_extra("max_len")
|
||||
if max_len and len(value) > max_len:
|
||||
raise ValueError(_("maximum {0} characters required").format(max_len))
|
||||
if self.impl_get_extra("forbidden_char"):
|
||||
forbidden_char = set(value) & self.impl_get_extra("forbidden_char")
|
||||
if forbidden_char:
|
||||
raise ValueError(
|
||||
_("must not have the characters {0}").format(
|
||||
display_list(list(forbidden_char), add_quote=True)
|
||||
)
|
||||
)
|
||||
_type = _('password')
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2023-2024 Team tiramisu (see AUTHORS for all contributors)
|
||||
# Copyright (C) 2023 Team tiramisu (see AUTHORS for all contributors)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by the
|
||||
|
@ -33,25 +33,27 @@ class PermissionsOption(IntOption):
|
|||
If a fourth digit is present to the setuid bit, the setgid bit and the sticky bit attributes.
|
||||
This option is an integer value.
|
||||
"""
|
||||
|
||||
__slots__ = tuple()
|
||||
perm_re = re.compile(r"^[0-7]{3,4}$")
|
||||
_type = "unix file permissions"
|
||||
_type = _('unix file permissions')
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*args,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
# do not display intoption attributs
|
||||
super().__init__(*args, **kwargs)
|
||||
def __init__(self,
|
||||
*args,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
#do not display intoption attributs
|
||||
super().__init__(*args,
|
||||
**kwargs)
|
||||
|
||||
def validate(self, value: str) -> None:
|
||||
def validate(self,
|
||||
value: str) -> None:
|
||||
super().validate(value)
|
||||
if not self.perm_re.search(str(value)):
|
||||
raise ValueError(_("only 3 or 4 octal digits are allowed"))
|
||||
raise ValueError(_('only 3 or 4 octal digits are allowed'))
|
||||
|
||||
def second_level_validation(self, value: str, warnings_only: bool) -> None:
|
||||
def second_level_validation(self,
|
||||
value: str,
|
||||
warnings_only: bool) -> None:
|
||||
old_digit = 7
|
||||
str_value = str(value)
|
||||
if len(str_value) == 4:
|
||||
|
@ -60,12 +62,12 @@ class PermissionsOption(IntOption):
|
|||
new_digit = int(digit)
|
||||
if old_digit < new_digit:
|
||||
if idx == 1:
|
||||
old = _("user")
|
||||
new = _("group")
|
||||
old = _('user')
|
||||
new = _('group')
|
||||
else:
|
||||
old = _("group")
|
||||
new = _("other")
|
||||
raise ValueError(_("{0} has more right than {1}").format(new, old))
|
||||
old = _('group')
|
||||
new = _('other')
|
||||
raise ValueError(_(f'{new} has more right than {old}'))
|
||||
old_digit = new_digit
|
||||
if str_value == "777":
|
||||
raise ValueError(_("too weak"))
|
||||
if str_value == '777':
|
||||
raise ValueError(_('too weak'))
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2017-2024 Team tiramisu (see AUTHORS for all contributors)
|
||||
# Copyright (C) 2017-2023 Team tiramisu (see AUTHORS for all contributors)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by the
|
||||
|
@ -36,64 +36,62 @@ class PortOption(StrOption):
|
|||
Port number 0 is reserved and can't be used.
|
||||
see: http://en.wikipedia.org/wiki/Port_numbers
|
||||
"""
|
||||
|
||||
__slots__ = tuple()
|
||||
port_re = re.compile(r"^[0-9]*$")
|
||||
_type = "port"
|
||||
_port = _('port')
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*args,
|
||||
allow_range: bool = False,
|
||||
allow_zero: bool = False,
|
||||
allow_wellknown: bool = True,
|
||||
allow_registred: bool = True,
|
||||
allow_protocol: bool = False,
|
||||
allow_private: bool = False,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
def __init__(self,
|
||||
*args,
|
||||
allow_range: bool=False,
|
||||
allow_zero: bool=False,
|
||||
allow_wellknown: bool=True,
|
||||
allow_registred: bool=True,
|
||||
allow_protocol: bool=False,
|
||||
allow_private: bool=False,
|
||||
**kwargs) -> None:
|
||||
|
||||
extra = {
|
||||
"_allow_range": allow_range,
|
||||
"_allow_protocol": allow_protocol,
|
||||
"_min_value": None,
|
||||
"_max_value": None,
|
||||
}
|
||||
extra = {'_allow_range': allow_range,
|
||||
'_allow_protocol': allow_protocol,
|
||||
'_min_value': None,
|
||||
'_max_value': None,
|
||||
}
|
||||
ports_min = [0, 1, 1024, 49152]
|
||||
ports_max = [0, 1023, 49151, 65535]
|
||||
is_finally = False
|
||||
for index, allowed in enumerate(
|
||||
[allow_zero, allow_wellknown, allow_registred, allow_private]
|
||||
):
|
||||
if extra["_min_value"] is None:
|
||||
for index, allowed in enumerate([allow_zero,
|
||||
allow_wellknown,
|
||||
allow_registred,
|
||||
allow_private]):
|
||||
if extra['_min_value'] is None:
|
||||
if allowed:
|
||||
extra["_min_value"] = ports_min[index]
|
||||
extra['_min_value'] = ports_min[index]
|
||||
elif not allowed:
|
||||
is_finally = True
|
||||
elif allowed and is_finally:
|
||||
raise ValueError(_("inconsistency in allowed range"))
|
||||
raise ValueError(_('inconsistency in allowed range'))
|
||||
if allowed:
|
||||
extra["_max_value"] = ports_max[index]
|
||||
extra['_max_value'] = ports_max[index]
|
||||
|
||||
if extra["_max_value"] is None:
|
||||
raise ValueError(_("max value is empty"))
|
||||
if extra['_max_value'] is None:
|
||||
raise ValueError(_('max value is empty'))
|
||||
|
||||
super().__init__(*args, extra=extra, **kwargs)
|
||||
super().__init__(*args,
|
||||
extra=extra,
|
||||
**kwargs)
|
||||
|
||||
def validate(self, value: str) -> None:
|
||||
def validate(self,
|
||||
value: str) -> None:
|
||||
super().validate(value)
|
||||
if self.impl_get_extra("_allow_protocol") and (
|
||||
value.startswith("tcp:") or value.startswith("udp:")
|
||||
):
|
||||
if self.impl_get_extra('_allow_protocol') and (value.startswith('tcp:') or
|
||||
value.startswith('udp:')):
|
||||
value = [value[4:]]
|
||||
elif self.impl_get_extra("_allow_range") and ":" in str(value):
|
||||
value = value.split(":")
|
||||
elif self.impl_get_extra('_allow_range') and ":" in str(value):
|
||||
value = value.split(':')
|
||||
if len(value) != 2:
|
||||
raise ValueError(_("range must have two values only"))
|
||||
raise ValueError(_('range must have two values only'))
|
||||
if not value[0] < value[1]:
|
||||
raise ValueError(
|
||||
_("first port in range must be" " smaller than the second one")
|
||||
)
|
||||
raise ValueError(_('first port in range must be'
|
||||
' smaller than the second one'))
|
||||
else:
|
||||
value = [value]
|
||||
|
||||
|
@ -101,29 +99,22 @@ class PortOption(StrOption):
|
|||
if not self.port_re.search(val):
|
||||
raise ValueError()
|
||||
|
||||
def second_level_validation(self, value: str, warnings_only: bool) -> None:
|
||||
if self.impl_get_extra("_allow_protocol") and (
|
||||
value.startswith("tcp:") or value.startswith("udp:")
|
||||
):
|
||||
def second_level_validation(self,
|
||||
value: str,
|
||||
warnings_only: bool) -> None:
|
||||
if self.impl_get_extra('_allow_protocol') and (value.startswith('tcp:') or
|
||||
value.startswith('udp:')):
|
||||
value = [value[4:]]
|
||||
elif ":" in value:
|
||||
value = value.split(":")
|
||||
elif ':' in value:
|
||||
value = value.split(':')
|
||||
else:
|
||||
value = [value]
|
||||
for val in value:
|
||||
val = int(val)
|
||||
if (
|
||||
not self.impl_get_extra("_min_value")
|
||||
<= val
|
||||
<= self.impl_get_extra("_max_value")
|
||||
):
|
||||
if not self.impl_get_extra('_min_value') <= val <= self.impl_get_extra('_max_value'):
|
||||
if warnings_only:
|
||||
msg = _("should be between {0} and {1}")
|
||||
msg = 'should be between {0} and {1}'
|
||||
else:
|
||||
msg = _("must be between {0} and {1}")
|
||||
raise ValueError(
|
||||
msg.format(
|
||||
self.impl_get_extra("_min_value"),
|
||||
self.impl_get_extra("_max_value"),
|
||||
)
|
||||
)
|
||||
msg = 'must be between {0} and {1}'
|
||||
raise ValueError(_(msg).format(self.impl_get_extra('_min_value'),
|
||||
self.impl_get_extra('_max_value')))
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2017-2024 Team tiramisu (see AUTHORS for all contributors)
|
||||
# Copyright (C) 2017-2023 Team tiramisu (see AUTHORS for all contributors)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by the
|
||||
|
@ -27,31 +27,31 @@ from .option import Option
|
|||
|
||||
|
||||
class StrOption(Option):
|
||||
"""represents a string"""
|
||||
|
||||
"""represents a string
|
||||
"""
|
||||
__slots__ = tuple()
|
||||
_type = "string"
|
||||
_type = _('string')
|
||||
|
||||
def validate(
|
||||
self,
|
||||
value: str,
|
||||
) -> None:
|
||||
"""validation"""
|
||||
def validate(self,
|
||||
value: str,
|
||||
) -> None:
|
||||
"""validation
|
||||
"""
|
||||
if not isinstance(value, str):
|
||||
raise ValueError()
|
||||
|
||||
|
||||
class RegexpOption(StrOption):
|
||||
"""regexp validation, this is base option use to do a custom's one"""
|
||||
|
||||
"""regexp validation, this is base option use to do a custom's one
|
||||
"""
|
||||
__slots__ = tuple()
|
||||
|
||||
def validate(
|
||||
self,
|
||||
value: Any,
|
||||
) -> None:
|
||||
def validate(self,
|
||||
value: Any,
|
||||
) -> None:
|
||||
# pylint: disable=no-member
|
||||
"""validation"""
|
||||
"""validation
|
||||
"""
|
||||
super().validate(value)
|
||||
match = self._regexp.search(value)
|
||||
if not match:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2017-2024 Team tiramisu (see AUTHORS for all contributors)
|
||||
# Copyright (C) 2017-2023 Team tiramisu (see AUTHORS for all contributors)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by the
|
||||
|
@ -20,81 +20,78 @@
|
|||
# ____________________________________________________________
|
||||
"""SymLinkOption link to an other option
|
||||
"""
|
||||
from typing import Any, Optional, Dict
|
||||
from typing import Any
|
||||
from .baseoption import BaseOption, valid_name
|
||||
from ..error import ConfigError
|
||||
from ..i18n import _
|
||||
|
||||
|
||||
class SymLinkOption(BaseOption):
|
||||
"""SymLinkOption link to an other option"""
|
||||
"""SymLinkOption link to an other option
|
||||
"""
|
||||
__slots__ = ('_opt',)
|
||||
|
||||
__slots__ = (
|
||||
"_opt",
|
||||
"_leadership",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
opt: BaseOption,
|
||||
) -> None:
|
||||
def __init__(self,
|
||||
name: str,
|
||||
opt: BaseOption,
|
||||
) -> None:
|
||||
# pylint: disable=super-init-not-called
|
||||
if not valid_name(name):
|
||||
raise ValueError(_('"{0}" is an invalid name for an option').format(name))
|
||||
if (
|
||||
not isinstance(opt, BaseOption)
|
||||
or opt.impl_is_optiondescription()
|
||||
or opt.impl_is_symlinkoption()
|
||||
):
|
||||
raise ValueError(
|
||||
_(
|
||||
'malformed symlink second parameters must be an option for "{0}", not {1}'
|
||||
).format(name, opt)
|
||||
)
|
||||
self._name = name
|
||||
self._opt = opt
|
||||
self._leadership = None
|
||||
if not isinstance(opt, BaseOption) or \
|
||||
opt.impl_is_optiondescription() or \
|
||||
opt.impl_is_symlinkoption():
|
||||
raise ValueError(_('malformed symlinkoption must be an option for symlink {0}'
|
||||
'').format(name))
|
||||
_setattr = object.__setattr__
|
||||
_setattr(self, '_name', name)
|
||||
_setattr(self, '_opt', opt)
|
||||
opt._add_dependency(self)
|
||||
|
||||
def __getattr__(
|
||||
self,
|
||||
name: str,
|
||||
) -> Any:
|
||||
if name == "_subdyns":
|
||||
return None
|
||||
if name == "_path":
|
||||
def __getattr__(self,
|
||||
name: str,
|
||||
) -> Any:
|
||||
if name == '_path':
|
||||
raise AttributeError()
|
||||
return getattr(self._opt, name)
|
||||
|
||||
def _setsubdyn(self,
|
||||
subdyn,
|
||||
) -> None:
|
||||
raise ConfigError(_('cannot set symlinkoption in a '
|
||||
'dynoptiondescription'))
|
||||
|
||||
def impl_has_dependency(self,
|
||||
self_is_dep: bool=True,
|
||||
) -> bool:
|
||||
"""If self_is_dep is True, it has dependency (self._opt), so return True
|
||||
if self_is_dep is False, cannot has validation or callback, so return False
|
||||
"""
|
||||
return self_is_dep
|
||||
|
||||
def impl_is_symlinkoption(self) -> bool:
|
||||
"""it's a symlinkoption"""
|
||||
"""it's a symlinkoption
|
||||
"""
|
||||
return True
|
||||
|
||||
def impl_is_leader(self) -> bool:
|
||||
return False
|
||||
|
||||
def impl_is_follower(self):
|
||||
"""check if option is a leader in a follower"""
|
||||
leadership = self._leadership
|
||||
if leadership is None:
|
||||
return False
|
||||
return not leadership().is_leader(self)
|
||||
|
||||
def impl_getopt(self) -> BaseOption:
|
||||
"""get to linked option"""
|
||||
"""get to linked option
|
||||
"""
|
||||
return self._opt
|
||||
|
||||
def impl_is_multi(self) -> bool:
|
||||
"""is it a multi?"""
|
||||
if self._opt.impl_is_multi():
|
||||
return True
|
||||
if self._opt.issubdyn() or self.issubdyn():
|
||||
if self.issubdyn() != self._opt.issubdyn():
|
||||
return self._opt.issubdyn()
|
||||
return self._opt.issubdyn() in self.get_sub_dyns()
|
||||
def issubdyn(self) -> bool:
|
||||
"""it's not a sub dyn option
|
||||
"""
|
||||
return False
|
||||
|
||||
def impl_is_multi(self) -> bool:
|
||||
"""is it a multi?
|
||||
"""
|
||||
if self._opt.issubdyn():
|
||||
return True
|
||||
return self._opt.impl_is_multi()
|
||||
|
||||
def impl_is_submulti(self) -> bool:
|
||||
"""is it a submulti?"""
|
||||
"""is it a submulti?
|
||||
"""
|
||||
return self._opt.impl_is_submulti()
|
||||
|
|
351
tiramisu/option/syndynoption.py
Normal file
351
tiramisu/option/syndynoption.py
Normal file
|
@ -0,0 +1,351 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2017-2024 Team tiramisu (see AUTHORS for all contributors)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by the
|
||||
# Free Software Foundation, either version 3 of the License, or (at your
|
||||
# option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# The original `Config` design model is unproudly borrowed from
|
||||
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||
# the whole pypy projet is under MIT licence
|
||||
# ____________________________________________________________
|
||||
"""SynDynOption internal option, it's an instanciate synoption
|
||||
"""
|
||||
import re
|
||||
from typing import Optional, Iterator, Any, List, Tuple
|
||||
|
||||
from .baseoption import BaseOption
|
||||
from ..i18n import _
|
||||
from ..setting import ConfigBag, undefined
|
||||
|
||||
|
||||
NAME_REGEXP = re.compile(r'^[a-zA-Z\d\-_]*$')
|
||||
|
||||
|
||||
class CommonDyn:
|
||||
def get_path(self,
|
||||
config_bag,
|
||||
):
|
||||
if config_bag is undefined or \
|
||||
config_bag.context.get_description() == self:
|
||||
return ''
|
||||
return self.impl_getpath()
|
||||
|
||||
def get_suffixes(self,
|
||||
parent: 'SubConfig',
|
||||
) -> List[str]:
|
||||
"""get dynamic suffixes
|
||||
"""
|
||||
subconfig = parent.get_child(self,
|
||||
None,
|
||||
False,
|
||||
properties=None,
|
||||
)
|
||||
values = self._suffixes.execute(subconfig)
|
||||
if values is None:
|
||||
values = []
|
||||
values_ = []
|
||||
if __debug__:
|
||||
if not isinstance(values, list):
|
||||
raise ValueError(_('DynOptionDescription suffixes for '
|
||||
f'option "{self.impl_get_display_name()}", is not '
|
||||
f'a list ({values})'))
|
||||
for val in values:
|
||||
cval = self.convert_suffix_to_path(val)
|
||||
if not isinstance(cval, str) or re.match(NAME_REGEXP, cval) is None:
|
||||
if __debug__ and cval is not None:
|
||||
raise ValueError(_('invalid suffix "{}" for option "{}"'
|
||||
'').format(cval,
|
||||
self.impl_get_display_name()))
|
||||
else:
|
||||
values_.append(val)
|
||||
if __debug__ and len(values_) > len(set(values_)):
|
||||
raise ValueError(_(f'DynOptionDescription "{self._name}" suffixes return a list with '
|
||||
f'same values "{values_}"'''))
|
||||
return values_
|
||||
|
||||
def split_path(self,
|
||||
option,
|
||||
*,
|
||||
dynoption=None,
|
||||
) -> Tuple[str, str]:
|
||||
"""self.impl_getpath() is something like root.xxx.dynoption_path
|
||||
option.impl_getpath() is something like root.xxx.dynoption_path.sub.path
|
||||
must return ('root.xxx.', '.sub')
|
||||
"""
|
||||
if dynoption is None:
|
||||
self_path = self.impl_getpath()
|
||||
else:
|
||||
self_path = dynoption.impl_getpath()
|
||||
root_path = self_path.rsplit('.', 1)[0] if '.' in self_path else None
|
||||
#
|
||||
if self.option_is_self(option):
|
||||
sub_path = ''
|
||||
else:
|
||||
option_path = option.impl_getpath()
|
||||
if root_path:
|
||||
if isinstance(option, SynDynLeadership):
|
||||
count_root_path = option_path.count('.') - root_path.count('.')
|
||||
root_path = option_path.rsplit('.', count_root_path)[0]
|
||||
root_path += '.'
|
||||
self_number_child = self_path.count('.') + 1
|
||||
option_sub_path = option_path.split('.', self_number_child)[-1]
|
||||
sub_path = '.' + option_sub_path.rsplit('.', 1)[0] if '.' in option_sub_path else ''
|
||||
return root_path, sub_path
|
||||
|
||||
|
||||
class Syn:
|
||||
__slots__ = ('rootpath',
|
||||
'opt',
|
||||
'_current_suffixes',
|
||||
'__weakref__')
|
||||
|
||||
def __init__(self,
|
||||
opt: BaseOption,
|
||||
rootpath: str,
|
||||
suffixes: list,
|
||||
) -> None:
|
||||
self.opt = opt
|
||||
self.rootpath = rootpath
|
||||
self._current_suffixes = suffixes
|
||||
|
||||
def __getattr__(self,
|
||||
name: str,
|
||||
) -> Any:
|
||||
# if not in SynDynOptionDescription, get value in self.opt
|
||||
return getattr(self.opt,
|
||||
name,
|
||||
)
|
||||
|
||||
def impl_get_display_name(self) -> str:
|
||||
return self.opt.impl_get_display_name(self)
|
||||
|
||||
def get_current_suffixes(self) -> str:
|
||||
"""get suffixes
|
||||
"""
|
||||
return self.current__suffixes
|
||||
|
||||
def impl_is_dynsymlinkoption(self) -> bool:
|
||||
"""it's a dynsymlinkoption
|
||||
"""
|
||||
return True
|
||||
|
||||
def impl_getpath(self) -> str:
|
||||
"""get path
|
||||
"""
|
||||
path = self.impl_getname()
|
||||
if self.rootpath:
|
||||
path = f'{self.rootpath}.{path}'
|
||||
return path
|
||||
|
||||
|
||||
class SynDescr(Syn):
|
||||
__slots__ = ('opt',
|
||||
'rootpath',
|
||||
'_current_suffixes',
|
||||
)
|
||||
|
||||
def get_child(self,
|
||||
name: str,
|
||||
config_bag: ConfigBag,
|
||||
*,
|
||||
allow_dynoption: bool=False,
|
||||
):
|
||||
"""get children
|
||||
"""
|
||||
# if not dyn
|
||||
option = self.get_child_not_dynamic(name,
|
||||
allow_dynoption,
|
||||
)
|
||||
if option:
|
||||
if allow_dynoption and option.impl_is_dynoptiondescription():
|
||||
return option
|
||||
return option.to_dynoption(self.impl_getpath(),
|
||||
self._current_suffixes,
|
||||
)
|
||||
for child in self.opt._children[1]: # pylint: disable=no-member
|
||||
if not child.impl_is_dynoptiondescription():
|
||||
continue
|
||||
for suffix in child.get_suffixes(config_bag):
|
||||
if name != child.impl_getname(suffix):
|
||||
continue
|
||||
return child.to_dynoption(self.impl_getpath(),
|
||||
self._current_suffixes + [suffix],
|
||||
)
|
||||
raise AttributeError(_(f'unknown option "{name}" '
|
||||
f'in optiondescription "{self.impl_get_display_name()}"'
|
||||
))
|
||||
|
||||
def get_children(self,
|
||||
config_bag: ConfigBag,
|
||||
):
|
||||
# pylint: disable=unused-argument
|
||||
"""get children
|
||||
"""
|
||||
for child in self.opt._children[1]:
|
||||
if child.impl_is_dynoptiondescription():
|
||||
dynchild = self.get_child(child.impl_getname(),
|
||||
config_bag,
|
||||
allow_dynoption=True,
|
||||
)
|
||||
for d in dynchild.get_sub_children(dynchild,
|
||||
config_bag,
|
||||
):
|
||||
yield d.option
|
||||
# yield from dynchild.get_sub_children(dynchild,
|
||||
# config_bag,
|
||||
# )
|
||||
#for suffix in dynchild.get_suffixes(config_bag):
|
||||
# yield child.to_dynoption(self.impl_getpath(),
|
||||
# self._suffixes + [suffix],
|
||||
# )
|
||||
else:
|
||||
yield child.to_dynoption(self.impl_getpath(),
|
||||
self._current_suffixes,
|
||||
)
|
||||
|
||||
def get_children_recursively(self,
|
||||
bytype: Optional[BaseOption],
|
||||
byname: Optional[str],
|
||||
config_bag: ConfigBag,
|
||||
self_opt: BaseOption=None,
|
||||
) -> BaseOption:
|
||||
# pylint: disable=unused-argument
|
||||
"""get children recursively
|
||||
"""
|
||||
for option in self.opt.get_children_recursively(bytype,
|
||||
byname,
|
||||
config_bag,
|
||||
self,
|
||||
):
|
||||
yield option
|
||||
|
||||
def get_child_not_dynamic(self,
|
||||
name,
|
||||
allow_dynoption,
|
||||
):
|
||||
children = self.opt._children
|
||||
if name in children[0]: # pylint: disable=no-member
|
||||
option = children[1][children[0].index(name)] # pylint: disable=no-member
|
||||
if option.impl_is_dynoptiondescription() and not allow_dynoption:
|
||||
raise AttributeError(_(f'unknown option "{name}" '
|
||||
"in root optiondescription (it's a dynamic option)"
|
||||
))
|
||||
return SubDynOptionDescription(option,
|
||||
self.impl_getpath(),
|
||||
self._current_suffixes,
|
||||
)
|
||||
|
||||
|
||||
class SynDynOption(Syn):
|
||||
"""SynDynOption is an Option include un DynOptionDescription with specified prefix
|
||||
"""
|
||||
__slots__ = ()
|
||||
|
||||
def impl_get_leadership(self): # pylint: disable=inconsistent-return-statements
|
||||
"""is it a leadership?
|
||||
"""
|
||||
leadership = self.opt.impl_get_leadership()
|
||||
if leadership:
|
||||
rootpath = self.rootpath.rsplit('.', 1)[0]
|
||||
return leadership.to_dynoption(rootpath,
|
||||
self._current_suffixes,
|
||||
)
|
||||
#
|
||||
#
|
||||
#class SubDynOptionDescription(SynDescr, CommonDyn):
|
||||
# def option_is_self(self,
|
||||
# option,
|
||||
# ) -> bool:
|
||||
# return self.opt.option_is_self(option.opt)
|
||||
#
|
||||
# def get_sub_children(self,
|
||||
# option,
|
||||
# config_bag,
|
||||
# *,
|
||||
# index=None,
|
||||
# properties=undefined,
|
||||
# ):
|
||||
# root_path, sub_path = self.split_path(option)
|
||||
# for suffix in self.get_suffixes(config_bag):
|
||||
# if self.option_is_self(option):
|
||||
# parent_path = root_path
|
||||
# elif root_path:
|
||||
# parent_path = root_path + self.impl_getname(suffix) + sub_path
|
||||
# else:
|
||||
# parent_path = self.impl_getname(suffix) + sub_path
|
||||
# yield OptionBag(option.to_dynoption(parent_path,
|
||||
# [suffix],
|
||||
# ),
|
||||
# index,
|
||||
# config_bag,
|
||||
# properties=properties,
|
||||
# ori_option=option
|
||||
# )
|
||||
#
|
||||
#
|
||||
#class SynDynOptionDescription(SynDescr):
|
||||
# """SynDynOptionDescription internal option, it's an instanciate synoptiondescription
|
||||
# """
|
||||
# def impl_getname(self) -> str:
|
||||
# """get name
|
||||
# """
|
||||
# if self.opt.impl_is_dynoptiondescription():
|
||||
# return self.opt.impl_getname(self._current_suffixes[-1])
|
||||
# return self.opt.impl_getname()
|
||||
#
|
||||
# def getsubdyn(self):
|
||||
# return self.opt
|
||||
#
|
||||
#
|
||||
#class SynDynLeadership(SynDynOptionDescription):
|
||||
# """SynDynLeadership internal option, it's an instanciate synoptiondescription
|
||||
# """
|
||||
# def get_leader(self) -> SynDynOption:
|
||||
# """get the leader
|
||||
# """
|
||||
# return self.opt.get_leader().to_dynoption(self.impl_getpath(),
|
||||
# self._current_suffixes,
|
||||
# )
|
||||
#
|
||||
# def get_followers(self) -> Iterator[SynDynOption]:
|
||||
# """get followers
|
||||
# """
|
||||
# subpath = self.impl_getpath()
|
||||
# for follower in self.opt.get_followers():
|
||||
# yield follower.to_dynoption(subpath,
|
||||
# self._current_suffixes,
|
||||
# )
|
||||
#
|
||||
# def pop(self,
|
||||
# *args,
|
||||
# **kwargs,
|
||||
# ) -> None:
|
||||
# """pop value for a follower
|
||||
# """
|
||||
# self.opt.pop(*args,
|
||||
# followers=self.get_followers(),
|
||||
# **kwargs,
|
||||
# )
|
||||
#
|
||||
# def follower_force_store_value(self,
|
||||
# value,
|
||||
# config_bag,
|
||||
# owner,
|
||||
# ) -> None:
|
||||
# """force store value for a follower
|
||||
# """
|
||||
# self.opt.follower_force_store_value(value,
|
||||
# config_bag,
|
||||
# owner,
|
||||
# dyn=self,
|
||||
# )
|
235
tiramisu/option/syndynoptiondescription.py
Normal file
235
tiramisu/option/syndynoptiondescription.py
Normal file
|
@ -0,0 +1,235 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2017-2023 Team tiramisu (see AUTHORS for all contributors)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by the
|
||||
# Free Software Foundation, either version 3 of the License, or (at your
|
||||
# option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# The original `Config` design model is unproudly borrowed from
|
||||
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||
# the whole pypy projet is under MIT licence
|
||||
# ____________________________________________________________
|
||||
"""SynDynOptionDescription and SynDynLeadership internal option
|
||||
it's an instanciate synoptiondescription
|
||||
"""
|
||||
from typing import Optional, Iterator, Any, List
|
||||
|
||||
|
||||
from ..i18n import _
|
||||
from ..setting import ConfigBag, undefined
|
||||
from .baseoption import BaseOption
|
||||
from .syndynoption import SynDynOption
|
||||
|
||||
|
||||
class Syn:
|
||||
__slots__ = ('opt',
|
||||
'rootpath',
|
||||
'_suffixes',
|
||||
)
|
||||
|
||||
def __init__(self,
|
||||
opt: BaseOption,
|
||||
rootpath: str,
|
||||
suffixes: list,
|
||||
) -> None:
|
||||
self.opt = opt
|
||||
self.rootpath = rootpath
|
||||
self._suffixes = suffixes
|
||||
|
||||
def impl_get_display_name(self) -> str:
|
||||
return self.opt.impl_get_display_name(self)
|
||||
|
||||
def get_child(self,
|
||||
name: str,
|
||||
config_bag: ConfigBag,
|
||||
*,
|
||||
allow_dynoption: bool=False,
|
||||
):
|
||||
"""get children
|
||||
"""
|
||||
# if not dyn
|
||||
option = self.opt.get_child_not_dynamic(name,
|
||||
allow_dynoption,
|
||||
)
|
||||
if option:
|
||||
if allow_dynoption and option.impl_is_dynoptiondescription():
|
||||
return option
|
||||
return option.to_dynoption(self.impl_getpath(),
|
||||
self._suffixes,
|
||||
)
|
||||
for child in self.opt._children[1]: # pylint: disable=no-member
|
||||
if not child.impl_is_dynoptiondescription():
|
||||
continue
|
||||
for suffix in child.get_suffixes(config_bag,
|
||||
dynoption=self,
|
||||
):
|
||||
if name != child.impl_getname(suffix):
|
||||
continue
|
||||
return child.to_dynoption(self.impl_getpath(),
|
||||
self._suffixes + [suffix],
|
||||
)
|
||||
raise AttributeError(_(f'unknown option "{name}" '
|
||||
f'in optiondescription "{self.impl_get_display_name()}"'
|
||||
))
|
||||
|
||||
def get_children(self,
|
||||
config_bag: ConfigBag,
|
||||
):
|
||||
# pylint: disable=unused-argument
|
||||
"""get children
|
||||
"""
|
||||
for child in self.opt._children[1]:
|
||||
if child.impl_is_dynoptiondescription():
|
||||
for suffix in child.get_suffixes(config_bag,
|
||||
dynoption=self,
|
||||
):
|
||||
yield child.to_dynoption(self.impl_getpath(),
|
||||
self._suffixes + [suffix],
|
||||
)
|
||||
else:
|
||||
yield child.to_dynoption(self.impl_getpath(),
|
||||
self._suffixes,
|
||||
)
|
||||
|
||||
def get_children_recursively(self,
|
||||
bytype: Optional[BaseOption],
|
||||
byname: Optional[str],
|
||||
config_bag: ConfigBag,
|
||||
self_opt: BaseOption=None,
|
||||
) -> BaseOption:
|
||||
# pylint: disable=unused-argument
|
||||
"""get children recursively
|
||||
"""
|
||||
for option in self.opt.get_children_recursively(bytype,
|
||||
byname,
|
||||
config_bag,
|
||||
self,
|
||||
):
|
||||
yield option
|
||||
|
||||
def get_suffixes(self) -> str:
|
||||
"""get suffixes
|
||||
"""
|
||||
return self._suffixes
|
||||
|
||||
def impl_is_dynsymlinkoption(self) -> bool:
|
||||
"""it's a dynsymlinkoption
|
||||
"""
|
||||
return True
|
||||
|
||||
|
||||
class SubDynOptionDescription(Syn):
|
||||
|
||||
def impl_getpath(self) -> str:
|
||||
"""get path
|
||||
"""
|
||||
path = self.opt.impl_getname()
|
||||
if self.rootpath:
|
||||
path = f'{self.rootpath}.{path}'
|
||||
return path
|
||||
|
||||
def getsubdyn(self):
|
||||
return self.opt.getsubdyn()
|
||||
|
||||
def impl_is_optiondescription(self):
|
||||
return True
|
||||
|
||||
def impl_is_symlinkoption(self):
|
||||
return False
|
||||
|
||||
def impl_is_leadership(self):
|
||||
return False
|
||||
|
||||
def impl_is_dynoptiondescription(self) -> bool:
|
||||
return True
|
||||
|
||||
def impl_getproperties(self):
|
||||
return self.opt.impl_getproperties()
|
||||
|
||||
|
||||
class SynDynOptionDescription(Syn):
|
||||
"""SynDynOptionDescription internal option, it's an instanciate synoptiondescription
|
||||
"""
|
||||
def __getattr__(self,
|
||||
name: str,
|
||||
) -> Any:
|
||||
# if not in SynDynOptionDescription, get value in self.opt
|
||||
return getattr(self.opt,
|
||||
name,
|
||||
)
|
||||
|
||||
def impl_getname(self) -> str:
|
||||
"""get name
|
||||
"""
|
||||
if self.opt.impl_is_dynoptiondescription():
|
||||
return self.opt.impl_getname(self._suffixes[-1])
|
||||
return self.opt.impl_getname()
|
||||
|
||||
def impl_getpath(self) -> str:
|
||||
"""get path
|
||||
"""
|
||||
path = self.impl_getname()
|
||||
if self.rootpath:
|
||||
path = f'{self.rootpath}.{path}'
|
||||
return path
|
||||
|
||||
def getsubdyn(self):
|
||||
return self.opt
|
||||
|
||||
|
||||
class SynDynLeadership(SynDynOptionDescription):
|
||||
"""SynDynLeadership internal option, it's an instanciate synoptiondescription
|
||||
"""
|
||||
def get_leader(self) -> SynDynOption:
|
||||
"""get the leader
|
||||
"""
|
||||
return self.opt.get_leader().to_dynoption(self.impl_getpath(),
|
||||
self._suffixes,
|
||||
)
|
||||
|
||||
def get_followers(self) -> Iterator[SynDynOption]:
|
||||
"""get followers
|
||||
"""
|
||||
subpath = self.impl_getpath()
|
||||
for follower in self.opt.get_followers():
|
||||
yield follower.to_dynoption(subpath,
|
||||
self._suffixes,
|
||||
)
|
||||
|
||||
def pop(self,
|
||||
*args,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
"""pop value for a follower
|
||||
"""
|
||||
self.opt.pop(*args,
|
||||
followers=self.get_followers(),
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
def follower_force_store_value(self,
|
||||
value,
|
||||
config_bag,
|
||||
owner,
|
||||
) -> None:
|
||||
"""force store value for a follower
|
||||
"""
|
||||
self.opt.follower_force_store_value(value,
|
||||
config_bag,
|
||||
owner,
|
||||
dyn=self,
|
||||
)
|
||||
|
||||
def get_suffixes(self) -> str:
|
||||
"""get suffix
|
||||
"""
|
||||
return self._suffixes
|
|
@ -1,5 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2017-2024 Team tiramisu (see AUTHORS for all contributors)
|
||||
# Copyright (C) 2017-2023 Team tiramisu (see AUTHORS for all contributors)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by the
|
||||
|
@ -32,97 +32,100 @@ from .portoption import PortOption
|
|||
|
||||
|
||||
class URLOption(StrOption):
|
||||
"""URLOption to check url value"""
|
||||
|
||||
"""URLOption to check url value
|
||||
"""
|
||||
__slots__ = tuple()
|
||||
path_re = re.compile(r"^[A-Za-z0-9\-\._~:/\?#\[\]@!%\$&\'\(\)\*\+,;=]+$")
|
||||
_type = "URL"
|
||||
_type = _('URL')
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
doc: str,
|
||||
*args,
|
||||
allow_ip: bool = False,
|
||||
type: str = "domainname",
|
||||
allow_without_dot=False,
|
||||
allow_range: bool = False,
|
||||
allow_zero: bool = False,
|
||||
allow_wellknown: bool = True,
|
||||
allow_registred: bool = True,
|
||||
allow_private: bool = False,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
def __init__(self,
|
||||
name: str,
|
||||
doc: str,
|
||||
default: Any=undefined,
|
||||
default_multi: Any=None,
|
||||
multi: bool=False,
|
||||
validators: Optional[List[Calculation]]=None,
|
||||
properties: Optional[List[str]]=None,
|
||||
warnings_only: bool=False,
|
||||
extra: Optional[Dict]=None,
|
||||
allow_ip: bool=False,
|
||||
type: str='domainname',
|
||||
allow_without_dot=False,
|
||||
allow_range: bool=False,
|
||||
allow_zero: bool=False,
|
||||
allow_wellknown: bool=True,
|
||||
allow_registred: bool=True,
|
||||
allow_private: bool=False) -> None:
|
||||
# pylint: disable=too-many-arguments,too-many-locals,redefined-builtin
|
||||
extra = {
|
||||
"_domainname": DomainnameOption(
|
||||
name,
|
||||
doc,
|
||||
allow_ip=allow_ip,
|
||||
type=type,
|
||||
allow_without_dot=allow_without_dot,
|
||||
),
|
||||
"_port": PortOption(
|
||||
name,
|
||||
doc,
|
||||
allow_range=allow_range,
|
||||
allow_zero=allow_zero,
|
||||
allow_wellknown=allow_wellknown,
|
||||
allow_registred=allow_registred,
|
||||
allow_private=allow_private,
|
||||
),
|
||||
}
|
||||
super().__init__(
|
||||
name,
|
||||
doc,
|
||||
extra=extra,
|
||||
*args,
|
||||
**kwargs,
|
||||
)
|
||||
extra = {'_domainname': DomainnameOption(name,
|
||||
doc,
|
||||
allow_ip=allow_ip,
|
||||
type=type,
|
||||
allow_without_dot=allow_without_dot),
|
||||
'_port': PortOption(name,
|
||||
doc,
|
||||
allow_range=allow_range,
|
||||
allow_zero=allow_zero,
|
||||
allow_wellknown=allow_wellknown,
|
||||
allow_registred=allow_registred,
|
||||
allow_private=allow_private)}
|
||||
super().__init__(name,
|
||||
doc,
|
||||
default=default,
|
||||
default_multi=default_multi,
|
||||
multi=multi,
|
||||
validators=validators,
|
||||
properties=properties,
|
||||
warnings_only=warnings_only,
|
||||
extra=extra)
|
||||
|
||||
def _get_domain_port_files(self, value: str) -> (str, str):
|
||||
if value.startswith("http://"):
|
||||
type_ = "http"
|
||||
def _get_domain_port_files(self,
|
||||
value: str) -> (str, str):
|
||||
if value.startswith('http://'):
|
||||
type_ = 'http'
|
||||
value = value[7:]
|
||||
elif value.startswith("https://"):
|
||||
type_ = "https"
|
||||
elif value.startswith('https://'):
|
||||
type_ = 'https'
|
||||
value = value[8:]
|
||||
else:
|
||||
raise ValueError(_("must start with http:// or " "https://"))
|
||||
raise ValueError(_('must start with http:// or '
|
||||
'https://'))
|
||||
# get domain/files
|
||||
splitted = value.split("/", 1)
|
||||
splitted = value.split('/', 1)
|
||||
if len(splitted) == 1:
|
||||
domain = value
|
||||
files = None
|
||||
else:
|
||||
domain, files = splitted
|
||||
# if port in domain
|
||||
splitted = domain.split(":", 1)
|
||||
splitted = domain.split(':', 1)
|
||||
if len(splitted) == 1:
|
||||
domain = splitted[0]
|
||||
port = {"http": "80", "https": "443"}[type_]
|
||||
port = {'http': '80',
|
||||
'https': '443'}[type_]
|
||||
else:
|
||||
domain, port = splitted
|
||||
return domain, port, files
|
||||
|
||||
def validate(self, value: str) -> None:
|
||||
def validate(self,
|
||||
value: str) -> None:
|
||||
super().validate(value)
|
||||
domain, port, files = self._get_domain_port_files(value)
|
||||
# validate port
|
||||
portoption = self.impl_get_extra("_port")
|
||||
portoption = self.impl_get_extra('_port')
|
||||
portoption.validate(port)
|
||||
# validate domainname
|
||||
domainnameoption = self.impl_get_extra("_domainname")
|
||||
domainnameoption = self.impl_get_extra('_domainname')
|
||||
domainnameoption.validate(domain)
|
||||
# validate files
|
||||
if files is not None and files != "" and not self.path_re.search(files):
|
||||
raise ValueError(_("must ends with a valid resource name"))
|
||||
if files is not None and files != '' and not self.path_re.search(files):
|
||||
raise ValueError(_('must ends with a valid resource name'))
|
||||
|
||||
def second_level_validation(self, value, warnings_only):
|
||||
domain, port, _ = self._get_domain_port_files(value)
|
||||
# validate port
|
||||
portoption = self.impl_get_extra("_port")
|
||||
portoption = self.impl_get_extra('_port')
|
||||
portoption.second_level_validation(port, warnings_only)
|
||||
# validate domainname
|
||||
domainnameoption = self.impl_get_extra("_domainname")
|
||||
domainnameoption = self.impl_get_extra('_domainname')
|
||||
domainnameoption.second_level_validation(domain, warnings_only)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2017-2024 Team tiramisu (see AUTHORS for all contributors)
|
||||
# Copyright (C) 2017-2023 Team tiramisu (see AUTHORS for all contributors)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by the
|
||||
|
@ -27,16 +27,16 @@ from .stroption import RegexpOption
|
|||
|
||||
|
||||
class UsernameOption(RegexpOption):
|
||||
"""UsernameOption to check unix username value"""
|
||||
|
||||
"""UsernameOption to check unix username value
|
||||
"""
|
||||
__slots__ = tuple()
|
||||
# regexp build with 'man 8 adduser' informations
|
||||
#regexp build with 'man 8 adduser' informations
|
||||
_regexp = re.compile(r"^[a-z_][a-z0-9_-]{0,30}[$a-z0-9_-]{0,1}$")
|
||||
_type = "unix username"
|
||||
_type = _('unix username')
|
||||
|
||||
|
||||
class GroupnameOption(UsernameOption):
|
||||
"""GroupnameOption to check unix group value"""
|
||||
|
||||
"""GroupnameOption to check unix group value
|
||||
"""
|
||||
__slots__ = tuple()
|
||||
_type = "unix groupname"
|
||||
_type = _('unix groupname')
|
||||
|
|
File diff suppressed because it is too large
Load diff
1051
tiramisu/todict.py
1051
tiramisu/todict.py
File diff suppressed because it is too large
Load diff
1007
tiramisu/value.py
1007
tiramisu/value.py
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue