Compare commits

..

177 commits

Author SHA1 Message Date
f189608886 bump: version 1.2.0a59 → 1.2.0a60 2026-01-29 08:39:19 +01:00
9d7838ce31 feat: support transitive in properties variable 2026-01-29 08:39:11 +01:00
80027569a5 bump: version 1.2.0a58 → 1.2.0a59 2026-01-21 09:38:19 +01:00
f3c323bd25 fix: better support for secret manager 2026-01-21 08:43:09 +01:00
34e0654bbe fix: leadership and frozen 2026-01-19 17:01:44 +01:00
349e30fc10 bump: version 1.2.0a57 → 1.2.0a58 2026-01-16 13:35:31 +01:00
7027aaefd4 fix: secret with follower 2026-01-16 13:35:19 +01:00
f9c73783c5 bump: version 1.2.0a56 → 1.2.0a57 2026-01-16 08:48:46 +01:00
1ee82bede9 fix: add transition 2026-01-15 22:10:11 +01:00
9a7d4ef803 bump: version 1.2.0a55 → 1.2.0a56 2026-01-15 08:33:20 +01:00
4c8a3c813a fix: types with subfamily 2026-01-15 08:33:14 +01:00
6ae9662e75 bump: version 1.2.0a54 → 1.2.0a55 2026-01-15 08:15:28 +01:00
f495642e39 fix: better custom types support 2026-01-15 08:15:18 +01:00
bc27a98229 bump: version 1.2.0a53 → 1.2.0a54 2026-01-14 14:29:30 +01:00
a70627db2b fix: issymlinkoption is not available for an optiondescription 2026-01-14 14:29:23 +01:00
a593fa3d35 fix: better error messages 2026-01-12 09:08:59 +01:00
ae696e1738 bump: version 1.2.0a52 → 1.2.0a53 2026-01-05 08:17:00 +01:00
aa7bf6562e fix: new tiramisu version support 2026-01-04 19:48:45 +01:00
41a65ef2e5 bump: version 1.2.0a51 → 1.2.0a52 2026-01-03 17:03:20 +01:00
2f179a2bf6 feat: load tiramisu objects from cache 2026-01-03 16:54:12 +01:00
5a6e526d38 bump: version 1.2.0a50 → 1.2.0a51 2025-12-30 10:56:15 +01:00
42bd463810 feat: add types support 2025-12-29 11:13:17 +01:00
bb79bbba17 fix: better error message 2025-12-23 21:11:13 +01:00
018634a5e8 bump: version 1.2.0a49 → 1.2.0a50 2025-12-23 10:18:35 +01:00
3661131f9f fix: improvment 2025-12-23 10:15:56 +01:00
5ae05434fe bump: version 1.2.0a48 → 1.2.0a49 2025-12-22 19:05:11 +01:00
0682613f94 fix: better error message 2025-12-22 19:05:05 +01:00
27350dcab4 bump: version 1.2.0a47 → 1.2.0a48 2025-12-22 15:35:58 +01:00
fe66316e9c fix: documentation 2025-12-22 15:35:53 +01:00
bad47893d0 bump: version 1.2.0a46 → 1.2.0a47 2025-12-22 11:47:44 +01:00
57894d09b1 fix: description 2025-12-22 11:47:35 +01:00
b087aa39f7 bump: version 1.2.0a45 → 1.2.0a46 2025-12-22 09:58:58 +01:00
0adf0d3f73 fix: duplicate description 2025-12-22 09:58:44 +01:00
b582a57792 bump: version 1.2.0a44 → 1.2.0a45 2025-12-22 08:46:58 +01:00
c39e232fa9 feat: better translation 2025-12-22 08:46:46 +01:00
a757f739a7 feat: add "do" extension for jinja2 2025-12-22 08:43:13 +01:00
feff5dbd75 fix: user_datas => user_data 2025-12-22 08:42:38 +01:00
31c9efbf05 bump: version 1.2.0a43 → 1.2.0a44 2025-11-28 13:18:14 +01:00
e77b65ffd5 fix: disabled choices must not generate error when loaded from .rougailcli.yml 2025-11-28 13:17:50 +01:00
8f81df6909 bump: version 1.2.0a42 → 1.2.0a43 2025-11-21 08:32:42 +01:00
4d730a6219 fix: better rougailconfig copy 2025-11-21 08:32:33 +01:00
25dc5bfd42 fix: port is a string 2025-11-21 08:27:54 +01:00
9acb8b71c6 feat: add boolean return_type in validators 2025-11-21 08:27:22 +01:00
8d6cf62204 bump: version 1.2.0a41 → 1.2.0a42 2025-11-06 21:52:37 +01:00
e674217b63 fix: black 2025-11-06 21:33:24 +01:00
a68a52ad67 feat: can add limit length for a variable 2025-11-06 21:33:01 +01:00
439cf7fe2d bump: version 1.2.0a40 → 1.2.0a41 2025-11-06 06:32:55 +01:00
2ab5aee3cf feat: choice if invalid value or unknown variable in user data is a fatal error or not 2025-11-05 21:46:04 +01:00
21f1526891 bump: version 1.2.0a39 → 1.2.0a40 2025-11-03 08:52:52 +01:00
bf3396aa59 feat: can add name for a tiramisu config 2025-11-03 08:52:46 +01:00
656df6068f feat: active warnings for validators 2025-11-01 10:48:07 +01:00
d3477d6241 bump: version 1.2.0a38 → 1.2.0a39 2025-10-29 12:12:00 +01:00
a3aff66523 fix: load config leadership 2025-10-29 12:11:55 +01:00
8363580306 fix: do not load secrets if not allowed 2025-10-29 09:26:11 +01:00
cc790bb930 fix: update translation 2025-10-26 15:29:31 +01:00
9a9544c7f9 fix: add test 2025-10-26 14:35:03 +01:00
192325e9e0 feat: add tags support 2025-10-26 09:20:12 +01:00
e42347cf3d bump: version 1.2.0a37 → 1.2.0a38 2025-10-22 17:10:19 +02:00
0dfb901fd5 ConvertDynOptionDescription.convert_identifier_to_path is now a staticmethod 2025-10-19 20:19:49 +02:00
c80aca1e12 bump: version 1.2.0a36 → 1.2.0a37 2025-10-16 08:22:48 +02:00
c8aad30517 fix: name is uncalculated 2025-10-16 08:21:07 +02:00
4df2b013df feat: keep forced_descriptions information (mostly for rougail-output-doc) 2025-10-14 13:57:09 +02:00
5d8278acf8 bump: version 1.2.0a35 → 1.2.0a36 2025-10-10 08:16:50 +02:00
36f13dec22 feat: can desactivate isolated namespace feature 2025-10-10 08:09:37 +02:00
c4404a7d46 feat: add return_type to property 2025-10-07 21:11:42 +02:00
92b5257e66 feat: remove return_values_not_error and only_default parameter 2025-10-06 21:41:56 +02:00
5759e4f86b feat: user_data can load secret manager values 2025-10-05 21:41:26 +02:00
fb0f1e5f2c fix: translation for property is now in rougail 2025-10-05 21:40:02 +02:00
e8c692d39c fix: error in InformationCalculation errors 2025-10-03 22:41:38 +02:00
8bf07735b8 fix: proprerty with unknown variable 2025-10-03 22:31:09 +02:00
b120dd8e69 bump: version 1.2.0a34 → 1.2.0a35 2025-10-02 22:41:32 +02:00
64e2d137c5 feat: add warning class 2025-10-02 22:41:19 +02:00
fbba016007 bump: version 1.2.0a33 → 1.2.0a34 2025-09-30 22:02:21 +02:00
f5f55dd853 feat: for formatter 2025-09-30 22:02:07 +02:00
899226f7d2 bump: version 1.2.0a32 → 1.2.0a33 2025-09-29 21:27:36 +02:00
4bf7274871 fix: better doc for calculation with unknown variable 2025-09-29 21:19:13 +02:00
dcb1800346 bump: version 1.2.0a31 → 1.2.0a32 2025-09-29 10:58:37 +02:00
5e0af148d5 feat(#28): default value for a calculated variable with an unknown optional variable 2025-09-28 15:44:11 +02:00
bbcffffb82 feat(#26): cidr and network_cidr type is depreciate 2025-09-24 22:14:59 +02:00
99dddf20a9 feat(#25): add integer type which will replace number type 2025-09-23 20:30:16 +02:00
adff39d4d3 bump: version 1.2.0a30 → 1.2.0a31 2025-09-22 14:36:42 +02:00
bfc59e8084 fix: dictionary => structure 2025-09-22 14:36:32 +02:00
e2d5a30c21 bump: version 1.2.0a29 → 1.2.0a30 2025-09-20 18:46:20 +02:00
9ee03b22bb feat(40): better conflict error message with dynamic name 2025-09-20 18:46:08 +02:00
c8d5656094 feat: add new get_root_option function 2025-08-28 21:24:45 +02:00
c4b90cbe42 fix: update test 2025-08-28 21:24:04 +02:00
62620d9b2e bump: version 1.2.0a28 → 1.2.0a29 2025-06-20 07:51:48 +03:00
bed7a1d3b5 fix: UserDatas, do now set modified option in second round 2025-06-20 07:51:35 +03:00
06c87718d6 bump: version 1.2.0a27 → 1.2.0a28 2025-06-18 16:50:18 +03:00
a0677e7b00 fix: conversion 2025-06-18 16:49:45 +03:00
c840d57734 bump: version 1.2.0a26 → 1.2.0a27 2025-06-18 07:49:44 +03:00
a3b2699289 feat: separate rougail and rougail-base 2025-06-18 07:49:39 +03:00
c7a66a034e bump: version 1.2.0a25 → 1.2.0a26 2025-05-26 08:11:43 +02:00
9e06f1142e fix: user_data better support for follower variable 2025-05-19 19:08:32 +02:00
b902e15243 bump: version 1.2.0a24 → 1.2.0a25 2025-05-14 08:44:37 +02:00
cbccc8087f feat: can launch UserDatas twice 2025-05-12 19:25:50 +02:00
fecab8aca6 bump: version 1.2.0a23 → 1.2.0a24 2025-05-12 09:13:57 +02:00
97cc2460b2 fix: upgrade translation 2025-05-12 08:52:59 +02:00
5a4bb343b0 fix: black 2025-05-12 08:45:39 +02:00
bb1f117ed1 bump: version 1.2.0a22 → 1.2.0a23 2025-05-09 08:21:40 +02:00
1662568c17 fix: add_quotes 2025-05-09 08:21:31 +02:00
6be773de3c fix: tiramisu_display_name could display only description 2025-05-08 22:10:28 +02:00
70b6f3d274 fix: use own undefined 2025-05-08 22:09:52 +02:00
e7a1caf113 fix: support of default_dictionary_format_version file in tests 2025-05-07 08:06:30 +02:00
b229154df5 fix: simplify version support 2025-05-06 08:09:37 +02:00
e71d4600d7 bump: version 1.2.0a21 → 1.2.0a22 2025-05-05 08:49:45 +02:00
adc580069c fix: user_datas support empty directory 2025-05-05 08:49:11 +02:00
9c940f8b28 bump: version 1.2.0a20 → 1.2.0a21 2025-05-02 08:12:31 +02:00
6167e1ea2c fix: support {{ suffix }} name in 1.1 format version 2025-05-02 08:12:06 +02:00
46e2ede81d fix: do not force use_data usage 2025-05-02 08:12:03 +02:00
2488cc471e fix: validators for an index 2025-05-01 21:27:19 +02:00
1dcc00429c bump: version 1.2.0a19 → 1.2.0a20 2025-04-30 09:02:51 +02:00
2f9e584394 fix: remove symlink 2025-04-30 09:02:16 +02:00
2027da0675 bump: version 1.2.0a18 → 1.2.0a19 2025-04-30 08:56:28 +02:00
efb23c350e fix: update translation 2025-04-29 23:12:32 +02:00
52c8277238 fix: remove negative_description support 2025-04-29 22:48:33 +02:00
3b0130420d fix: redefine family in flatten mode 2025-04-29 22:48:03 +02:00
00f29c37c4 feat: add ymlfile names in ConfigError message 2025-04-27 16:35:13 +02:00
b9ea5edb07 fix: update tests 2025-04-27 10:30:31 +02:00
136a0e71b7 fix: better multi check 2025-04-21 19:35:02 +02:00
fc56827706 bump: version 1.2.0a17 → 1.2.0a18 2025-04-09 21:19:54 +02:00
77490ca176 fix: version 2025-04-09 21:19:45 +02:00
65ffaef2fe bump: version 1.2.0a16 → 1.2.0a17 2025-04-09 09:02:38 +02:00
c494a4662f fix: better detection of multi variable in default attribute 2025-04-09 09:02:32 +02:00
0bc1e24d38 fix: better error message 2025-04-09 09:01:48 +02:00
e59b9e84df bump: version 1.2.0a15 → 1.2.0a16 2025-04-03 20:47:28 +02:00
62097b552a feat: reoganise param conversion + better variable validation 2025-04-03 20:47:12 +02:00
19249875c3 fix: correction in namespace calculation 2025-04-02 21:46:47 +02:00
ae89e30e60 bump: version 1.2.0a14 → 1.2.0a15 2025-04-01 22:21:37 +02:00
e1b2d36aae fix: update tests 2025-04-01 22:06:18 +02:00
cc086f086a fix: do not raise variable in property with force_optional 2025-04-01 21:10:22 +02:00
7ee65b6cab fix: update translation 2025-04-01 21:09:49 +02:00
1858eeeb06 feat: can link regexp variable 2025-04-01 08:55:00 +02:00
dc311466a2 feat: can link choice variable 2025-04-01 08:36:23 +02:00
18df35acfe bump: version 1.2.0a13 → 1.2.0a14 2025-03-30 18:42:35 +02:00
0e522db15f fix: strutural step should not be available in commandline 2025-03-30 18:42:13 +02:00
07a22d7966 bump: version 1.2.0a12 → 1.2.0a13 2025-03-30 18:38:33 +02:00
7f9d6f17d7 fix: allow no user_datas installation (for example to generate doc) 2025-03-27 20:05:20 +01:00
2654141002 bump: version 1.2.0a11 → 1.2.0a12 2025-03-19 11:43:13 +01:00
999b53889c feat: add rougail secret_manager 2025-03-19 11:43:04 +01:00
d35fe16cd9 bump: version 1.2.0a10 → 1.2.0a11 2025-02-17 15:45:33 +01:00
04aa9444a3 fix: add get remove properties 2025-02-17 15:45:27 +01:00
9c7fb1d505 bump: version 1.2.0a9 → 1.2.0a10 2025-02-17 09:21:02 +01:00
70003fcbc5 fix: we can define structural plugin when generate documentation 2025-02-17 09:20:38 +01:00
85f3b9f80f fix: if a variable in user_data not existe, it's no a warnings 2025-02-17 09:19:31 +01:00
b0687fdcc6 bump: version 1.2.0a8 → 1.2.0a9 2025-02-10 10:32:57 +01:00
cc5aaf6393 feat: can change defaut params for an option 2025-02-10 10:32:48 +01:00
df2fcb467f fix: if no description, generate negative_description too 2025-02-10 10:09:34 +01:00
7b9d7ce419 fix: error messages 2025-02-07 08:08:55 +01:00
63f76dc68f bump: version 1.2.0a7 → 1.2.0a8 2025-01-04 12:01:17 +01:00
e7e9687b8d fix: better support of not_for_commandline feature 2025-01-04 12:01:08 +01:00
0fea822c91 bump: version 1.2.0a6 → 1.2.0a7 2025-01-02 22:01:56 +01:00
ea6baa3dc2 fix: add structural_directory 2025-01-02 22:01:38 +01:00
7d830d5e40 bump: version 1.2.0a5 → 1.2.0a6 2025-01-02 21:19:40 +01:00
81d86e7b6f fix: add path.py 2025-01-02 21:19:16 +01:00
7a5a1b42e8 bump: version 1.2.0a4 → 1.2.0a5 2025-01-02 21:06:47 +01:00
3849c42cba feat: upgrade is not in formatter 2025-01-02 21:06:13 +01:00
6c1df5578f feat: remove prefix 2025-01-02 21:02:44 +01:00
dfd31c4fb4 bump: version 1.2.0a3 → 1.2.0a4 2024-12-11 21:00:22 +01:00
45959ac18b fix: remove link 2024-12-11 20:58:08 +01:00
9e8c6f96c5 feat: move test to a new project rougail-tests 2024-12-11 20:54:54 +01:00
00e0941f6e fix: reorganise user_datas 2024-12-11 20:54:03 +01:00
8afb787c98 fix: only change prefix if path is relative 2024-12-11 20:51:08 +01:00
a91a4d6a55 feat: output could have annotator 2024-12-11 20:50:15 +01:00
688aa8d053 bump: version 1.2.0a2 → 1.2.0a3 2024-11-28 08:31:00 +01:00
4c613f6425 fix: add user_datas file 2024-11-28 08:30:47 +01:00
145b7be0a5 bump: version 1.2.0a1 → 1.2.0a2 2024-11-27 16:09:18 +01:00
829d7692ad fix: separate UserDatas 2024-11-27 16:09:04 +01:00
ea34751e08 fix: options could be a list 2024-11-27 10:22:00 +01:00
c25a66f0cb feat: add "exists" attribut for a family 2024-11-27 10:14:42 +01:00
fdfb7ec73b bump: version 1.2.0a0 → 1.2.0a1 2024-11-25 09:18:04 +01:00
db768f94af fix: dynamic variable could be optional 2024-11-25 09:17:27 +01:00
9782bcde95 fix: dynamic variable declare in verion 1.0 has {{ suffix }} 2024-11-25 09:16:48 +01:00
fbb1446fa3 fix: user_data plugins could have annotator function 2024-11-25 09:14:58 +01:00
56659f7ea4 fix: do not modify a dynamic variable if has default value 2024-11-25 09:10:44 +01:00
af3f77c920 bump: version 1.1.1 → 1.2.0a0 2024-11-08 08:13:27 +01:00
e29c0c8abc feat: add force_optional option to allow charging structure even if all variables are not available 2024-11-08 08:12:33 +01:00
1923 changed files with 20148 additions and 12450 deletions

View file

@ -1,3 +1,462 @@
## 1.2.0a60 (2026-01-29)
### Feat
- support transitive in properties variable
## 1.2.0a59 (2026-01-21)
### Fix
- better support for secret manager
- leadership and frozen
## 1.2.0a58 (2026-01-16)
### Fix
- secret with follower
## 1.2.0a57 (2026-01-16)
### Fix
- add transition
## 1.2.0a56 (2026-01-15)
### Fix
- types with subfamily
## 1.2.0a55 (2026-01-15)
### Fix
- better custom types support
## 1.2.0a54 (2026-01-14)
### Fix
- issymlinkoption is not available for an optiondescription
- better error messages
## 1.2.0a53 (2026-01-05)
### Fix
- new tiramisu version support
## 1.2.0a52 (2026-01-03)
### Feat
- load tiramisu objects from cache
## 1.2.0a51 (2025-12-30)
### Feat
- add types support
### Fix
- better error message
## 1.2.0a50 (2025-12-23)
### Fix
- improvment
## 1.2.0a49 (2025-12-22)
### Fix
- better error message
## 1.2.0a48 (2025-12-22)
### Fix
- documentation
## 1.2.0a47 (2025-12-22)
### Fix
- description
## 1.2.0a46 (2025-12-22)
### Fix
- duplicate description
## 1.2.0a45 (2025-12-22)
### Feat
- better translation
- add "do" extension for jinja2
### Fix
- user_datas => user_data
## 1.2.0a44 (2025-11-28)
### Fix
- disabled choices must not generate error when loaded from .rougailcli.yml
## 1.2.0a43 (2025-11-21)
### Feat
- add boolean return_type in validators
### Fix
- better rougailconfig copy
- port is a string
## 1.2.0a42 (2025-11-06)
### Feat
- can add limit length for a variable
### Fix
- black
## 1.2.0a41 (2025-11-06)
### Feat
- choice if invalid value or unknown variable in user data is a fatal error or not
## 1.2.0a40 (2025-11-03)
### Feat
- can add name for a tiramisu config
- active warnings for validators
## 1.2.0a39 (2025-10-29)
### Feat
- add tags support
### Fix
- load config leadership
- do not load secrets if not allowed
- update translation
- add test
## 1.2.0a38 (2025-10-22)
## 1.2.0a37 (2025-10-16)
### Feat
- keep forced_descriptions information (mostly for rougail-output-doc)
### Fix
- name is uncalculated
## 1.2.0a36 (2025-10-10)
### Feat
- can desactivate isolated namespace feature
- add return_type to property
- remove return_values_not_error and only_default parameter
- user_data can load secret manager values
### Fix
- translation for property is now in rougail
- error in InformationCalculation errors
- proprerty with unknown variable
## 1.2.0a35 (2025-10-02)
### Feat
- add warning class
## 1.2.0a34 (2025-09-30)
### Feat
- for formatter
## 1.2.0a33 (2025-09-29)
### Fix
- better doc for calculation with unknown variable
## 1.2.0a32 (2025-09-29)
### Feat
- **#28**: default value for a calculated variable with an unknown optional variable
- **#26**: cidr and network_cidr type is depreciate
- **#25**: add integer type which will replace number type
## 1.2.0a31 (2025-09-22)
### Fix
- dictionary => structure
## 1.2.0a30 (2025-09-20)
### Feat
- **40**: better conflict error message with dynamic name
- add new get_root_option function
### Fix
- update test
## 1.2.0a29 (2025-06-20)
### Fix
- UserDatas, do now set modified option in second round
## 1.2.0a28 (2025-06-18)
### Fix
- conversion
## 1.2.0a27 (2025-06-18)
### Feat
- separate rougail and rougail-base
## 1.2.0a26 (2025-05-26)
### Fix
- user_data better support for follower variable
## 1.2.0a25 (2025-05-14)
### Feat
- can launch UserDatas twice
## 1.2.0a24 (2025-05-12)
### Fix
- upgrade translation
- black
## 1.2.0a23 (2025-05-09)
### Fix
- add_quotes
- tiramisu_display_name could display only description
- use own undefined
- support of default_dictionary_format_version file in tests
- simplify version support
## 1.2.0a22 (2025-05-05)
### Fix
- user_datas support empty directory
## 1.2.0a21 (2025-05-02)
### Fix
- support {{ suffix }} name in 1.1 format version
- do not force use_data usage
- validators for an index
## 1.2.0a20 (2025-04-30)
### Fix
- remove symlink
## 1.2.0a19 (2025-04-30)
### Feat
- add ymlfile names in ConfigError message
### Fix
- update translation
- remove negative_description support
- redefine family in flatten mode
- update tests
- better multi check
## 1.2.0a18 (2025-04-09)
### Fix
- version
## 1.2.0a17 (2025-04-09)
### Fix
- better detection of multi variable in default attribute
- better error message
## 1.2.0a16 (2025-04-03)
### Feat
- reoganise param conversion + better variable validation
### Fix
- correction in namespace calculation
## 1.2.0a15 (2025-04-01)
### Feat
- can link regexp variable
- can link choice variable
### Fix
- update tests
- do not raise variable in property with force_optional
- update translation
## 1.2.0a14 (2025-03-30)
### Fix
- strutural step should not be available in commandline
## 1.2.0a13 (2025-03-27)
### Fix
- allow no user_datas installation (for example to generate doc)
## 1.2.0a12 (2025-03-19)
### Feat
- add rougail secret_manager
## 1.2.0a11 (2025-02-17)
### Fix
- add get remove properties
## 1.2.0a10 (2025-02-17)
### Fix
- we can define structural plugin when generate documentation
- if a variable in user_data not existe, it's no a warnings
## 1.2.0a9 (2025-02-10)
### Feat
- can change defaut params for an option
### Fix
- if no description, generate negative_description too
- error messages
## 1.2.0a8 (2025-01-04)
### Fix
- better support of not_for_commandline feature
## 1.2.0a7 (2025-01-02)
### Fix
- add structural_directory
## 1.2.0a6 (2025-01-02)
### Fix
- add path.py
## 1.2.0a5 (2025-01-02)
### Feat
- upgrade is not in formatter
- remove prefix
## 1.2.0a4 (2024-12-11)
### Feat
- move test to a new project rougail-tests
- output could have annotator
### Fix
- remove link
- reorganise user_datas
- only change prefix if path is relative
## 1.2.0a3 (2024-11-28)
### Fix
- add user_datas file
## 1.2.0a2 (2024-11-27)
### Feat
- add "exists" attribut for a family
### Fix
- separate UserDatas
- options could be a list
## 1.2.0a1 (2024-11-25)
### Fix
- dynamic variable could be optional
- dynamic variable declare in verion 1.0 has {{ suffix }}
- user_data plugins could have annotator function
- do not modify a dynamic variable if has default value
## 1.2.0a0 (2024-11-08)
### Feat
- add force_optional option to allow charging structure even if all variables are not available
## 1.1.1 (2024-11-06)
### Fix

211
README.fr.md Normal file
View file

@ -0,0 +1,211 @@
---
gitea: none
include_toc: true
---
[🇬🇧 (EN)](README.md) - [🇫🇷 (FR)](README.fr.md)
| Variable | Description | Valeur par défaut | Type | Contrôle des accès | Validateur |
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------|----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **<a id="default_structural_format_version" name="default_structural_format_version">default_structural_format_version</a>**<br/>**Ligne de commande** : <br/>-v, --default_structural_format_version<br/>**Variable d'environnement** : DEFAULT_STRUCTURAL_FORMAT_VERSION | Version par défaut du format des fichiers de structure.<br/>Cette valeur n&#x27;est utilisée que si la version n&#x27;est pas définie dans le fichier de structure. | | [`choice`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | **Choix** : <br/>&nbsp;1.0<br/>&nbsp;1.1<br/>&nbsp;null |
| **<a id="types" name="types">types</a>**<br/>**Ligne de commande** : <br/>--types<br/>**Variable d'environnement** : TYPES | Fichier avec types personnalisés.<br/>Ce fichier contient des types personnalisés au format Rougail pour les fichiers de structure. | | [`UNIX filename`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `multiple` | `standard` | `unique`<br/>&nbsp;le nom de fichier peut être une chemin relatif<br/>&nbsp;le fichier doit exister<br/>&nbsp;type de fichier autorisé: "fichier" et "répertoire". |
| **<a id="functions_files" name="functions_files">functions_files</a>**<br/>**Ligne de commande** : <br/>--functions_files<br/>**Variable d'environnement** : FUNCTIONS_FILES | Fichier avec les fonctions.<br/>Ce fichier contient des filtres et des fonctions Jinja2 supplémentaires utilisables dans les fichiers de structure. | | [`UNIX filename`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `multiple` | `standard` | `unique`<br/>&nbsp;le nom de fichier peut être une chemin relatif<br/>&nbsp;le fichier doit exister<br/>&nbsp;type de fichier autorisé: "file". |
| **<a id="modes_level" name="modes_level">modes_level</a>**<br/>**Ligne de commande** : <br/>--modes_level<br/>**Variable d'environnement** : MODES_LEVEL | Tous les niveaux de modes valides. | | [`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `multiple` | `standard` | `unique` |
| **<a id="default_family_mode" name="default_family_mode">default_family_mode</a>**<br/>**Variable d'environnement** : DEFAULT_FAMILY_MODE | Mode par défaut pour une famille. | le premier défini dans "[Tous les niveaux de modes valides](#modes_level)" | [`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | Ce mode doit être disponible dans "[Tous les niveaux de modes valides](#modes_level)". |
| **<a id="default_variable_mode" name="default_variable_mode">default_variable_mode</a>**<br/>**Variable d'environnement** : DEFAULT_VARIABLE_MODE | Mode par défaut pour une variable. | si la variable "[Tous les niveaux de modes valides](#modes_level)" est définit, la valeur par défaut est le second élément disponible, sinon, le premier | [`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | Ce mode doit être disponible dans "[Tous les niveaux de modes valides](#modes_level)". |
| **<a id="base_option_name" name="base_option_name">base_option_name</a>**<br/>**Variable d'environnement** : BASE_OPTION_NAME | Nom de l&#x27;option pour l&#x27;option de base. | baseoption | [`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="export_with_import" name="export_with_import">export_with_import</a>**<br/>**Variable d'environnement** : EXPORT_WITH_IMPORT | Dans le fichier de cache, ne pas importer Tiramisu et autres dépendances. | true | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="tiramisu_cache" name="tiramisu_cache">tiramisu_cache</a>**<br/>**Ligne de commande** : <br/>-t, --tiramisu_cache<br/>**Variable d'environnement** : TIRAMISU_CACHE | Enregistrer le cache Tiramisu dans le fichier.<br/>Ce fichier contient les instructions Tiramisu utilisé en interne pour charger les variables.<br/>Ce fichier peut être utilisé pour le débogage. | | [`UNIX filename`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | •&nbsp;le nom de fichier peut être une chemin relatif<br/>&nbsp;type de fichier autorisé: "file". |
| **<a id="internal_functions" name="internal_functions">internal_functions</a>**<br/>**Variable d'environnement** : INTERNAL_FUNCTIONS | Nom des fonctions internes qu&#x27;il est possible d&#x27;utiliser comme fonction. | | [`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `multiple` | `standard` | |
| **<a id="extra_annotators" name="extra_annotators">extra_annotators</a>**<br/>**Variable d'environnement** : EXTRA_ANNOTATORS | Nom des annotators supplémentaires. | | [`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `multiple` | `standard` | |
| **<a id="suffix" name="suffix">suffix</a>**<br/>**Variable d'environnement** : SUFFIX | Suffix ajouté pour généré le nom des options. | | [`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="force_optional" name="force_optional">force_optional</a>**<br/>**Ligne de commande** : <br/>&nbsp;--force_optional<br/>&nbsp;--no-force_optional<br/>**Variable d'environnement** : FORCE_OPTIONAL | Toutes les variables dans un calcul sont optionnelles. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `obligatoire` | `standard` | |
| **<a id="load_unexist_redefine" name="load_unexist_redefine">load_unexist_redefine</a>**<br/>**Variable d'environnement** : LOAD_UNEXIST_REDEFINE | Charger les variables redéfinis même si elles n&#x27;existe pas. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
## Le gestionnaire de secret
> [!NOTE]
>
> **Chemin** : secret_manager\
> `standard`
| Variable | Description | Valeur par défaut | Type | Contrôle des accès |
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------|--------------------------------------------------------------------------------------------------|----------------------|
| **<a id="secret_manager.pattern" name="secret_manager.pattern">secret_manager.pattern</a>**<br/>**Ligne de commande** : <br/>--secret_manager.pattern<br/>**Variable d'environnement** : SECRET_MANAGER.PATTERN | Le modèle de secret permettant de construire le nom de l&#x27;élément recherché dans le gestionnaire de secrets.<br/>Le modèle est au format Jinja2. | {{ project }} - {{ environment }} - {{ service }} - {{ user }} | [`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `obligatoire` | `standard` |
## Load and exporter steps
> [!NOTE]
>
> **Chemin** : step\
> `standard`
| Variable | Description | Valeur par défaut | Type | Contrôle des accès | Validateur |
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------|---------------------|--------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **<a id="step.structural" name="step.structural">step.structural</a>**<br/>**Variable d'environnement** : STEP.STRUCTURAL | Sélection pour structure. | •&nbsp;directory | [`choice`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `multiple` | `standard` | **Choix** : <br/>&nbsp;directory<br/>&nbsp;string<br/>&nbsp;commandline<br/>&nbsp;risotto |
| **<a id="step.user_data" name="step.user_data">step.user_data</a>**<br/>**Ligne de commande** : <br/>-u, --step.user_data<br/>**Variable d'environnement** : STEP.USER_DATA | Sélection pour données utilisateur. | | [`choice`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `multiple` | `standard` *`désactivé`*<br/>**Désactivé** : les sorties "doc" n'autorisent pas des données utilisateur | `unique`<br/>**Choix** : <br/>&nbsp;yaml<br/>&nbsp;environment<br/>&nbsp;commandline<br/>&nbsp;ansible<br/>&nbsp;questionary<br/>&nbsp;risotto<br/>&nbsp;bitwarden |
| **<a id="step.output" name="step.output">step.output</a>**<br/>**Ligne de commande** : <br/>-o, --step.output<br/>**Variable d'environnement** : STEP.OUTPUT | Sélection pour sortie. | display | [`choice`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `obligatoire` | `standard` | **Choix** : <br/>&nbsp;display<br/>&nbsp;json<br/>&nbsp;doc<br/>&nbsp;table<br/>&nbsp;ansible |
| Variable | Description | Valeur par défaut | Type | Contrôle des accès |
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------|---------------------|---------------------------------------------------------------------------------------------------|----------------------|
| **<a id="define_default_params" name="define_default_params">define_default_params</a>**<br/>**Ligne de commande** : <br/>&nbsp;--define_default_params<br/>&nbsp;--no-define_default_params<br/>**Variable d'environnement** : DEFINE_DEFAULT_PARAMS | Sur charger les paramètre par défaut pour le type d&#x27;option. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `obligatoire` | `standard` |
## Paramètre par défaut pour le type d&#x27;option
> [!NOTE]
>
> **Chemin** : default_params\
> `standard` *`désactivé`*\
> **Désactivé** : lorsque la variable "[Sur charger les paramètre par défaut pour le type d&#x27;option](#define_default_params)" a la valeur "false"
### UNIX filename
> [!NOTE]
>
> **Chemin** : default_params.unix_filename\
> `standard`
| Variable | Description | Valeur par défaut | Type | Contrôle des accès | Validateur |
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------|----------------------------------|-----------------------------------------------------------------------------------------------|----------------------|----------------------------------------------------------------|
| **<a id="default_params.unix_filename.allow_relative" name="default_params.unix_filename.allow_relative">default_params.unix_filename.allow_relative</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.unix_filename.allow_relative<br/>&nbsp;--default_params.unix_filename.no-allow_relative<br/>**Variable d'environnement** : DEFAULT_PARAMS.UNIX_FILENAME.ALLOW_RELATIVE | Le nom de fichier peut être une chemin relatif. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.unix_filename.test_existence" name="default_params.unix_filename.test_existence">default_params.unix_filename.test_existence</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.unix_filename.test_existence<br/>&nbsp;--default_params.unix_filename.no-test_existence<br/>**Variable d'environnement** : DEFAULT_PARAMS.UNIX_FILENAME.TEST_EXISTENCE | Le fichier doit exister. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.unix_filename.types" name="default_params.unix_filename.types">default_params.unix_filename.types</a>**<br/>**Ligne de commande** : <br/>--default_params.unix_filename.types<br/>**Variable d'environnement** : DEFAULT_PARAMS.UNIX_FILENAME.TYPES | Type de fichier autorisé. | •&nbsp;file<br/>&nbsp;directory | [`choice`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `multiple` | `standard` | `unique`<br/>**Choix** : <br/>&nbsp;file<br/>&nbsp;directory |
### IP
> [!NOTE]
>
> **Chemin** : default_params.ip\
> `standard`
| Variable | Description | Valeur par défaut | Type | Contrôle des accès |
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------|---------------------|-------------------------------------------------------------------------------------|----------------------|
| **<a id="default_params.ip.private_only" name="default_params.ip.private_only">default_params.ip.private_only</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.ip.private_only<br/>&nbsp;--default_params.ip.no-private_only<br/>**Variable d'environnement** : DEFAULT_PARAMS.IP.PRIVATE_ONLY | Les IP privées sont autorisées. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` |
| **<a id="default_params.ip.allow_reserved" name="default_params.ip.allow_reserved">default_params.ip.allow_reserved</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.ip.allow_reserved<br/>&nbsp;--default_params.ip.no-allow_reserved<br/>**Variable d'environnement** : DEFAULT_PARAMS.IP.ALLOW_RESERVED | Les IP réservées sont autorisés. | true | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` |
| **<a id="default_params.ip.cidr" name="default_params.ip.cidr">default_params.ip.cidr</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.ip.cidr<br/>&nbsp;--default_params.ip.no-cidr<br/>**Variable d'environnement** : DEFAULT_PARAMS.IP.CIDR | L&#x27;IP doit être au format CIDR. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` |
### CIDR
> [!NOTE]
>
> **Chemin** : default_params.cidr\
> `standard`
| Variable | Description | Valeur par défaut | Type | Contrôle des accès |
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------|---------------------|-------------------------------------------------------------------------------------|----------------------|
| **<a id="default_params.cidr.private_only" name="default_params.cidr.private_only">default_params.cidr.private_only</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.cidr.private_only<br/>&nbsp;--default_params.cidr.no-private_only<br/>**Variable d'environnement** : DEFAULT_PARAMS.CIDR.PRIVATE_ONLY | Les IP privées sont autorisées. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` |
| **<a id="default_params.cidr.allow_reserved" name="default_params.cidr.allow_reserved">default_params.cidr.allow_reserved</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.cidr.allow_reserved<br/>&nbsp;--default_params.cidr.no-allow_reserved<br/>**Variable d'environnement** : DEFAULT_PARAMS.CIDR.ALLOW_RESERVED | Les IP réservées sont autorisés. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` |
| **<a id="default_params.cidr.cidr" name="default_params.cidr.cidr">default_params.cidr.cidr</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.cidr.cidr<br/>&nbsp;--default_params.cidr.no-cidr<br/>**Variable d'environnement** : DEFAULT_PARAMS.CIDR.CIDR | L&#x27;IP doit être au format CIDR. | true | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` |
### Network
> [!NOTE]
>
> **Chemin** : default_params.network\
> `standard`
| Variable | Description | Valeur par défaut | Type | Contrôle des accès |
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------|---------------------|-------------------------------------------------------------------------------------|----------------------|
| **<a id="default_params.network.private_only" name="default_params.network.private_only">default_params.network.private_only</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.network.private_only<br/>&nbsp;--default_params.network.no-private_only<br/>**Variable d'environnement** : DEFAULT_PARAMS.NETWORK.PRIVATE_ONLY | Les réseaux privés sont autorisés. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` |
| **<a id="default_params.network.allow_reserved" name="default_params.network.allow_reserved">default_params.network.allow_reserved</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.network.allow_reserved<br/>&nbsp;--default_params.network.no-allow_reserved<br/>**Variable d'environnement** : DEFAULT_PARAMS.NETWORK.ALLOW_RESERVED | Les réseaux réservés sont autorisés. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` |
| **<a id="default_params.network.cidr" name="default_params.network.cidr">default_params.network.cidr</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.network.cidr<br/>&nbsp;--default_params.network.no-cidr<br/>**Variable d'environnement** : DEFAULT_PARAMS.NETWORK.CIDR | Le réseau doit être au format CIDR. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` |
### Network CIDR
> [!NOTE]
>
> **Chemin** : default_params.network_cidr\
> `standard`
| Variable | Description | Valeur par défaut | Type | Contrôle des accès |
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------|---------------------|-------------------------------------------------------------------------------------|----------------------|
| **<a id="default_params.network_cidr.private_only" name="default_params.network_cidr.private_only">default_params.network_cidr.private_only</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.network_cidr.private_only<br/>&nbsp;--default_params.network_cidr.no-private_only<br/>**Variable d'environnement** : DEFAULT_PARAMS.NETWORK_CIDR.PRIVATE_ONLY | Les réseaux privés sont autorisés. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` |
| **<a id="default_params.network_cidr.allow_reserved" name="default_params.network_cidr.allow_reserved">default_params.network_cidr.allow_reserved</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.network_cidr.allow_reserved<br/>&nbsp;--default_params.network_cidr.no-allow_reserved<br/>**Variable d'environnement** : DEFAULT_PARAMS.NETWORK_CIDR.ALLOW_RESERVED | Les réseaux réservés sont autorisés. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` |
| **<a id="default_params.network_cidr.cidr" name="default_params.network_cidr.cidr">default_params.network_cidr.cidr</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.network_cidr.cidr<br/>&nbsp;--default_params.network_cidr.no-cidr<br/>**Variable d'environnement** : DEFAULT_PARAMS.NETWORK_CIDR.CIDR | Le réseau doit être au format CIDR. | true | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` |
### Netbios
> [!NOTE]
>
> **Chemin** : default_params.netbios\
> `standard`
| Variable | Description | Valeur par défaut | Type | Contrôle des accès | Validateur |
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------|---------------------|-------------------------------------------------------------------------------------|----------------------|-------------------------------------------------------------------------------------------|
| **<a id="default_params.netbios.type" name="default_params.netbios.type">default_params.netbios.type</a>**<br/>**Ligne de commande** : <br/>--default_params.netbios.type<br/>**Variable d'environnement** : DEFAULT_PARAMS.NETBIOS.TYPE | Type de nom de domaine. | netbios | [`choice`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | **Choix** : <br/>&nbsp;domainname<br/>&nbsp;netbios<br/>&nbsp;hostname<br/>&nbsp;null |
| **<a id="default_params.netbios.allow_without_dot" name="default_params.netbios.allow_without_dot">default_params.netbios.allow_without_dot</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.netbios.allow_without_dot<br/>&nbsp;--default_params.netbios.no-allow_without_dot<br/>**Variable d'environnement** : DEFAULT_PARAMS.NETBIOS.ALLOW_WITHOUT_DOT | Le nom de domaine peut être un nom d&#x27;hôte. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.netbios.test_existence" name="default_params.netbios.test_existence">default_params.netbios.test_existence</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.netbios.test_existence<br/>&nbsp;--default_params.netbios.no-test_existence<br/>**Variable d'environnement** : DEFAULT_PARAMS.NETBIOS.TEST_EXISTENCE | Le nom de domaine doit exister. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.netbios.allow_ip" name="default_params.netbios.allow_ip">default_params.netbios.allow_ip</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.netbios.allow_ip<br/>&nbsp;--default_params.netbios.no-allow_ip<br/>**Variable d'environnement** : DEFAULT_PARAMS.NETBIOS.ALLOW_IP | Le nom de domaine peut être une IP. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.netbios.allow_cidr_network" name="default_params.netbios.allow_cidr_network">default_params.netbios.allow_cidr_network</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.netbios.allow_cidr_network<br/>&nbsp;--default_params.netbios.no-allow_cidr_network<br/>**Variable d'environnement** : DEFAULT_PARAMS.NETBIOS.ALLOW_CIDR_NETWORK | Le nom de domaine peut être un réseau au format CIDR. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.netbios.allow_startswith_dot" name="default_params.netbios.allow_startswith_dot">default_params.netbios.allow_startswith_dot</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.netbios.allow_startswith_dot<br/>&nbsp;--default_params.netbios.no-allow_startswith_dot<br/>**Variable d'environnement** : DEFAULT_PARAMS.NETBIOS.ALLOW_STARTSWITH_DOT | Le nom de domaine peut démarré par un point. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
### Domainname
> [!NOTE]
>
> **Chemin** : default_params.domainname\
> `standard`
| Variable | Description | Valeur par défaut | Type | Contrôle des accès | Validateur |
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------|---------------------|-------------------------------------------------------------------------------------|----------------------|-------------------------------------------------------------------------------------------|
| **<a id="default_params.domainname.type" name="default_params.domainname.type">default_params.domainname.type</a>**<br/>**Ligne de commande** : <br/>--default_params.domainname.type<br/>**Variable d'environnement** : DEFAULT_PARAMS.DOMAINNAME.TYPE | Type de nom de domaine. | domainname | [`choice`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | **Choix** : <br/>&nbsp;domainname<br/>&nbsp;netbios<br/>&nbsp;hostname<br/>&nbsp;null |
| **<a id="default_params.domainname.allow_without_dot" name="default_params.domainname.allow_without_dot">default_params.domainname.allow_without_dot</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.domainname.allow_without_dot<br/>&nbsp;--default_params.domainname.no-allow_without_dot<br/>**Variable d'environnement** : DEFAULT_PARAMS.DOMAINNAME.ALLOW_WITHOUT_DOT | Le nom de domaine peut être un nom d&#x27;hôte. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.domainname.test_existence" name="default_params.domainname.test_existence">default_params.domainname.test_existence</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.domainname.test_existence<br/>&nbsp;--default_params.domainname.no-test_existence<br/>**Variable d'environnement** : DEFAULT_PARAMS.DOMAINNAME.TEST_EXISTENCE | Le nom de domaine doit exister. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.domainname.allow_ip" name="default_params.domainname.allow_ip">default_params.domainname.allow_ip</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.domainname.allow_ip<br/>&nbsp;--default_params.domainname.no-allow_ip<br/>**Variable d'environnement** : DEFAULT_PARAMS.DOMAINNAME.ALLOW_IP | Le nom de domaine peut être une IP. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.domainname.allow_cidr_network" name="default_params.domainname.allow_cidr_network">default_params.domainname.allow_cidr_network</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.domainname.allow_cidr_network<br/>&nbsp;--default_params.domainname.no-allow_cidr_network<br/>**Variable d'environnement** : DEFAULT_PARAMS.DOMAINNAME.ALLOW_CIDR_NETWORK | Le nom de domaine peut être un réseau au format CIDR. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.domainname.allow_startswith_dot" name="default_params.domainname.allow_startswith_dot">default_params.domainname.allow_startswith_dot</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.domainname.allow_startswith_dot<br/>&nbsp;--default_params.domainname.no-allow_startswith_dot<br/>**Variable d'environnement** : DEFAULT_PARAMS.DOMAINNAME.ALLOW_STARTSWITH_DOT | Le nom de domaine peut démarré par un point. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
### Hostname
> [!NOTE]
>
> **Chemin** : default_params.hostname\
> `standard`
| Variable | Description | Valeur par défaut | Type | Contrôle des accès | Validateur |
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------|---------------------|-------------------------------------------------------------------------------------|----------------------|-------------------------------------------------------------------------------------------|
| **<a id="default_params.hostname.type" name="default_params.hostname.type">default_params.hostname.type</a>**<br/>**Ligne de commande** : <br/>--default_params.hostname.type<br/>**Variable d'environnement** : DEFAULT_PARAMS.HOSTNAME.TYPE | Type de nom de domaine. | hostname | [`choice`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | **Choix** : <br/>&nbsp;domainname<br/>&nbsp;netbios<br/>&nbsp;hostname<br/>&nbsp;null |
| **<a id="default_params.hostname.allow_without_dot" name="default_params.hostname.allow_without_dot">default_params.hostname.allow_without_dot</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.hostname.allow_without_dot<br/>&nbsp;--default_params.hostname.no-allow_without_dot<br/>**Variable d'environnement** : DEFAULT_PARAMS.HOSTNAME.ALLOW_WITHOUT_DOT | Le nom de domaine peut être un nom d&#x27;hôte. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.hostname.test_existence" name="default_params.hostname.test_existence">default_params.hostname.test_existence</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.hostname.test_existence<br/>&nbsp;--default_params.hostname.no-test_existence<br/>**Variable d'environnement** : DEFAULT_PARAMS.HOSTNAME.TEST_EXISTENCE | Le nom de domaine doit exister. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.hostname.allow_ip" name="default_params.hostname.allow_ip">default_params.hostname.allow_ip</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.hostname.allow_ip<br/>&nbsp;--default_params.hostname.no-allow_ip<br/>**Variable d'environnement** : DEFAULT_PARAMS.HOSTNAME.ALLOW_IP | Le nom de domaine peut être une IP. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.hostname.allow_cidr_network" name="default_params.hostname.allow_cidr_network">default_params.hostname.allow_cidr_network</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.hostname.allow_cidr_network<br/>&nbsp;--default_params.hostname.no-allow_cidr_network<br/>**Variable d'environnement** : DEFAULT_PARAMS.HOSTNAME.ALLOW_CIDR_NETWORK | Le nom de domaine peut être un réseau au format CIDR. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.hostname.allow_startswith_dot" name="default_params.hostname.allow_startswith_dot">default_params.hostname.allow_startswith_dot</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.hostname.allow_startswith_dot<br/>&nbsp;--default_params.hostname.no-allow_startswith_dot<br/>**Variable d'environnement** : DEFAULT_PARAMS.HOSTNAME.ALLOW_STARTSWITH_DOT | Le nom de domaine peut démarré par un point. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
### Web address
> [!NOTE]
>
> **Chemin** : default_params.web_address\
> `standard`
| Variable | Description | Valeur par défaut | Type | Contrôle des accès | Validateur |
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------|---------------------|-------------------------------------------------------------------------------------|----------------------|-------------------------------------------------------------------------------------------|
| **<a id="default_params.web_address.type" name="default_params.web_address.type">default_params.web_address.type</a>**<br/>**Ligne de commande** : <br/>--default_params.web_address.type<br/>**Variable d'environnement** : DEFAULT_PARAMS.WEB_ADDRESS.TYPE | Type de nom de domaine. | domainname | [`choice`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | **Choix** : <br/>&nbsp;domainname<br/>&nbsp;netbios<br/>&nbsp;hostname<br/>&nbsp;null |
| **<a id="default_params.web_address.allow_without_dot" name="default_params.web_address.allow_without_dot">default_params.web_address.allow_without_dot</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.web_address.allow_without_dot<br/>&nbsp;--default_params.web_address.no-allow_without_dot<br/>**Variable d'environnement** : DEFAULT_PARAMS.WEB_ADDRESS.ALLOW_WITHOUT_DOT | Le nom de domaine peut être un nom d&#x27;hôte. | true | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.web_address.test_existence" name="default_params.web_address.test_existence">default_params.web_address.test_existence</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.web_address.test_existence<br/>&nbsp;--default_params.web_address.no-test_existence<br/>**Variable d'environnement** : DEFAULT_PARAMS.WEB_ADDRESS.TEST_EXISTENCE | Le nom de domaine doit exister. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.web_address.allow_ip" name="default_params.web_address.allow_ip">default_params.web_address.allow_ip</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.web_address.allow_ip<br/>&nbsp;--default_params.web_address.no-allow_ip<br/>**Variable d'environnement** : DEFAULT_PARAMS.WEB_ADDRESS.ALLOW_IP | Le nom de domaine peut être une IP. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.web_address.allow_cidr_network" name="default_params.web_address.allow_cidr_network">default_params.web_address.allow_cidr_network</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.web_address.allow_cidr_network<br/>&nbsp;--default_params.web_address.no-allow_cidr_network<br/>**Variable d'environnement** : DEFAULT_PARAMS.WEB_ADDRESS.ALLOW_CIDR_NETWORK | Le nom de domaine peut être un réseau au format CIDR. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.web_address.allow_startswith_dot" name="default_params.web_address.allow_startswith_dot">default_params.web_address.allow_startswith_dot</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.web_address.allow_startswith_dot<br/>&nbsp;--default_params.web_address.no-allow_startswith_dot<br/>**Variable d'environnement** : DEFAULT_PARAMS.WEB_ADDRESS.ALLOW_STARTSWITH_DOT | Le nom de domaine peut démarré par un point. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.web_address.allow_range" name="default_params.web_address.allow_range">default_params.web_address.allow_range</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.web_address.allow_range<br/>&nbsp;--default_params.web_address.no-allow_range<br/>**Variable d'environnement** : DEFAULT_PARAMS.WEB_ADDRESS.ALLOW_RANGE | Peut être une plage de port. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.web_address.allow_protocol" name="default_params.web_address.allow_protocol">default_params.web_address.allow_protocol</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.web_address.allow_protocol<br/>&nbsp;--default_params.web_address.no-allow_protocol<br/>**Variable d'environnement** : DEFAULT_PARAMS.WEB_ADDRESS.ALLOW_PROTOCOL | Peut avoir le protocole. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.web_address.allow_zero" name="default_params.web_address.allow_zero">default_params.web_address.allow_zero</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.web_address.allow_zero<br/>&nbsp;--default_params.web_address.no-allow_zero<br/>**Variable d'environnement** : DEFAULT_PARAMS.WEB_ADDRESS.ALLOW_ZERO | Port 0 est autorisé. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.web_address.allow_wellknown" name="default_params.web_address.allow_wellknown">default_params.web_address.allow_wellknown</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.web_address.allow_wellknown<br/>&nbsp;--default_params.web_address.no-allow_wellknown<br/>**Variable d'environnement** : DEFAULT_PARAMS.WEB_ADDRESS.ALLOW_WELLKNOWN | Les ports connus (1 à 1023) sont autorisés. | true | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.web_address.allow_registred" name="default_params.web_address.allow_registred">default_params.web_address.allow_registred</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.web_address.allow_registred<br/>&nbsp;--default_params.web_address.no-allow_registred<br/>**Variable d'environnement** : DEFAULT_PARAMS.WEB_ADDRESS.ALLOW_REGISTRED | Les ports enregistrés (1024 à 49151) sont autorisés. | true | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.web_address.allow_private" name="default_params.web_address.allow_private">default_params.web_address.allow_private</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.web_address.allow_private<br/>&nbsp;--default_params.web_address.no-allow_private<br/>**Variable d'environnement** : DEFAULT_PARAMS.WEB_ADDRESS.ALLOW_PRIVATE | Les ports privés (supérieur à 49152) sont autorisés. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
### Port
> [!NOTE]
>
> **Chemin** : default_params.port\
> `standard`
| Variable | Description | Valeur par défaut | Type | Contrôle des accès |
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------|---------------------|-------------------------------------------------------------------------------------|----------------------|
| **<a id="default_params.port.allow_range" name="default_params.port.allow_range">default_params.port.allow_range</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.port.allow_range<br/>&nbsp;--default_params.port.no-allow_range<br/>**Variable d'environnement** : DEFAULT_PARAMS.PORT.ALLOW_RANGE | Peut être une plage de port. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` |
| **<a id="default_params.port.allow_protocol" name="default_params.port.allow_protocol">default_params.port.allow_protocol</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.port.allow_protocol<br/>&nbsp;--default_params.port.no-allow_protocol<br/>**Variable d'environnement** : DEFAULT_PARAMS.PORT.ALLOW_PROTOCOL | Peut avoir le protocole. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` |
| **<a id="default_params.port.allow_zero" name="default_params.port.allow_zero">default_params.port.allow_zero</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.port.allow_zero<br/>&nbsp;--default_params.port.no-allow_zero<br/>**Variable d'environnement** : DEFAULT_PARAMS.PORT.ALLOW_ZERO | Port 0 est autorisé. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` |
| **<a id="default_params.port.allow_wellknown" name="default_params.port.allow_wellknown">default_params.port.allow_wellknown</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.port.allow_wellknown<br/>&nbsp;--default_params.port.no-allow_wellknown<br/>**Variable d'environnement** : DEFAULT_PARAMS.PORT.ALLOW_WELLKNOWN | Les ports connus (1 à 1023) sont autorisés. | true | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` |
| **<a id="default_params.port.allow_registred" name="default_params.port.allow_registred">default_params.port.allow_registred</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.port.allow_registred<br/>&nbsp;--default_params.port.no-allow_registred<br/>**Variable d'environnement** : DEFAULT_PARAMS.PORT.ALLOW_REGISTRED | Les ports enregistrés (1024 à 49151) sont autorisés. | true | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` |
| **<a id="default_params.port.allow_private" name="default_params.port.allow_private">default_params.port.allow_private</a>**<br/>**Ligne de commande** : <br/>&nbsp;--default_params.port.allow_private<br/>&nbsp;--default_params.port.no-allow_private<br/>**Variable d'environnement** : DEFAULT_PARAMS.PORT.ALLOW_PRIVATE | Les ports privés (supérieur à 49152) sont autorisés. | true | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` |

288
README.md
View file

@ -1,105 +1,211 @@
![Logo Rougail](logo.png "logo rougail")
# Rougail
## Description
Rougail is a free full-featured configuration manager library written in python3.
The configuration is describe in YAML dictionary files.
Those dictionaries are converted into [Tiramisu](https://framagit.org/tiramisu/tiramisu) objects.
Rougail can be incorporated with other technologies and stacks regardless of whether theyre written in Python or not.
## Simple example
Create a directory:
```bash
# mkdir dict
```
## Dictionary
A dictionary is a variables description file.
Create the file `dict/dictionary.yml`:
```yml
---
version: 1.1
# describe a variable my_first_variable
# and a family with a variable my_second_variable
my_first_variable: my_value
my_family:
my_second_variable: 1
```
gitea: none
include_toc: true
---
[🇬🇧 (EN)](README.md) - [🇫🇷 (FR)](README.fr.md)
## Generate variable
| Variable | Description | Default value | Type | Access control | Validator |
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------|------------------|--------------------------------------------------------------------------------------------------------------------------------------------------|
| **<a id="default_structural_format_version" name="default_structural_format_version">default_structural_format_version</a>**<br/>**Command line**: <br/>-v, --default_structural_format_version<br/>**Environment variable**: DEFAULT_STRUCTURAL_FORMAT_VERSION | Default version of the structural file format.<br/>This value is only used if the version is not set in the structural file. | | [`choice`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | **Choices**: <br/>&nbsp;1.0<br/>&nbsp;1.1<br/>&nbsp;null |
| **<a id="types" name="types">types</a>**<br/>**Command line**: <br/>--types<br/>**Environment variable**: TYPES | File with personalize types.<br/>This file contains personalize types in Rougail format for structure files. | | [`UNIX filename`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `multiple` | `standard` | `unique`<br/>&nbsp;this filename could be a relative path<br/>&nbsp;this file must exist<br/>&nbsp;file type allowed: "directory" and "file". |
| **<a id="functions_files" name="functions_files">functions_files</a>**<br/>**Command line**: <br/>--functions_files<br/>**Environment variable**: FUNCTIONS_FILES | File with functions.<br/>This file contains filters and additional Jinja2 functions usable in structure files. | | [`UNIX filename`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `multiple` | `standard` | `unique`<br/>&nbsp;this filename could be a relative path<br/>&nbsp;this file must exist<br/>&nbsp;file type allowed: "file". |
| **<a id="modes_level" name="modes_level">modes_level</a>**<br/>**Command line**: <br/>--modes_level<br/>**Environment variable**: MODES_LEVEL | All modes level available. | | [`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `multiple` | `standard` | `unique` |
| **<a id="default_family_mode" name="default_family_mode">default_family_mode</a>**<br/>**Environment variable**: DEFAULT_FAMILY_MODE | Default mode for a family. | the first one defined in "[All modes level available](#modes_level)" | [`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | This mode must be available in "[All modes level available](#modes_level)". |
| **<a id="default_variable_mode" name="default_variable_mode">default_variable_mode</a>**<br/>**Environment variable**: DEFAULT_VARIABLE_MODE | Default mode for a variable. | if the variable "[All modes level available](#modes_level)" is defined, the default value is the second available element, otherwise, the first | [`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | This mode must be available in "[All modes level available](#modes_level)". |
| **<a id="base_option_name" name="base_option_name">base_option_name</a>**<br/>**Environment variable**: BASE_OPTION_NAME | Option name for the base option. | baseoption | [`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="export_with_import" name="export_with_import">export_with_import</a>**<br/>**Environment variable**: EXPORT_WITH_IMPORT | In cache file, do not importation of Tiramisu and other dependencies. | true | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="tiramisu_cache" name="tiramisu_cache">tiramisu_cache</a>**<br/>**Command line**: <br/>-t, --tiramisu_cache<br/>**Environment variable**: TIRAMISU_CACHE | Store Tiramisu cache filename.<br/>This file contains the Tiramisu instructions used internally to load the variables.<br/>This file can be used for debugging. | | [`UNIX filename`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | •&nbsp;this filename could be a relative path<br/>&nbsp;file type allowed: "file". |
| **<a id="internal_functions" name="internal_functions">internal_functions</a>**<br/>**Environment variable**: INTERNAL_FUNCTIONS | Name of internal functions that we can use as a function. | | [`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `multiple` | `standard` | |
| **<a id="extra_annotators" name="extra_annotators">extra_annotators</a>**<br/>**Environment variable**: EXTRA_ANNOTATORS | Name of extra annotators. | | [`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `multiple` | `standard` | |
| **<a id="suffix" name="suffix">suffix</a>**<br/>**Environment variable**: SUFFIX | Suffix add to generated options name. | | [`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="force_optional" name="force_optional">force_optional</a>**<br/>**Command line**: <br/>&nbsp;--force_optional<br/>&nbsp;--no-force_optional<br/>**Environment variable**: FORCE_OPTIONAL | Every variables in calculation are optionals. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `mandatory` | `standard` | |
| **<a id="load_unexist_redefine" name="load_unexist_redefine">load_unexist_redefine</a>**<br/>**Environment variable**: LOAD_UNEXIST_REDEFINE | Loads redefine variables even if there don&#x27;t already exists. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
### With commandline:
## The secret manager
```bash
# rougail -m dict
Variables:
┣━━ 📓 my_first_variable: my_value
┗━━ 📂 my_family
┗━━ 📓 my_second_variable: 1
> [!NOTE]
>
> **Path**: secret_manager\
> `standard`
```
| Variable | Description | Default value | Type | Access control |
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------|------------------------------------------------------------------------------------------------|------------------|
| **<a id="secret_manager.pattern" name="secret_manager.pattern">secret_manager.pattern</a>**<br/>**Command line**: <br/>--secret_manager.pattern<br/>**Environment variable**: SECRET_MANAGER.PATTERN | The secret pattern to constructing the name of the item searched for in the secret manager.<br/>The pattern is in Jinja2 format. | {{ project }} - {{ environment }} - {{ service }} - {{ user }} | [`string`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `mandatory` | `standard` |
### With default value:
## Load and exporter steps
Here is a python3 example file:
> [!NOTE]
>
> **Path**: step\
> `standard`
```python
from rougail import Rougail, RougailConfig
from pprint import pprint
| Variable | Description | Default value | Type | Access control | Validator |
|------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------|------------------|------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **<a id="step.structural" name="step.structural">step.structural</a>**<br/>**Environment variable**: STEP.STRUCTURAL | Select for structural. | •&nbsp;directory | [`choice`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `multiple` | `standard` | **Choices**: <br/>&nbsp;directory<br/>&nbsp;string<br/>&nbsp;commandline<br/>&nbsp;risotto |
| **<a id="step.user_data" name="step.user_data">step.user_data</a>**<br/>**Command line**: <br/>-u, --step.user_data<br/>**Environment variable**: STEP.USER_DATA | Select for user datas. | | [`choice`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `multiple` | `standard` *`disabled`*<br/>**Disabled**: outputs "doc" did not allow user data | `unique`<br/>**Choices**: <br/>&nbsp;yaml<br/>&nbsp;environment<br/>&nbsp;commandline<br/>&nbsp;ansible<br/>&nbsp;questionary<br/>&nbsp;risotto<br/>&nbsp;bitwarden |
| **<a id="step.output" name="step.output">step.output</a>**<br/>**Command line**: <br/>-o, --step.output<br/>**Environment variable**: STEP.OUTPUT | Select for output. | display | [`choice`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `mandatory` | `standard` | **Choices**: <br/>&nbsp;display<br/>&nbsp;json<br/>&nbsp;doc<br/>&nbsp;table<br/>&nbsp;ansible |
RougailConfig['dictionaries_dir'] = ['dict']
rougail = Rougail()
config = rougail.run()
pprint(config.value.get(), sort_dicts=False)
```
| Variable | Description | Default value | Type | Access control |
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------|-----------------|-------------------------------------------------------------------------------------------------|------------------|
| **<a id="define_default_params" name="define_default_params">define_default_params</a>**<br/>**Command line**: <br/>&nbsp;--define_default_params<br/>&nbsp;--no-define_default_params<br/>**Environment variable**: DEFINE_DEFAULT_PARAMS | Override default parameters for option type. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `mandatory` | `standard` |
The result is:
## Default parameters for option type
```json
{<TiramisuOption path="rougail">: {<TiramisuOption path="rougail.my_first_variable">: 'my_value',
<TiramisuOption path="rougail.my_family">: {<TiramisuOption path="rougail.my_family.my_second_variable">: 1}}}
```
> [!NOTE]
>
> **Path**: default_params\
> `standard` *`disabled`*\
> **Disabled**: when the variable "[Override default parameters for option type](#define_default_params)" has the value "false"
### With modified value
### UNIX filename
> [!NOTE]
>
> **Path**: default_params.unix_filename\
> `standard`
| Variable | Description | Default value | Type | Access control | Validator |
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------|----------------------------------|-----------------------------------------------------------------------------------------------|------------------|-----------------------------------------------------------------|
| **<a id="default_params.unix_filename.allow_relative" name="default_params.unix_filename.allow_relative">default_params.unix_filename.allow_relative</a>**<br/>**Command line**: <br/>&nbsp;--default_params.unix_filename.allow_relative<br/>&nbsp;--default_params.unix_filename.no-allow_relative<br/>**Environment variable**: DEFAULT_PARAMS.UNIX_FILENAME.ALLOW_RELATIVE | This filename could be a relative path. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.unix_filename.test_existence" name="default_params.unix_filename.test_existence">default_params.unix_filename.test_existence</a>**<br/>**Command line**: <br/>&nbsp;--default_params.unix_filename.test_existence<br/>&nbsp;--default_params.unix_filename.no-test_existence<br/>**Environment variable**: DEFAULT_PARAMS.UNIX_FILENAME.TEST_EXISTENCE | This file must exist. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.unix_filename.types" name="default_params.unix_filename.types">default_params.unix_filename.types</a>**<br/>**Command line**: <br/>--default_params.unix_filename.types<br/>**Environment variable**: DEFAULT_PARAMS.UNIX_FILENAME.TYPES | File type allowed. | •&nbsp;file<br/>&nbsp;directory | [`choice`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `multiple` | `standard` | `unique`<br/>**Choices**: <br/>&nbsp;file<br/>&nbsp;directory |
### IP
> [!NOTE]
>
> **Path**: default_params.ip\
> `standard`
| Variable | Description | Default value | Type | Access control |
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------|-----------------|-------------------------------------------------------------------------------------|------------------|
| **<a id="default_params.ip.private_only" name="default_params.ip.private_only">default_params.ip.private_only</a>**<br/>**Command line**: <br/>&nbsp;--default_params.ip.private_only<br/>&nbsp;--default_params.ip.no-private_only<br/>**Environment variable**: DEFAULT_PARAMS.IP.PRIVATE_ONLY | Private IP are allowed. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` |
| **<a id="default_params.ip.allow_reserved" name="default_params.ip.allow_reserved">default_params.ip.allow_reserved</a>**<br/>**Command line**: <br/>&nbsp;--default_params.ip.allow_reserved<br/>&nbsp;--default_params.ip.no-allow_reserved<br/>**Environment variable**: DEFAULT_PARAMS.IP.ALLOW_RESERVED | Reserved IP are allowed. | true | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` |
| **<a id="default_params.ip.cidr" name="default_params.ip.cidr">default_params.ip.cidr</a>**<br/>**Command line**: <br/>&nbsp;--default_params.ip.cidr<br/>&nbsp;--default_params.ip.no-cidr<br/>**Environment variable**: DEFAULT_PARAMS.IP.CIDR | IP must be in CIDR format. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` |
### CIDR
> [!NOTE]
>
> **Path**: default_params.cidr\
> `standard`
| Variable | Description | Default value | Type | Access control |
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------|-----------------|-------------------------------------------------------------------------------------|------------------|
| **<a id="default_params.cidr.private_only" name="default_params.cidr.private_only">default_params.cidr.private_only</a>**<br/>**Command line**: <br/>&nbsp;--default_params.cidr.private_only<br/>&nbsp;--default_params.cidr.no-private_only<br/>**Environment variable**: DEFAULT_PARAMS.CIDR.PRIVATE_ONLY | Private IP are allowed. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` |
| **<a id="default_params.cidr.allow_reserved" name="default_params.cidr.allow_reserved">default_params.cidr.allow_reserved</a>**<br/>**Command line**: <br/>&nbsp;--default_params.cidr.allow_reserved<br/>&nbsp;--default_params.cidr.no-allow_reserved<br/>**Environment variable**: DEFAULT_PARAMS.CIDR.ALLOW_RESERVED | Reserved IP are allowed. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` |
| **<a id="default_params.cidr.cidr" name="default_params.cidr.cidr">default_params.cidr.cidr</a>**<br/>**Command line**: <br/>&nbsp;--default_params.cidr.cidr<br/>&nbsp;--default_params.cidr.no-cidr<br/>**Environment variable**: DEFAULT_PARAMS.CIDR.CIDR | IP must be in CIDR format. | true | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` |
### Network
> [!NOTE]
>
> **Path**: default_params.network\
> `standard`
| Variable | Description | Default value | Type | Access control |
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------|-----------------|-------------------------------------------------------------------------------------|------------------|
| **<a id="default_params.network.private_only" name="default_params.network.private_only">default_params.network.private_only</a>**<br/>**Command line**: <br/>&nbsp;--default_params.network.private_only<br/>&nbsp;--default_params.network.no-private_only<br/>**Environment variable**: DEFAULT_PARAMS.NETWORK.PRIVATE_ONLY | Private network are allowed. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` |
| **<a id="default_params.network.allow_reserved" name="default_params.network.allow_reserved">default_params.network.allow_reserved</a>**<br/>**Command line**: <br/>&nbsp;--default_params.network.allow_reserved<br/>&nbsp;--default_params.network.no-allow_reserved<br/>**Environment variable**: DEFAULT_PARAMS.NETWORK.ALLOW_RESERVED | Reserved network are allowed. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` |
| **<a id="default_params.network.cidr" name="default_params.network.cidr">default_params.network.cidr</a>**<br/>**Command line**: <br/>&nbsp;--default_params.network.cidr<br/>&nbsp;--default_params.network.no-cidr<br/>**Environment variable**: DEFAULT_PARAMS.NETWORK.CIDR | Network must be in CIDR format. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` |
### Network CIDR
> [!NOTE]
>
> **Path**: default_params.network_cidr\
> `standard`
| Variable | Description | Default value | Type | Access control |
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------|-----------------|-------------------------------------------------------------------------------------|------------------|
| **<a id="default_params.network_cidr.private_only" name="default_params.network_cidr.private_only">default_params.network_cidr.private_only</a>**<br/>**Command line**: <br/>&nbsp;--default_params.network_cidr.private_only<br/>&nbsp;--default_params.network_cidr.no-private_only<br/>**Environment variable**: DEFAULT_PARAMS.NETWORK_CIDR.PRIVATE_ONLY | Private network are allowed. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` |
| **<a id="default_params.network_cidr.allow_reserved" name="default_params.network_cidr.allow_reserved">default_params.network_cidr.allow_reserved</a>**<br/>**Command line**: <br/>&nbsp;--default_params.network_cidr.allow_reserved<br/>&nbsp;--default_params.network_cidr.no-allow_reserved<br/>**Environment variable**: DEFAULT_PARAMS.NETWORK_CIDR.ALLOW_RESERVED | Reserved network are allowed. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` |
| **<a id="default_params.network_cidr.cidr" name="default_params.network_cidr.cidr">default_params.network_cidr.cidr</a>**<br/>**Command line**: <br/>&nbsp;--default_params.network_cidr.cidr<br/>&nbsp;--default_params.network_cidr.no-cidr<br/>**Environment variable**: DEFAULT_PARAMS.NETWORK_CIDR.CIDR | Network must be in CIDR format. | true | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` |
### Netbios
> [!NOTE]
>
> **Path**: default_params.netbios\
> `standard`
| Variable | Description | Default value | Type | Access control | Validator |
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------|-----------------|-------------------------------------------------------------------------------------|------------------|--------------------------------------------------------------------------------------------|
| **<a id="default_params.netbios.type" name="default_params.netbios.type">default_params.netbios.type</a>**<br/>**Command line**: <br/>--default_params.netbios.type<br/>**Environment variable**: DEFAULT_PARAMS.NETBIOS.TYPE | Type of domainname. | netbios | [`choice`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | **Choices**: <br/>&nbsp;domainname<br/>&nbsp;netbios<br/>&nbsp;hostname<br/>&nbsp;null |
| **<a id="default_params.netbios.allow_without_dot" name="default_params.netbios.allow_without_dot">default_params.netbios.allow_without_dot</a>**<br/>**Command line**: <br/>&nbsp;--default_params.netbios.allow_without_dot<br/>&nbsp;--default_params.netbios.no-allow_without_dot<br/>**Environment variable**: DEFAULT_PARAMS.NETBIOS.ALLOW_WITHOUT_DOT | The domain name can be a hostname. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.netbios.test_existence" name="default_params.netbios.test_existence">default_params.netbios.test_existence</a>**<br/>**Command line**: <br/>&nbsp;--default_params.netbios.test_existence<br/>&nbsp;--default_params.netbios.no-test_existence<br/>**Environment variable**: DEFAULT_PARAMS.NETBIOS.TEST_EXISTENCE | The domain name must exist. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.netbios.allow_ip" name="default_params.netbios.allow_ip">default_params.netbios.allow_ip</a>**<br/>**Command line**: <br/>&nbsp;--default_params.netbios.allow_ip<br/>&nbsp;--default_params.netbios.no-allow_ip<br/>**Environment variable**: DEFAULT_PARAMS.NETBIOS.ALLOW_IP | The domain name can be an IP. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.netbios.allow_cidr_network" name="default_params.netbios.allow_cidr_network">default_params.netbios.allow_cidr_network</a>**<br/>**Command line**: <br/>&nbsp;--default_params.netbios.allow_cidr_network<br/>&nbsp;--default_params.netbios.no-allow_cidr_network<br/>**Environment variable**: DEFAULT_PARAMS.NETBIOS.ALLOW_CIDR_NETWORK | The domain name can be network in CIDR format. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.netbios.allow_startswith_dot" name="default_params.netbios.allow_startswith_dot">default_params.netbios.allow_startswith_dot</a>**<br/>**Command line**: <br/>&nbsp;--default_params.netbios.allow_startswith_dot<br/>&nbsp;--default_params.netbios.no-allow_startswith_dot<br/>**Environment variable**: DEFAULT_PARAMS.NETBIOS.ALLOW_STARTSWITH_DOT | The domain name can starts by a dot. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
### Domainname
> [!NOTE]
>
> **Path**: default_params.domainname\
> `standard`
| Variable | Description | Default value | Type | Access control | Validator |
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------|-----------------|-------------------------------------------------------------------------------------|------------------|--------------------------------------------------------------------------------------------|
| **<a id="default_params.domainname.type" name="default_params.domainname.type">default_params.domainname.type</a>**<br/>**Command line**: <br/>--default_params.domainname.type<br/>**Environment variable**: DEFAULT_PARAMS.DOMAINNAME.TYPE | Type of domainname. | domainname | [`choice`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | **Choices**: <br/>&nbsp;domainname<br/>&nbsp;netbios<br/>&nbsp;hostname<br/>&nbsp;null |
| **<a id="default_params.domainname.allow_without_dot" name="default_params.domainname.allow_without_dot">default_params.domainname.allow_without_dot</a>**<br/>**Command line**: <br/>&nbsp;--default_params.domainname.allow_without_dot<br/>&nbsp;--default_params.domainname.no-allow_without_dot<br/>**Environment variable**: DEFAULT_PARAMS.DOMAINNAME.ALLOW_WITHOUT_DOT | The domain name can be a hostname. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.domainname.test_existence" name="default_params.domainname.test_existence">default_params.domainname.test_existence</a>**<br/>**Command line**: <br/>&nbsp;--default_params.domainname.test_existence<br/>&nbsp;--default_params.domainname.no-test_existence<br/>**Environment variable**: DEFAULT_PARAMS.DOMAINNAME.TEST_EXISTENCE | The domain name must exist. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.domainname.allow_ip" name="default_params.domainname.allow_ip">default_params.domainname.allow_ip</a>**<br/>**Command line**: <br/>&nbsp;--default_params.domainname.allow_ip<br/>&nbsp;--default_params.domainname.no-allow_ip<br/>**Environment variable**: DEFAULT_PARAMS.DOMAINNAME.ALLOW_IP | The domain name can be an IP. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.domainname.allow_cidr_network" name="default_params.domainname.allow_cidr_network">default_params.domainname.allow_cidr_network</a>**<br/>**Command line**: <br/>&nbsp;--default_params.domainname.allow_cidr_network<br/>&nbsp;--default_params.domainname.no-allow_cidr_network<br/>**Environment variable**: DEFAULT_PARAMS.DOMAINNAME.ALLOW_CIDR_NETWORK | The domain name can be network in CIDR format. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.domainname.allow_startswith_dot" name="default_params.domainname.allow_startswith_dot">default_params.domainname.allow_startswith_dot</a>**<br/>**Command line**: <br/>&nbsp;--default_params.domainname.allow_startswith_dot<br/>&nbsp;--default_params.domainname.no-allow_startswith_dot<br/>**Environment variable**: DEFAULT_PARAMS.DOMAINNAME.ALLOW_STARTSWITH_DOT | The domain name can starts by a dot. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
### Hostname
> [!NOTE]
>
> **Path**: default_params.hostname\
> `standard`
| Variable | Description | Default value | Type | Access control | Validator |
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------|-----------------|-------------------------------------------------------------------------------------|------------------|--------------------------------------------------------------------------------------------|
| **<a id="default_params.hostname.type" name="default_params.hostname.type">default_params.hostname.type</a>**<br/>**Command line**: <br/>--default_params.hostname.type<br/>**Environment variable**: DEFAULT_PARAMS.HOSTNAME.TYPE | Type of domainname. | hostname | [`choice`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | **Choices**: <br/>&nbsp;domainname<br/>&nbsp;netbios<br/>&nbsp;hostname<br/>&nbsp;null |
| **<a id="default_params.hostname.allow_without_dot" name="default_params.hostname.allow_without_dot">default_params.hostname.allow_without_dot</a>**<br/>**Command line**: <br/>&nbsp;--default_params.hostname.allow_without_dot<br/>&nbsp;--default_params.hostname.no-allow_without_dot<br/>**Environment variable**: DEFAULT_PARAMS.HOSTNAME.ALLOW_WITHOUT_DOT | The domain name can be a hostname. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.hostname.test_existence" name="default_params.hostname.test_existence">default_params.hostname.test_existence</a>**<br/>**Command line**: <br/>&nbsp;--default_params.hostname.test_existence<br/>&nbsp;--default_params.hostname.no-test_existence<br/>**Environment variable**: DEFAULT_PARAMS.HOSTNAME.TEST_EXISTENCE | The domain name must exist. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.hostname.allow_ip" name="default_params.hostname.allow_ip">default_params.hostname.allow_ip</a>**<br/>**Command line**: <br/>&nbsp;--default_params.hostname.allow_ip<br/>&nbsp;--default_params.hostname.no-allow_ip<br/>**Environment variable**: DEFAULT_PARAMS.HOSTNAME.ALLOW_IP | The domain name can be an IP. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.hostname.allow_cidr_network" name="default_params.hostname.allow_cidr_network">default_params.hostname.allow_cidr_network</a>**<br/>**Command line**: <br/>&nbsp;--default_params.hostname.allow_cidr_network<br/>&nbsp;--default_params.hostname.no-allow_cidr_network<br/>**Environment variable**: DEFAULT_PARAMS.HOSTNAME.ALLOW_CIDR_NETWORK | The domain name can be network in CIDR format. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.hostname.allow_startswith_dot" name="default_params.hostname.allow_startswith_dot">default_params.hostname.allow_startswith_dot</a>**<br/>**Command line**: <br/>&nbsp;--default_params.hostname.allow_startswith_dot<br/>&nbsp;--default_params.hostname.no-allow_startswith_dot<br/>**Environment variable**: DEFAULT_PARAMS.HOSTNAME.ALLOW_STARTSWITH_DOT | The domain name can starts by a dot. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
### Web address
> [!NOTE]
>
> **Path**: default_params.web_address\
> `standard`
| Variable | Description | Default value | Type | Access control | Validator |
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------|-----------------|-------------------------------------------------------------------------------------|------------------|--------------------------------------------------------------------------------------------|
| **<a id="default_params.web_address.type" name="default_params.web_address.type">default_params.web_address.type</a>**<br/>**Command line**: <br/>--default_params.web_address.type<br/>**Environment variable**: DEFAULT_PARAMS.WEB_ADDRESS.TYPE | Type of domainname. | domainname | [`choice`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | **Choices**: <br/>&nbsp;domainname<br/>&nbsp;netbios<br/>&nbsp;hostname<br/>&nbsp;null |
| **<a id="default_params.web_address.allow_without_dot" name="default_params.web_address.allow_without_dot">default_params.web_address.allow_without_dot</a>**<br/>**Command line**: <br/>&nbsp;--default_params.web_address.allow_without_dot<br/>&nbsp;--default_params.web_address.no-allow_without_dot<br/>**Environment variable**: DEFAULT_PARAMS.WEB_ADDRESS.ALLOW_WITHOUT_DOT | The domain name can be a hostname. | true | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.web_address.test_existence" name="default_params.web_address.test_existence">default_params.web_address.test_existence</a>**<br/>**Command line**: <br/>&nbsp;--default_params.web_address.test_existence<br/>&nbsp;--default_params.web_address.no-test_existence<br/>**Environment variable**: DEFAULT_PARAMS.WEB_ADDRESS.TEST_EXISTENCE | The domain name must exist. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.web_address.allow_ip" name="default_params.web_address.allow_ip">default_params.web_address.allow_ip</a>**<br/>**Command line**: <br/>&nbsp;--default_params.web_address.allow_ip<br/>&nbsp;--default_params.web_address.no-allow_ip<br/>**Environment variable**: DEFAULT_PARAMS.WEB_ADDRESS.ALLOW_IP | The domain name can be an IP. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.web_address.allow_cidr_network" name="default_params.web_address.allow_cidr_network">default_params.web_address.allow_cidr_network</a>**<br/>**Command line**: <br/>&nbsp;--default_params.web_address.allow_cidr_network<br/>&nbsp;--default_params.web_address.no-allow_cidr_network<br/>**Environment variable**: DEFAULT_PARAMS.WEB_ADDRESS.ALLOW_CIDR_NETWORK | The domain name can be network in CIDR format. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.web_address.allow_startswith_dot" name="default_params.web_address.allow_startswith_dot">default_params.web_address.allow_startswith_dot</a>**<br/>**Command line**: <br/>&nbsp;--default_params.web_address.allow_startswith_dot<br/>&nbsp;--default_params.web_address.no-allow_startswith_dot<br/>**Environment variable**: DEFAULT_PARAMS.WEB_ADDRESS.ALLOW_STARTSWITH_DOT | The domain name can starts by a dot. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.web_address.allow_range" name="default_params.web_address.allow_range">default_params.web_address.allow_range</a>**<br/>**Command line**: <br/>&nbsp;--default_params.web_address.allow_range<br/>&nbsp;--default_params.web_address.no-allow_range<br/>**Environment variable**: DEFAULT_PARAMS.WEB_ADDRESS.ALLOW_RANGE | Can be range of port. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.web_address.allow_protocol" name="default_params.web_address.allow_protocol">default_params.web_address.allow_protocol</a>**<br/>**Command line**: <br/>&nbsp;--default_params.web_address.allow_protocol<br/>&nbsp;--default_params.web_address.no-allow_protocol<br/>**Environment variable**: DEFAULT_PARAMS.WEB_ADDRESS.ALLOW_PROTOCOL | Can have the protocol. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.web_address.allow_zero" name="default_params.web_address.allow_zero">default_params.web_address.allow_zero</a>**<br/>**Command line**: <br/>&nbsp;--default_params.web_address.allow_zero<br/>&nbsp;--default_params.web_address.no-allow_zero<br/>**Environment variable**: DEFAULT_PARAMS.WEB_ADDRESS.ALLOW_ZERO | Port 0 is allowed. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.web_address.allow_wellknown" name="default_params.web_address.allow_wellknown">default_params.web_address.allow_wellknown</a>**<br/>**Command line**: <br/>&nbsp;--default_params.web_address.allow_wellknown<br/>&nbsp;--default_params.web_address.no-allow_wellknown<br/>**Environment variable**: DEFAULT_PARAMS.WEB_ADDRESS.ALLOW_WELLKNOWN | Well-known ports (1 to 1023) are allowed. | true | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.web_address.allow_registred" name="default_params.web_address.allow_registred">default_params.web_address.allow_registred</a>**<br/>**Command line**: <br/>&nbsp;--default_params.web_address.allow_registred<br/>&nbsp;--default_params.web_address.no-allow_registred<br/>**Environment variable**: DEFAULT_PARAMS.WEB_ADDRESS.ALLOW_REGISTRED | Registred ports (1024 to 49151) are allowed. | true | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
| **<a id="default_params.web_address.allow_private" name="default_params.web_address.allow_private">default_params.web_address.allow_private</a>**<br/>**Command line**: <br/>&nbsp;--default_params.web_address.allow_private<br/>&nbsp;--default_params.web_address.no-allow_private<br/>**Environment variable**: DEFAULT_PARAMS.WEB_ADDRESS.ALLOW_PRIVATE | Private ports (greater than 49152) are allowed. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` | |
### Port
> [!NOTE]
>
> **Path**: default_params.port\
> `standard`
| Variable | Description | Default value | Type | Access control |
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------|-----------------|-------------------------------------------------------------------------------------|------------------|
| **<a id="default_params.port.allow_range" name="default_params.port.allow_range">default_params.port.allow_range</a>**<br/>**Command line**: <br/>&nbsp;--default_params.port.allow_range<br/>&nbsp;--default_params.port.no-allow_range<br/>**Environment variable**: DEFAULT_PARAMS.PORT.ALLOW_RANGE | Can be range of port. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` |
| **<a id="default_params.port.allow_protocol" name="default_params.port.allow_protocol">default_params.port.allow_protocol</a>**<br/>**Command line**: <br/>&nbsp;--default_params.port.allow_protocol<br/>&nbsp;--default_params.port.no-allow_protocol<br/>**Environment variable**: DEFAULT_PARAMS.PORT.ALLOW_PROTOCOL | Can have the protocol. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` |
| **<a id="default_params.port.allow_zero" name="default_params.port.allow_zero">default_params.port.allow_zero</a>**<br/>**Command line**: <br/>&nbsp;--default_params.port.allow_zero<br/>&nbsp;--default_params.port.no-allow_zero<br/>**Environment variable**: DEFAULT_PARAMS.PORT.ALLOW_ZERO | Port 0 is allowed. | false | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` |
| **<a id="default_params.port.allow_wellknown" name="default_params.port.allow_wellknown">default_params.port.allow_wellknown</a>**<br/>**Command line**: <br/>&nbsp;--default_params.port.allow_wellknown<br/>&nbsp;--default_params.port.no-allow_wellknown<br/>**Environment variable**: DEFAULT_PARAMS.PORT.ALLOW_WELLKNOWN | Well-known ports (1 to 1023) are allowed. | true | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` |
| **<a id="default_params.port.allow_registred" name="default_params.port.allow_registred">default_params.port.allow_registred</a>**<br/>**Command line**: <br/>&nbsp;--default_params.port.allow_registred<br/>&nbsp;--default_params.port.no-allow_registred<br/>**Environment variable**: DEFAULT_PARAMS.PORT.ALLOW_REGISTRED | Registred ports (1024 to 49151) are allowed. | true | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` |
| **<a id="default_params.port.allow_private" name="default_params.port.allow_private">default_params.port.allow_private</a>**<br/>**Command line**: <br/>&nbsp;--default_params.port.allow_private<br/>&nbsp;--default_params.port.no-allow_private<br/>**Environment variable**: DEFAULT_PARAMS.PORT.ALLOW_PRIVATE | Private ports (greater than 49152) are allowed. | true | [`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | `standard` |
Use [Tiramisu](https://framagit.org/tiramisu/tiramisu) API to change values:
```python
from rougail import Rougail, RougailConfig
from pprint import pprint
RougailConfig['dictionaries_dir'] = ['dict']
rougail = Rougail()
config = rougail.get_config()
config.option('rougail.my_first_variable').value.set('modified_value')
config.option('rougail.my_family.my_second_variable').value.set(2)
pprint(config.value.get(), sort_dicts=False)
```
The destination file is generated with new values:
```json
{<TiramisuOption path="rougail">: {<TiramisuOption path="rougail.my_first_variable">: 'modified_value',
<TiramisuOption path="rougail.my_family">: {<TiramisuOption path="rougail.my_family.my_second_variable">: 2}}}
```
# Link
* [Documentation](https://rougail.readthedocs.io/en/latest/)
* [Licence ](LICENSE)
# Related projects
* [Tiramisu](https://forge.cloud.silique.fr/gnunux/tiramisu)
* [Risotto](https://cloud.silique.fr/gitea/risotto/risotto)

File diff suppressed because it is too large Load diff

View file

@ -5,7 +5,7 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2024-11-04 12:04+0100\n"
"POT-Creation-Date: 2026-01-21 08:42+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"
@ -15,75 +15,437 @@ msgstr ""
"Generated-By: pygettext.py 1.5\n"
#: src/rougail/annotator/family.py:139
#: src/rougail/annotator/family.py:152
msgid "default variable mode \"{0}\" is not a valid mode, valid modes are {1}"
msgstr ""
#: src/rougail/annotator/family.py:145
#: src/rougail/annotator/family.py:158
msgid "default family mode \"{0}\" is not a valid mode, valid modes are {1}"
msgstr ""
#: src/rougail/annotator/family.py:177
#: src/rougail/annotator/family.py:190
msgid "mode \"{0}\" for \"{1}\" is not a valid mode, valid modes are {2}"
msgstr ""
#: src/rougail/annotator/family.py:181
#: src/rougail/annotator/family.py:194
msgid "mode \"{0}\" for \"{1}\" is not a valid mode, no modes are available"
msgstr ""
#: src/rougail/annotator/family.py:245
#: src/rougail/annotator/family.py:258
msgid "the variable \"{0}\" is mandatory so in \"{1}\" mode but family has the higher family mode \"{2}\""
msgstr ""
#: src/rougail/annotator/family.py:283
#: src/rougail/annotator/family.py:296
msgid "the follower \"{0}\" is in \"{1}\" mode but leader have the higher mode \"{2}\""
msgstr ""
#: src/rougail/annotator/family.py:316
#: src/rougail/annotator/family.py:329
msgid "the family \"{0}\" is in \"{1}\" mode but variables and families inside have the higher modes \"{2}\""
msgstr ""
#: src/rougail/annotator/family.py:334
#: src/rougail/annotator/family.py:347
msgid "the variable \"{0}\" is in \"{1}\" mode but family has the higher family mode \"{2}\""
msgstr ""
#: src/rougail/annotator/value.py:77
msgid "the follower \"{0}\" without multi attribute can only have one value"
#: src/rougail/annotator/property.py:181
msgid "invalid tag name \"{0}\" should only contains lowercase ascii character, number or _"
msgstr ""
#: src/rougail/annotator/value.py:93
#: src/rougail/annotator/property.py:186
msgid "invalid tag name \"{0}\" should not be a name of an existing mode"
msgstr ""
#: src/rougail/annotator/property.py:191
msgid "invalid tag name \"{0}\" should not be the name of an available properties"
msgstr ""
#: src/rougail/annotator/value.py:78
msgid "the follower \"{0}\" is not multi, so cannot have a list has default value"
msgstr ""
#: src/rougail/annotator/value.py:94
msgid "the variable \"{0}\" is multi but has a non list default value"
msgstr ""
#: src/rougail/annotator/variable.py:189
#: src/rougail/annotator/value.py:118
msgid "the variable \"{0}\" is a \"choice\" variable but don't have any choice"
msgstr ""
#: src/rougail/annotator/value.py:137
msgid "the variable \"{0}\" is a \"regexp\" variable but don't have any regexp"
msgstr ""
#: src/rougail/annotator/variable.py:93
msgid "only \"unix_user\" or \"secret\" variable type can have \"secret_manager\" attribute, but \"{0}\" has type \"{1}\""
msgstr ""
#: src/rougail/annotator/variable.py:100
msgid "the variable \"{0}\" has attribute \"secret_manager\" but is a multi variable"
msgstr ""
#: src/rougail/annotator/variable.py:105
msgid "the variable \"{0}\" has attribute \"secret_manager\" so must not have default value"
msgstr ""
#: src/rougail/annotator/variable.py:159
msgid "{0} values needed, but there are {{{{ var | length }}}}"
msgstr ""
#: src/rougail/annotator/variable.py:160
msgid "needs exactly {0} values"
msgstr ""
#: src/rougail/annotator/variable.py:162
msgid "a maximum of {0} values are needed, but there are {{{{ var | length }}}}"
msgstr ""
#: src/rougail/annotator/variable.py:163
msgid "needs a maximum of {0} values"
msgstr ""
#: src/rougail/annotator/variable.py:167
msgid "a minimum of {0} values are needed, but there are {{{{ var | length }}}}"
msgstr ""
#: src/rougail/annotator/variable.py:168
msgid "needs a minimum of {0} values"
msgstr ""
#: src/rougail/annotator/variable.py:246
msgid "the \"{0}\" default value is a calculation with itself"
msgstr ""
#: src/rougail/annotator/variable.py:306
msgid "the variable \"{0}\" has regexp attribut but has not the \"regexp\" type"
msgstr ""
#: src/rougail/annotator/variable.py:232
#: src/rougail/annotator/variable.py:349
msgid "the variable \"{0}\" has choices attribut but has not the \"choice\" type"
msgstr ""
#: src/rougail/annotator/variable.py:260
#: src/rougail/annotator/variable.py:377
msgid "the variable \"{0}\" has an unvalid default value \"{1}\" should be in {2}"
msgstr ""
#: src/rougail/convert.py:281
msgid "A variable or a family located in the \"{0}\" namespace shall not be used in the \"{1}\" namespace"
#: src/rougail/config/__init__.py:272
msgid "Default version of the structural file format"
msgstr ""
#: src/rougail/convert.py:475
#: src/rougail/config/__init__.py:273
msgid "This value is only used if the version is not set in the structural file"
msgstr ""
#: src/rougail/config/__init__.py:281
msgid "File with personalize types"
msgstr ""
#: src/rougail/config/__init__.py:282
msgid "This file contains personalize types in Rougail format for structure files"
msgstr ""
#: src/rougail/config/__init__.py:291
msgid "File with functions"
msgstr ""
#: src/rougail/config/__init__.py:292
msgid "This file contains filters and additional Jinja2 functions usable in structure files"
msgstr ""
#: src/rougail/config/__init__.py:303
msgid "All modes level available"
msgstr ""
#: src/rougail/config/__init__.py:315
msgid "Default mode for a family"
msgstr ""
#: src/rougail/config/__init__.py:321
msgid "the first one defined in \"modes_level\""
msgstr ""
#: src/rougail/config/__init__.py:327 src/rougail/config/__init__.py:354
msgid "when no mode is defined in \"modes_level\""
msgstr ""
#: src/rougail/config/__init__.py:334 src/rougail/config/__init__.py:361
msgid "this mode must be available in \"modes_level\""
msgstr ""
#: src/rougail/config/__init__.py:338
msgid "Default mode for a variable"
msgstr ""
#: src/rougail/config/__init__.py:348
msgid "if the variable \"modes_level\" is defined, the default value is the second available element, otherwise, the first"
msgstr ""
#: src/rougail/config/__init__.py:365
msgid "Option name for the base option"
msgstr ""
#: src/rougail/config/__init__.py:370
msgid "In cache file, do not importation of Tiramisu and other dependencies"
msgstr ""
#: src/rougail/config/__init__.py:375
msgid "Store Tiramisu cache filename"
msgstr ""
#: src/rougail/config/__init__.py:376
msgid ""
"This file contains the Tiramisu instructions used internally to load the variables.\n"
"\n"
"This file can be used for debugging"
msgstr ""
#: src/rougail/config/__init__.py:386
msgid "Name of internal functions that we can use as a function"
msgstr ""
#: src/rougail/config/__init__.py:392
msgid "Name of extra annotators"
msgstr ""
#: src/rougail/config/__init__.py:398
msgid "Suffix add to generated options name"
msgstr ""
#: src/rougail/config/__init__.py:404
msgid "Every variables in calculation are optionals"
msgstr ""
#: src/rougail/config/__init__.py:408
msgid "Loads redefine variables even if there don't already exists"
msgstr ""
#: src/rougail/config/__init__.py:412
msgid "The secret manager"
msgstr ""
#: src/rougail/config/__init__.py:415
msgid "The secret pattern to constructing the name of the item searched for in the secret manager"
msgstr ""
#: src/rougail/config/__init__.py:416
msgid "The pattern is in Jinja2 format"
msgstr ""
#: src/rougail/config/__init__.py:425
msgid "structural"
msgstr ""
#: src/rougail/config/__init__.py:426
msgid "user datas"
msgstr ""
#: src/rougail/config/__init__.py:427
msgid "output"
msgstr ""
#: src/rougail/config/__init__.py:448
msgid "Select for {0}"
msgstr ""
#: src/rougail/config/__init__.py:486
msgid "outputs {0} did not allow user data"
msgstr ""
#: src/rougail/config/__init__.py:512
msgid "Override default parameters for option type"
msgstr ""
#: src/rougail/config/__init__.py:515
msgid "Default parameters for option type"
msgstr ""
#: src/rougail/convert/convert.py:281
msgid "unknown type {0} for {1}"
msgstr ""
#: src/rougail/convert.py:1345
msgid "duplicate dictionary file name {0}"
#: src/rougail/convert/convert.py:444
msgid "family \"{0}\" define multiple time"
msgstr ""
#: src/rougail/convert.py:1392
#: src/rougail/convert/convert.py:715
msgid "variable \"{0}\" define multiple time"
msgstr ""
#: src/rougail/convert/convert.py:808 src/rougail/convert/convert.py:815
msgid "params must be a dict for {0}"
msgstr ""
#: src/rougail/convert/convert.py:836
msgid "\"{0}\" has an invalid \"params\" for {1}: {2}"
msgstr ""
#: src/rougail/convert/convert.py:850
msgid "secret_manager must be a dict for {0}"
msgstr ""
#: src/rougail/convert/convert.py:1190
msgid "Cannot execute annotate multiple time"
msgstr ""
#: src/rougail/error.py:67
#: src/rougail/convert/convert.py:1197
msgid "invalid \"structural\" definition ({0}), we cannot load any structural file!"
msgstr ""
#: src/rougail/convert/object_model.py:132
msgid "cannot find variable \"{0}\" defined in attribute \"{1}\" for \"{2}\""
msgstr ""
#: src/rougail/convert/object_model.py:138
msgid "the variable \"{0}\" is in fact a family in attribute \"{1}\" for \"{2}\""
msgstr ""
#: src/rougail/convert/object_model.py:143
#: src/rougail/convert/object_model.py:528
msgid "unknown object \"{0}\" in attribute \"{1}\" for \"{2}\""
msgstr ""
#: src/rougail/convert/object_model.py:162
msgid "identifier parameter for \"{0}\" in \"{1}\" cannot be set none dynamic family"
msgstr ""
#: src/rougail/convert/object_model.py:191
msgid "cannot find variable \"{0}\" defined in \"{1}\" for \"{2}\""
msgstr ""
#: src/rougail/convert/object_model.py:196
msgid "variable \"{0}\" defined in \"{1}\" for \"{2}\" is a dynamic variable"
msgstr ""
#: src/rougail/convert/object_model.py:213
msgid "the variable \"{0}\" is not a follower, so cannot have index type for param in \"{1}\""
msgstr ""
#: src/rougail/convert/object_model.py:263
msgid "\"warnings\" are only available with attribute \"{self.attribute_name}\" for variable \"{self.path}\""
msgstr ""
#: src/rougail/convert/object_model.py:325
msgid "the variable \"{0}\" has a depreciated return_type \"{1}\", please use \"{2}\" instead in {3}"
msgstr ""
#: src/rougail/convert/object_model.py:413
#: src/rougail/convert/object_model.py:447
msgid "variable \"{0}\" has a calculating \"{1}\" with an invalid return_type, should be boolean or string, not \"{2}\""
msgstr ""
#: src/rougail/convert/object_model.py:424
msgid "the variable \"{0}\" has a return_type \"{1}\", for attribute \"{2}\" but has not description in {3}"
msgstr ""
#: src/rougail/convert/object_model.py:429
msgid "value is invalid"
msgstr ""
#: src/rougail/convert/object_model.py:523
msgid "a variable \"{0}\" is needs in attribute \"{1}\" for \"{2}\" but it's a family"
msgstr ""
#: src/rougail/convert/object_model.py:545
msgid "variable \"{0}\" has an attribute \"{1}\" calculated with the unknown variable \"{2}\""
msgstr ""
#: src/rougail/convert/object_model.py:593
msgid "the variable \"{0}\" has an invalid \"{1}\" the variable \"{2}\" is in a sub dynamic option"
msgstr ""
#: src/rougail/convert/object_model.py:602
msgid "the leader \"{0}\" has an invalid \"{1}\" the follower \"{2}\" is a multi"
msgstr ""
#: src/rougail/convert/object_model.py:644
msgid "the variable \"{0}\" has an invalid attribute \"{1}\", the variable \"{2}\" must not be multi"
msgstr ""
#: src/rougail/convert/object_model.py:658
msgid "the variable \"{0}\" has an invalid attribute \"{1}\", the variable must not be a multi or the variable \"{2}\" must be multi"
msgstr ""
#: src/rougail/convert/object_model.py:672
msgid "the variable \"{0}\" has an invalid attribute \"{1}\", the variable must be a multi or the variable \"{2}\" must not be multi"
msgstr ""
#: src/rougail/convert/object_model.py:686
msgid "the variable \"{0}\" has an invalid attribute \"{1}\", the variable \"{2}\" is multi but is inside a list"
msgstr ""
#: src/rougail/convert/object_model.py:708
msgid "the variable \"{0}\" is waiting for a list as \"{1}\" but the attribute \"default\" is not a list (\"{2}\")"
msgstr ""
#: src/rougail/convert/object_model.py:712
msgid "the variable \"{0}\" is not waiting for a list as \"{1}\" but the attribute \"default\" is a list (\"{2}\")"
msgstr ""
#: src/rougail/convert/object_model.py:737
msgid "\"{0}\" attribut shall not have an \"optional\" attribute without the \"default\" attribute for variable \"{1}\""
msgstr ""
#: src/rougail/convert/object_model.py:759
msgid "variable \"{0}\" has a default value calculated with \"{1}\" which has incompatible type"
msgstr ""
#: src/rougail/convert/object_model.py:805
msgid "the variable \"{0}\" is waiting for a boolean as \"{1}\" but the attribute \"default\" is not a boolean (\"{2}\")"
msgstr ""
#: src/rougail/convert/object_model.py:828
msgid "\"when\" is not allowed in format version 1.0 for attribute \"{0}\" for variable \"{1}\""
msgstr ""
#: src/rougail/convert/object_model.py:833
msgid "the variable \"{0}\" has an invalid attribute \"{1}\", \"when\" and \"when_not\" cannot set together"
msgstr ""
#: src/rougail/convert/object_model.py:841
msgid "\"when_not\" is not allowed in format version 1.0 for attribute \"{0}\" for variable \"{1}\""
msgstr ""
#: src/rougail/convert/object_model.py:852
msgid "\"when\" or \"when_not\" is mandatory for the not boolean variable \"{0}\" in attribute \"{1}\""
msgstr ""
#: src/rougail/convert/object_model.py:899
msgid "cannot find variable \"{0}\" for the information \"{1}\" when calculating \"{2}\""
msgstr ""
#: src/rougail/convert/object_model.py:904
msgid "identifier not allowed for the information \"{0}\" when calculating \"{1}\""
msgstr ""
#: src/rougail/convert/object_model.py:958
msgid "\"when\" is not allowed in format version 1.0 for attribute \"{0}\""
msgstr ""
#: src/rougail/convert/object_model.py:964
#: src/rougail/convert/object_model.py:974
msgid "the identifier has an invalid attribute \"{0}\", \"when\" and \"when_not\" cannot set together"
msgstr ""
#: src/rougail/convert/object_model.py:1001
msgid "the variable \"{0}\" is not a follower, so cannot have index type for \"{1}\""
msgstr ""
#: src/rougail/convert/path.py:211
msgid "A variable or a family located in the \"{0}\" namespace shall not be used in the \"{1}\" namespace"
msgstr ""
#: src/rougail/convert/tiramisureflector.py:348
msgid "variable param \"{0}\" has whole attribute but it's not allowed for external variable"
msgstr ""
#: src/rougail/convert/tiramisureflector.py:351
msgid "variable param \"{0}\" has dynamic attribute but it's not allowed for external variable"
msgstr ""
#: src/rougail/convert/tiramisureflector.py:360
msgid "internal error, {0} is not a dynamic variable"
msgstr ""
#: src/rougail/error.py:61 src/rougail/tiramisu.py:237
msgid "{0} in {1}"
msgstr ""
@ -95,23 +457,368 @@ msgstr ""
msgid "conflict alternative_name \"{0}\": \"{1}\" and \"{2}\""
msgstr ""
#: src/rougail/structural_commandline/annotator.py:95
msgid "negative_description is mandatory for boolean variable, but \"{0}\" hasn't"
#: src/rougail/structural_directory/__init__.py:130
msgid "duplicate structural file name {0}"
msgstr ""
#: src/rougail/structural_commandline/annotator.py:104
msgid "negative_description is only available for boolean variable, but \"{0}\" is \"{1}\""
#: src/rougail/structural_directory/config.py:32
msgid "Main namespace name"
msgstr ""
#: src/rougail/update/update.py:738
msgid "not a XML file: {0}"
#: src/rougail/structural_directory/config.py:40
msgid "directory or string is not in \"_.step.structural\""
msgstr ""
#: src/rougail/utils.py:55
#: src/rougail/structural_directory/config.py:43
msgid "Directories where structural files are placed"
msgstr ""
#: src/rougail/structural_directory/config.py:60
msgid "Sort structural from differents directories"
msgstr ""
#: src/rougail/structural_directory/config.py:69
msgid "Namespaces are isolated"
msgstr ""
#: src/rougail/structural_directory/config.py:75
msgid "directory or string is not in \"_.step.structural\" or \"_.main_namespace\" is not set"
msgstr ""
#: src/rougail/structural_directory/config.py:78
msgid "Extra namespaces"
msgstr ""
#: src/rougail/structural_directory/config.py:87
msgid "Extra namespace name"
msgstr ""
#: src/rougail/structural_directory/config.py:93
msgid "Directories where extra structural files are placed"
msgstr ""
#: src/rougail/structural_directory/config.py:106
msgid "directory is not in \"__.step.structural\""
msgstr ""
#: src/rougail/structural_string/config.py:32
msgid "Structural files contents"
msgstr ""
#: src/rougail/structural_string/config.py:33
#: src/rougail/structural_string/config.py:51
msgid "This variable is a list of string with YAML file format"
msgstr ""
#: src/rougail/structural_string/config.py:45
msgid "string is not in \"_.step.structural\""
msgstr ""
#: src/rougail/structural_string/config.py:50
msgid "Extra structural contents"
msgstr ""
#: src/rougail/structural_string/config.py:58
msgid "string is not in \"__.step.structural\""
msgstr ""
#: src/rougail/tiramisu.py:85
msgid "unknown boolean value \"{0}\""
msgstr ""
#: src/rougail/tiramisu.py:88
msgid "IP must be in CIDR format"
msgstr ""
#: src/rougail/tiramisu.py:89
msgid "private IP are allowed"
msgstr ""
#: src/rougail/tiramisu.py:90
msgid "reserved IP are allowed"
msgstr ""
#: src/rougail/tiramisu.py:93
msgid "network must be in CIDR format"
msgstr ""
#: src/rougail/tiramisu.py:94
msgid "private network are allowed"
msgstr ""
#: src/rougail/tiramisu.py:95
msgid "reserved network are allowed"
msgstr ""
#: src/rougail/tiramisu.py:98
msgid "can be range of port"
msgstr ""
#: src/rougail/tiramisu.py:99
msgid "can have the protocol"
msgstr ""
#: src/rougail/tiramisu.py:100
msgid "port 0 is allowed"
msgstr ""
#: src/rougail/tiramisu.py:101
msgid "well-known ports (1 to 1023) are allowed"
msgstr ""
#: src/rougail/tiramisu.py:102
msgid "registred ports (1024 to 49151) are allowed"
msgstr ""
#: src/rougail/tiramisu.py:103
msgid "private ports (greater than 49152) are allowed"
msgstr ""
#: src/rougail/tiramisu.py:106
msgid "type of domainname"
msgstr ""
#: src/rougail/tiramisu.py:106
msgid "type {0}"
msgstr ""
#: src/rougail/tiramisu.py:107
msgid "the domain name can starts by a dot"
msgstr ""
#: src/rougail/tiramisu.py:108
msgid "the domain name can be a hostname"
msgstr ""
#: src/rougail/tiramisu.py:109
msgid "the domain name can be an IP"
msgstr ""
#: src/rougail/tiramisu.py:110
msgid "the domain name can be network in CIDR format"
msgstr ""
#: src/rougail/tiramisu.py:111
msgid "the domain name must exist"
msgstr ""
#: src/rougail/tiramisu.py:121 src/rougail/tiramisu.py:127
msgid "the minimum value"
msgstr ""
#: src/rougail/tiramisu.py:121 src/rougail/tiramisu.py:127
msgid "the minimum value is {0}"
msgstr ""
#: src/rougail/tiramisu.py:122 src/rougail/tiramisu.py:128
msgid "the maximum value"
msgstr ""
#: src/rougail/tiramisu.py:122 src/rougail/tiramisu.py:128
msgid "the maximum value is {0}"
msgstr ""
#: src/rougail/tiramisu.py:137
msgid "minimum characters length for the secret"
msgstr ""
#: src/rougail/tiramisu.py:137
msgid "minimum length for the secret is {0} characters"
msgstr ""
#: src/rougail/tiramisu.py:138
msgid "maximum characters length for the secret"
msgstr ""
#: src/rougail/tiramisu.py:138
msgid "maximum length for the secret is {0} characters"
msgstr ""
#: src/rougail/tiramisu.py:139
msgid "forbidden characters"
msgstr ""
#: src/rougail/tiramisu.py:139
msgid "forbidden characters: {0}"
msgstr ""
#: src/rougail/tiramisu.py:146
msgid "this filename could be a relative path"
msgstr ""
#: src/rougail/tiramisu.py:147
msgid "this file must exist"
msgstr ""
#: src/rougail/tiramisu.py:148
msgid "file type allowed"
msgstr ""
#: src/rougail/tiramisu.py:148
msgid "file type allowed: {0}"
msgstr ""
#: src/rougail/tiramisu.py:438
msgid "cannot calculate the variable \"{0}\""
msgstr ""
#: src/rougail/tiramisu.py:439
msgid "the attribute \"{0}\" in {1} with the parameters \"{2}\" causes the error: {3}"
msgstr ""
#: src/rougail/tiramisu.py:457
msgid "cannot converting the variable \"{0}\""
msgstr ""
#: src/rougail/tiramisu.py:458
msgid "\"{0}\" is an invalid {1}"
msgstr ""
#: src/rougail/tiramisu.py:460
msgid "the attribute \"{0}\" in {1} causes the error: {2}"
msgstr ""
#: src/rougail/types.py:66
msgid "type is not compatible with leadership family"
msgstr ""
#: src/rougail/types.py:68
msgid "type is not compatible with dynamic family"
msgstr ""
#: src/rougail/user_data.py:104
msgid "{0}, it will be ignored"
msgstr ""
#: src/rougail/user_data.py:155
msgid "cannot load variable path \"{0}\", the identifier \"{1}\" is not valid in {2}"
msgstr ""
#: src/rougail/user_data.py:239
msgid "the variable contains secrets and should not be defined in {0}"
msgstr ""
#: src/rougail/user_data.py:318
msgid "it's a family so we cannot set the value {0}, it has been loading from {1}"
msgstr ""
#: src/rougail/user_data.py:322
msgid "it's a family so we cannot set the value {0}, it will be ignored when loading from {1}"
msgstr ""
#: src/rougail/user_data.py:332
msgid "it's a symlink option so we cannot set the value {0}"
msgstr ""
#: src/rougail/user_data.py:334 src/rougail/user_data.py:364
#: src/rougail/user_data.py:493 src/rougail/user_data.py:505
#: src/rougail/user_data.py:518
msgid "{0}, it has been loading from {1}"
msgstr ""
#: src/rougail/user_data.py:336 src/rougail/user_data.py:368
#: src/rougail/user_data.py:497 src/rougail/user_data.py:509
#: src/rougail/user_data.py:520
msgid "{0}, it will be ignored when loading from {1}"
msgstr ""
#: src/rougail/user_data.py:341 src/rougail/user_data.py:346
msgid "{0}, it has been loaded from {1}"
msgstr ""
#: src/rougail/user_data.py:360
msgid "variable or family \"{0}\" does not exist so cannot load \"{1}\""
msgstr ""
#: src/rougail/user_data.py:377
msgid "\"{0}\" is the name of a dynamic family, it has been loading from {1}"
msgstr ""
#: src/rougail/user_data.py:381
msgid "\"{0}\" is the name of a dynamic family, it will be ignored when loading from {1}"
msgstr ""
#: src/rougail/user_data.py:387
msgid "{0} loaded from {1}"
msgstr ""
#: src/rougail/user_data.py:426
msgid "variable {0} at index \"{1}\" is {2}, it has been loading from {3}"
msgstr ""
#: src/rougail/user_data.py:430
msgid "variable {0} at index \"{1}\" is {2}, it will be ignored when loading from {3}"
msgstr ""
#: src/rougail/user_data.py:443
msgid "family {0} is {1}, {2} at index \"{3}\", it has been loading from {4}"
msgstr ""
#: src/rougail/user_data.py:447
msgid "family {0} is {1}, {2} at index \"{3}\", it will be ignored when loading from {4}"
msgstr ""
#: src/rougail/user_data.py:462
msgid "variable has propery {0}, it has been loading from {1}"
msgstr ""
#: src/rougail/user_data.py:466
msgid "variable has property {0}, it will be ignored when loading from {1}"
msgstr ""
#: src/rougail/user_data.py:476
msgid "family {0} has property {1}, so cannot access to {2}, it has been loading from {3}"
msgstr ""
#: src/rougail/user_data.py:480
msgid "family {0} has property {1}, so cannot access to {2}, it will be ignored when loading from {3}"
msgstr ""
#: src/rougail/user_data.py:525
msgid "the value {0} is an invalid {1}, {2}"
msgstr ""
#: src/rougail/user_data.py:531
msgid ", it has been loading from {0}"
msgstr ""
#: src/rougail/user_data.py:533
msgid ", it will be ignored when loading from {0}"
msgstr ""
#: src/rougail/user_data.py:566
msgid "loaded from {0}"
msgstr ""
#: src/rougail/user_data.py:574
msgid "{0} (the search key is \"{1}\")"
msgstr ""
#: src/rougail/utils.py:56
msgid "invalid variable or family name \"{0}\" must only contains lowercase ascii character, number or _"
msgstr ""
#: src/rougail/utils.py:117
msgid "error in jinja \"{0}\" for the variable \"{1}\": {2}"
#: src/rougail/utils.py:104
msgid "error for the variable \"{1}\" in jinja \"{0}\": {2}"
msgstr ""
#: src/rougail/utils.py:212
msgid "mandatory"
msgstr ""
#: src/rougail/utils.py:213
msgid "hidden"
msgstr ""
#: src/rougail/utils.py:214
msgid "disabled"
msgstr ""
#: src/rougail/utils.py:215
msgid "unique"
msgstr ""
#: src/rougail/utils.py:216
msgid "auto modified"
msgstr ""

View file

@ -1,50 +1,18 @@
[build-system]
build-backend = "flit_core.buildapi"
requires = ["flit_core >=3.8.0,<4"]
[project]
name = "rougail"
version = "1.1.1"
authors = [{name = "Emmanuel Garette", email = "gnunux@gnunux.info"}]
readme = "README.md"
description = "A consistency handling system that was initially designed in the configuration management"
requires-python = ">=3.8"
classifiers = [
"License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)",
"Programming Language :: Python",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3",
"Operating System :: OS Independent",
"Natural Language :: English",
"Natural Language :: French",
]
dependencies = [
"ruamel.yaml ~= 0.18.6",
"pydantic ~= 2.9.2",
"jinja2 ~= 3.1.4",
"tiramisu >=5.0,<6"
]
[project.optional-dependencies]
dev = [
"pylint ~= 3.0.3",
"pytest ~= 8.2.2",
"lxml ~= 5.2.2"
]
[project.urls]
Home = "https://forge.cloud.silique.fr/stove/rougail"
version = "1.2.0a60"
[tool.commitizen]
name = "cz_conventional_commits"
tag_format = "$version"
version_scheme = "pep440"
version_provider = "pep621"
version_files = [
"src/rougail/__version__.py",
"rougail-pyproject.toml:version",
"rougail-pyproject.toml:rougail-base == ",
"rougail-base-pyproject.toml:version",
]
update_changelog_on_bump = true
changelog_merge_prerelease = true

View file

@ -0,0 +1,52 @@
[build-system]
build-backend = "flit_core.buildapi"
requires = ["flit_core >=3.8.0,<4"]
[project]
name = "rougail-base"
version = "1.2.0a60"
authors = [{name = "Emmanuel Garette", email = "gnunux@gnunux.info"}]
readme = "README.md"
description = "A consistency handling system that was initially designed in the configuration management"
requires-python = ">=3.10"
license = {file = "LICENSE"}
classifiers = [
"License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)",
"Programming Language :: Python",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Programming Language :: Python :: 3",
"Operating System :: OS Independent",
"Natural Language :: English",
"Natural Language :: French",
]
dependencies = [
"jinja2 ~= 3.1.4",
"tiramisu ~= 5.0"
]
[project.optional-dependencies]
dev = [
"pylint ~= 3.0.3",
"pytest ~= 8.2.2",
]
[tool.flit.module]
name = "rougail"
[tool.flit.sdist]
exclude = [
"src/rougail/annotator",
"src/rougail/config",
"src/rougail/convert",
"src/rougail/structural_commandline",
"src/rougail/structural_directory",
"src/rougail/update",
]
[project.urls]
Home = "https://forge.cloud.silique.fr/stove/rougail"

35
rougail-pyproject.toml Normal file
View file

@ -0,0 +1,35 @@
[build-system]
build-backend = "flit_core.buildapi"
requires = ["flit_core >=3.8.0,<4"]
[project]
name = "rougail"
version = "1.2.0a60"
authors = [{name = "Emmanuel Garette", email = "gnunux@gnunux.info"}]
description = "A consistency handling system that was initially designed in the configuration management"
classifiers = [
"License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)",
"Programming Language :: Python",
"Operating System :: OS Independent",
"Natural Language :: English",
"Natural Language :: French",
]
dependencies = [
"ruamel.yaml ~= 0.18.6",
"pydantic ~= 2.9.2",
"rougail-base == 1.2.0a60",
]
[tool.flit.sdist]
exclude = [
"src/rougail/error.py",
"src/rougail/i18n.py",
"src/rougail/tiramisu.py",
"src/rougail/user_datas.py",
"src/rougail/utils.py",
"src/rougail/__version__.py",
]
[project.urls]
Home = "https://forge.cloud.silique.fr/stove/rougail"

View file

@ -9,7 +9,7 @@ Cadoles (http://www.cadoles.com)
Copyright (C) 2019-2021
Silique (https://www.silique.fr)
Copyright (C) 2022-2024
Copyright (C) 2022-2026
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,302 +25,12 @@ 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/>.
"""
from tiramisu import Config, undefined
from tiramisu.error import PropertiesOptionError, LeadershipError, ConfigError
from warnings import warn
from typing import List
from re import compile, findall
from .__version__ import __version__
from .convert import RougailConvert
from .config import RougailConfig
from .update import RougailUpgrade
from .object_model import CONVERT_OPTION
from .utils import normalize_family
try:
from .convert import Rougail
from .config import RougailConfig
def tiramisu_display_name(
kls,
subconfig,
with_quote: bool = False,
) -> str:
"""Replace the Tiramisu display_name function to display path + description"""
doc = kls._get_information(subconfig, "doc", None)
comment = f" ({doc})" if doc and doc != kls.impl_getname() else ""
if "{{ identifier }}" in comment:
comment = comment.replace("{{ identifier }}", str(subconfig.identifiers[-1]))
path = kls.impl_getpath()
if "{{ identifier }}" in path and subconfig.identifiers:
path = path.replace(
"{{ identifier }}", normalize_family(str(subconfig.identifiers[-1]))
)
if with_quote:
return f'"{path}"{comment}'
return f"{path}{comment}"
class Rougail:
"""Main Rougail object"""
def __init__(
self,
rougailconfig=None,
) -> None:
if rougailconfig is None:
rougailconfig = RougailConfig
self.rougailconfig = rougailconfig
self.converted = RougailConvert(self.rougailconfig)
self.config = None
def add_path_prefix(
self,
path_prefix: str,
) -> None:
"""Add a prefix"""
self.converted.load_config()
self.converted.parse_directories(path_prefix)
def run(self):
"""Get Tiramisu Config"""
if not self.config:
tiram_obj = self.converted.save(self.rougailconfig["tiramisu_cache"])
optiondescription = {}
custom_types = {
custom.__name__: custom
for custom in self.rougailconfig["custom_types"].values()
}
exec(tiram_obj, custom_types, optiondescription) # pylint: disable=W0122
self.config = Config(
optiondescription["option_0"],
display_name=tiramisu_display_name,
)
self.config.property.read_write()
return self.config
def get_config(self):
warn(
"get_config is deprecated, use run instead",
DeprecationWarning,
stacklevel=2,
)
return self.run()
def user_datas(self, user_datas: List[dict]):
values = {}
errors = []
warnings = []
for datas in user_datas:
options = datas.get("options", {})
for name, data in datas.get("values", {}).items():
values[name] = {
"values": data,
"options": options.copy(),
}
errors.extend(datas.get("errors", []))
warnings.extend(datas.get("warnings", []))
self._auto_configure_dynamics(values)
while values:
value_is_set = False
for option in self._get_variable(self.config):
path = option.path()
if path not in values:
path = path.upper()
options = values.get(path, {}).get("options", {})
if path not in values or options.get("upper") is not True:
continue
else:
options = values[path].get("options", {})
value = values[path]["values"]
if option.ismulti():
if options.get("multi_separator") and not isinstance(value, list):
value = value.split(options["multi_separator"])
values[path]["values"] = value
if options.get("needs_convert"):
value = [convert_value(option, val) for val in value]
values[path]["values"] = value
values[path]["options"]["needs_convert"] = False
elif options.get("needs_convert"):
value = convert_value(option, value)
index = option.index()
if index is not None:
if not isinstance(value, list) or index >= len(value):
continue
value = value[index]
try:
option.value.set(value)
value_is_set = True
if index is not None:
values[path]["values"][index] = undefined
if set(values[path]["values"]) == {undefined}:
values.pop(path)
else:
values.pop(path)
except Exception as err:
if path != option.path():
values[option.path()] = values.pop(path)
if not value_is_set:
break
for path, data in values.items():
try:
option = self.config.option(path)
value = data["values"]
if option.isfollower():
for index, val in enumerate(value):
if val is undefined:
continue
self.config.option(path, index).value.set(val)
else:
option.value.set(value)
except AttributeError as err:
errors.append(str(err))
except (ValueError, LeadershipError) as err:
# errors.append(str(err).replace('"', "'"))
errors.append(str(err))
except PropertiesOptionError as err:
# warnings.append(f'"{err}" but is defined in "{self.filename}"')
warnings.append(str(err))
return {
"errors": errors,
"warnings": warnings,
}
def _get_variable(self, config):
for subconfig in config:
if subconfig.isoptiondescription():
yield from self._get_variable(subconfig)
else:
yield subconfig
def _auto_configure_dynamics(
self,
values,
):
cache = {}
added = []
for path, data in list(values.items()):
value = data["values"]
# for value in data['values'].items():
try:
option = self.config.option(path)
option.name()
except (ConfigError, PropertiesOptionError):
pass
except AttributeError:
config = self.config
current_path = ""
identifiers = []
for name in path.split(".")[:-1]:
if current_path:
current_path += "."
current_path += name
if current_path in cache:
config, identifier = cache[current_path]
identifiers.append(identifier)
else:
tconfig = config.option(name)
try:
tconfig.group_type()
config = tconfig
except AttributeError:
for tconfig in config.list(uncalculated=True):
if tconfig.isdynamic(only_self=True):
identifier = self._get_identifier(
tconfig.name(), name
)
if identifier is None:
continue
dynamic_variable = tconfig.information.get(
"dynamic_variable",
None,
)
if not dynamic_variable:
continue
option_type = self.config.option(
dynamic_variable
).information.get("type")
if identifiers:
for s in identifiers:
dynamic_variable = dynamic_variable.replace(
"{{ identifier }}", str(s), 1
)
if dynamic_variable not in values:
values[dynamic_variable] = {"values": []}
added.append(dynamic_variable)
elif dynamic_variable not in added:
continue
config = tconfig
# option_type = option.information.get('type')
typ = CONVERT_OPTION.get(option_type, {}).get(
"func"
)
if typ:
identifier = typ(identifier)
if (
identifier
not in values[dynamic_variable]["values"]
):
values[dynamic_variable]["values"].append(
identifier
)
identifiers.append(identifier)
cache[current_path] = config, identifier
break
else:
if option.isdynamic():
parent_option = self.config.option(path.rsplit(".", 1)[0])
identifiers = self._get_identifier(
parent_option.name(uncalculated=True),
parent_option.name(),
)
dynamic_variable = None
while True:
dynamic_variable = parent_option.information.get(
"dynamic_variable",
None,
)
if dynamic_variable:
break
parent_option = self.config.option(
parent_option.path().rsplit(".", 1)[0]
)
if "." not in parent_option.path():
parent_option = None
break
if not parent_option:
continue
identifiers = parent_option.identifiers()
for identifier in identifiers:
dynamic_variable = dynamic_variable.replace(
"{{ identifier }}", str(identifier), 1
)
if dynamic_variable not in values:
values[dynamic_variable] = {"values": []}
added.append(dynamic_variable)
elif dynamic_variable not in added:
continue
option_type = option.information.get("type")
typ = CONVERT_OPTION.get(option_type, {}).get("func")
if typ:
identifier = typ(identifier)
if identifier not in values[dynamic_variable]["values"]:
values[dynamic_variable]["values"].append(identifier)
cache[option.path()] = option, identifier
def _get_identifier(self, true_name, name) -> str:
regexp = true_name.replace("{{ identifier }}", "(.*)")
finded = findall(regexp, name)
if len(finded) != 1 or not finded[0]:
return
return finded[0]
def convert_value(option, value):
if value == "":
return None
option_type = option.information.get("type")
func = CONVERT_OPTION.get(option_type, {}).get("func")
if func:
return func(value)
return value
__all__ = ("Rougail", "RougailConfig", "RougailUpgrade")
__all__ = ("Rougail", "RougailConfig", "__version__")
except ModuleNotFoundError as err:
__all__ = ("__version__",)

View file

@ -0,0 +1 @@
__version__ = "1.2.0a60"

View file

@ -1,4 +1,4 @@
"""Annotate dictionaries
"""Annotate structural file
Created by:
EOLE (http://eole.orion.education.fr)
@ -9,7 +9,7 @@ Cadoles (http://www.cadoles.com)
Copyright (C) 2019-2021
Silique (https://www.silique.fr)
Copyright (C) 2022-2024
Copyright (C) 2022-2026
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
@ -71,16 +71,38 @@ class SpaceAnnotator: # pylint: disable=R0903
if extra_annotator in ANNOTATORS:
continue
get_annotators(ANNOTATORS, extra_annotator)
for plugin in objectspace.plugins:
for structural in objectspace.structurals:
try:
get_annotators(ANNOTATORS, f"rougail.{plugin}", "annotator")
get_annotators(
ANNOTATORS, f"rougail.structural_{structural}", "annotator"
)
except ModuleNotFoundError:
pass
for user_data in objectspace.user_data:
try:
get_annotators(
ANNOTATORS, f"rougail.user_data_{user_data}", "annotator"
)
except ModuleNotFoundError:
pass
if objectspace.output:
try:
get_annotators(
ANNOTATORS, f"rougail.output_{objectspace.output}", "annotator"
)
except ModuleNotFoundError:
pass
annotators = ANNOTATORS["rougail.annotator"].copy()
for extra_annotator in objectspace.extra_annotators:
annotators.extend(ANNOTATORS[extra_annotator])
for plugin in objectspace.plugins:
annotators.extend(ANNOTATORS[f"rougail.{plugin}.annotator"])
for structural in objectspace.structurals:
annotators.extend(ANNOTATORS[f"rougail.structural_{structural}.annotator"])
for user_data in objectspace.user_data:
annotators.extend(ANNOTATORS[f"rougail.user_data_{user_data}.annotator"])
if objectspace.output:
annotators.extend(
ANNOTATORS[f"rougail.output_{objectspace.output}.annotator"]
)
annotators = sorted(annotators, key=get_level)
functions = {}
functions_files = objectspace.functions_files

View file

@ -9,7 +9,7 @@ Cadoles (http://www.cadoles.com)
Copyright (C) 2019-2021
Silique (https://www.silique.fr)
Copyright (C) 2022-2024
Copyright (C) 2022-2026
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,7 +29,7 @@ from typing import Optional
from rougail.i18n import _
from rougail.error import DictConsistencyError
from rougail.annotator.variable import Walk
from rougail.object_model import VariableCalculation
from rougail.convert.object_model import VariableCalculation
class Mode: # pylint: disable=R0903
@ -122,14 +122,27 @@ class Annotator(Walk):
for family in self.get_families():
if not family.description:
family.description = family.name
self.objectspace.forced_descriptions.append(family.path)
if family.type == "dynamic" and isinstance(
family.dynamic, VariableCalculation
):
path = self.objectspace.paths.get_full_path(
family.dynamic.variable,
family.path,
path = family.dynamic.variable
if (
family.version != "1.0"
and self.objectspace.paths.regexp_relative.search(path)
):
path = self.objectspace.paths.get_full_path(
family.dynamic.variable,
family.path,
)
if family.version == "1.0" and "{{ suffix }}" in path:
path = path.replace("{{ suffix }}", "{{ identifier }}")
self.objectspace.dynamics_variable.setdefault(path, []).append(
family.path
)
self.objectspace.informations.add(family.path, "dynamic_variable", path)
if family.xmlfiles:
self.objectspace.informations.add(family.path, "ymlfiles", family.xmlfiles)
def change_modes(self):
"""change the mode of variables"""
@ -333,7 +346,7 @@ class Annotator(Walk):
if self._has_mode(variable):
msg = _(
'the variable "{0}" is in "{1}" mode but family has the higher family mode "{2}"'
).format(variable.name, variable_mode, family_mode)
).format(variable.path, variable_mode, family_mode)
raise DictConsistencyError(msg, 61, variable.xmlfiles)
self._set_auto_mode(variable, family_mode)
if not variable.mode:

View file

@ -9,7 +9,7 @@ Cadoles (http://www.cadoles.com)
Copyright (C) 2019-2021
Silique (https://www.silique.fr)
Copyright (C) 2022-2024
Copyright (C) 2022-2026
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,11 +25,14 @@ 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/>.
"""
from typing import Union
from typing import Union, List
from tiramisu.setting import PROPERTIES_MAKE_SENSE
from rougail.i18n import _
from rougail.error import DictConsistencyError
from rougail.annotator.variable import Walk
from rougail.object_model import Calculation
from rougail.convert.object_model import Calculation
from rougail.utils import NAME_REGEXP
from rougail.convert.object_model import VariableCalculation
PROPERTIES = (
@ -49,33 +52,56 @@ class Annotator(Walk):
def __init__(self, objectspace, *args) -> None:
self.objectspace = objectspace
if not self.objectspace.paths:
return
self.frozen = {}
if self.objectspace.paths:
self.convert_family()
self.convert_variable()
self.variables_default_transitive = []
self.convert_leadership()
self.convert_family()
self.convert_variable()
def convert_leadership(self) -> None:
for variable_path in self.objectspace.leaders:
variable = self.objectspace.paths[variable_path]
if variable.hidden:
family = self.objectspace.paths[variable.path.rsplit(".", 1)[0]]
hidden = variable.hidden
if hidden is not True:
hidden = hidden.model_copy()
if hidden.ori_path is None:
hidden.ori_path = variable_path
family.hidden = hidden
variable.hidden = None
def convert_family(self) -> None:
"""convert families"""
for family in self.get_families():
self._convert_property(family)
self.family_variable_property(family)
# collect for force_default_on_freeze
if family.hidden:
self.set_variable_frozen(
if family.hidden is True:
frozen = True
else:
frozen = family.hidden.model_copy()
frozen.attribute_name = "frozen"
if frozen.ori_path is None:
frozen.ori_path = family.path
self.set_variable_frozen_inside_family(
family.path,
family.hidden,
frozen,
)
def set_variable_frozen(
def set_variable_frozen_inside_family(
self,
family_path: str,
hidden: Union[bool, Calculation],
frozen: Union[bool, Calculation],
) -> None:
for variable_path in self.objectspace.parents[family_path]:
if variable_path in self.objectspace.families:
# it's a family
self.set_variable_frozen(
self.set_variable_frozen_inside_family(
variable_path,
hidden,
frozen,
)
else:
# it's a variable
@ -84,51 +110,48 @@ class Annotator(Walk):
if (
self.frozen.get(variable.path) is True
or variable.hidden is True
or hidden is True
or frozen is True
):
self.frozen[variable.path] = True
elif variable.path in self.frozen:
self.frozen[variable.path].append(hidden)
else:
self.frozen[variable.path] = [hidden]
if variable.path in self.frozen:
if not isinstance(self.frozen[variable.path], list):
self.frozen[variable.path] = [frozen]
self.frozen[variable.path].append(frozen)
else:
self.frozen[variable.path] = frozen
def convert_variable(self) -> None:
"""convert variables"""
for variable in self.get_variables():
if variable.path.startswith("services."):
continue
if variable.type == "symlink":
continue
self._convert_variable_property(variable)
self.convert_variable_property(variable)
def _convert_variable_property(
def convert_variable_property(
self,
variable: dict,
) -> None:
"""convert properties"""
path = variable.path
self._convert_property(variable)
self.family_variable_property(variable)
if variable.hidden:
if variable.hidden is True:
self.frozen[path] = True
elif self.frozen.get(path) is not True:
self.frozen.setdefault(path, []).append(variable.hidden)
frozen = variable.hidden.model_copy()
frozen.attribute_name = "frozen"
if frozen.ori_path is None:
frozen.ori_path = path
if path in self.frozen:
if not isinstance(self.frozen, list):
self.frozen[path] = [self.frozen[path]]
self.frozen[path].append(frozen)
else:
self.frozen[path] = frozen
if path in self.frozen:
frozen = self.frozen[path]
if frozen is True:
value = True
else:
value = []
for calculation in frozen:
calculation_copy = calculation.copy()
calculation_copy.attribute_name = "frozen"
calculation_copy.ori_path = calculation_copy.path
calculation_copy.path = path
value.append(calculation_copy)
if len(value) == 1:
value = value[0]
self.objectspace.properties.add(path, "frozen", value)
if not variable.auto_save:
self.objectspace.properties.add(path, "frozen", self.frozen[path])
if not variable.auto_save and not variable.secret_manager:
# if auto_save, save calculated value
self.objectspace.properties.add(path, "force_default_on_freeze", True)
if not variable.empty and self.objectspace.multis.get(variable.path, False):
@ -141,8 +164,37 @@ class Annotator(Walk):
self.objectspace.properties.add(path, "notunique", True)
if variable.auto_save:
self.objectspace.properties.add(path, "force_store_value", True)
if variable.tags:
for tag in variable.tags:
self.check_tag(tag, variable.xmlfiles)
self.objectspace.properties.add(variable.path, tag, True)
self.objectspace.informations.add(
variable.path, "tags", tuple(variable.tags)
)
def _convert_property(
def check_tag(
self,
tag: str,
xmlfiles: List[str],
):
match = NAME_REGEXP.search(tag)
if not match:
msg = _(
'invalid tag name "{0}" should only contains lowercase ascii character, number or _'
).format(tag)
raise DictConsistencyError(msg, 82, xmlfiles)
if tag in self.objectspace.modes_level:
msg = _(
'invalid tag name "{0}" should not be a name of an existing mode'
).format(tag)
raise DictConsistencyError(msg, 82, xmlfiles)
if tag in PROPERTIES_MAKE_SENSE:
msg = _(
'invalid tag name "{0}" should not be the name of an available properties'
).format(tag)
raise DictConsistencyError(msg, 82, xmlfiles)
def family_variable_property(
self,
obj: dict,
) -> None:

View file

@ -9,7 +9,7 @@ Cadoles (http://www.cadoles.com)
Copyright (C) 2019-2021
Silique (https://www.silique.fr)
Copyright (C) 2022-2024
Copyright (C) 2022-2026
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,7 +29,7 @@ from rougail.annotator.variable import Walk
from rougail.i18n import _
from rougail.error import DictConsistencyError
from rougail.object_model import Calculation
from rougail.convert.object_model import Calculation
class Annotator(Walk): # pylint: disable=R0903
@ -47,6 +47,7 @@ class Annotator(Walk): # pylint: disable=R0903
self.objectspace = objectspace
self.convert_value()
self.valid_choices()
self.valid_regexp()
def convert_value(self) -> None:
"""convert value"""
@ -75,8 +76,8 @@ class Annotator(Walk): # pylint: disable=R0903
raise DictConsistencyError(msg, 68, variable.xmlfiles)
if variable.path in self.objectspace.followers and multi != "submulti":
msg = _(
'the follower "{0}" without multi attribute can only have one value'
).format(variable.name)
'the follower "{0}" is not multi, so cannot have a list has default value'
).format(variable.path)
raise DictConsistencyError(msg, 87, variable.xmlfiles)
if not variable.default:
variable.default = None
@ -92,7 +93,7 @@ class Annotator(Walk): # pylint: disable=R0903
elif variable.multi:
msg = _(
'the variable "{0}" is multi but has a non list default value'
).format(variable.name)
).format(variable.path)
raise DictConsistencyError(msg, 12, variable.xmlfiles)
elif variable.path in self.objectspace.followers:
self.objectspace.default_multi[variable.path] = variable.default
@ -114,7 +115,9 @@ class Annotator(Walk): # pylint: disable=R0903
if isinstance(variable.choices, Calculation):
continue
if variable.choices is None:
msg = f'the variable "{variable.path}" is a "choice" variable but don\'t have any choice'
msg = _(
'the variable "{0}" is a "choice" variable but don\'t have any choice'
).format(variable.path)
raise DictConsistencyError(msg, 19, variable.xmlfiles)
if not variable.mandatory and not variable.multi:
self.add_choice_nil(variable)
@ -125,3 +128,13 @@ class Annotator(Walk): # pylint: disable=R0903
if choice is None:
return
variable.choices.append(None)
def valid_regexp(self) -> None:
for variable in self.get_variables():
if variable.type != "regexp":
continue
if variable.regexp is None:
msg = _(
'the variable "{0}" is a "regexp" variable but don\'t have any regexp'
).format(variable.path)
raise DictConsistencyError(msg, 66, variable.xmlfiles)

View file

@ -9,7 +9,7 @@ Cadoles (http://www.cadoles.com)
Copyright (C) 2019-2021
Silique (https://www.silique.fr)
Copyright (C) 2022-2024
Copyright (C) 2022-2026
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,10 +25,20 @@ 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/>.
"""
from rougail.i18n import _
from rougail.error import DictConsistencyError
from rougail.object_model import Calculation, VariableCalculation
from tiramisu.error import display_list
from rougail.i18n import _
from rougail.utils import calc_multi_for_type_variable
from rougail.error import DictConsistencyError
from rougail.convert.object_model import (
Calculation,
VariableCalculation,
VariableParam,
IndexCalculation,
JinjaCalculation,
)
from rougail.tiramisu import display_xmlfiles, RENAME_TYPE
from warnings import warn
class Walk:
@ -41,8 +51,6 @@ class Walk:
for path in self.objectspace.variables:
yield self.objectspace.paths[path]
# yield from get_variables(self.objectspace)
def get_families(self):
"""Iter all families from the objectspace"""
for path in self.objectspace.families:
@ -62,105 +70,219 @@ class Annotator(Walk): # pylint: disable=R0903
if not objectspace.paths:
return
self.objectspace = objectspace
if self.objectspace.main_namespace:
self.forbidden_name = [self.objectspace.main_namespace]
for extra in self.objectspace.extra_dictionaries:
self.forbidden_name.append(extra)
else:
self.forbidden_name = []
# default type inference from a default value with :term:`basic types`
self.basic_types = {
str: "string",
int: "number",
int: "integer",
bool: "boolean",
float: "float",
}
self.verify_secret_managers()
self.verify_choices()
self.convert_variable()
self.convert_test()
self.convert_examples()
self.convert_help()
def verify_secret_managers(self):
for variable in self.get_variables():
if not variable.secret_manager:
continue
path = variable.path
if variable.type not in ["unix_user", "secret"]:
msg = _(
'only "unix_user" or "secret" variable type can have "secret_manager" attribute, but "{0}" has type "{1}"'
)
raise DictConsistencyError(
msg.format(path, variable.type), 56, variable.xmlfiles
)
if variable.multi and path not in self.objectspace.leaders:
msg = _(
'the variable "{0}" has attribute "secret_manager" but is a multi variable'
)
raise DictConsistencyError(msg.format(path), 57, variable.xmlfiles)
if variable.default is not None:
msg = _(
'the variable "{0}" has attribute "secret_manager" so must not have default value'
)
raise DictConsistencyError(msg.format(path), 59, variable.xmlfiles)
def convert_variable(self):
"""convert variable"""
for variable in self.get_variables():
if variable.version != "1.0":
if variable.type == "symlink":
continue
self._convert_variable_inference(variable)
for variable in self.get_variables():
if variable.type == "symlink":
continue
if variable.version != "1.0":
self._default_variable_copy_informations(variable)
if variable.multi is None:
variable.multi = False
if variable.type is None:
variable.type = "string"
self.objectspace.informations.add(variable.path, "type", variable.type)
self._convert_variable_inference(variable)
self._convert_variable_multi(variable)
for variable in self.get_variables():
if variable.type == "symlink":
continue
if variable.type in RENAME_TYPE:
warning = f'the variable "{ variable.path }" has a depreciated type "{variable.type}", please use "{RENAME_TYPE[variable.type]}" instead in {display_xmlfiles(variable.xmlfiles)}'
warn(
warning,
DeprecationWarning,
)
variable.type = RENAME_TYPE[variable.type]
if variable.type == "cidr":
warning = f'the variable "{ variable.path }" has a depreciated type "{variable.type}", please use type "ip" with attribute cidr=True instead in {display_xmlfiles(variable.xmlfiles)}'
warn(
warning,
DeprecationWarning,
)
if variable.type == "network_cidr":
warning = f'the variable "{ variable.path }" has a depreciated type "{variable.type}", please use type "network" with attribute cidr=True instead in {display_xmlfiles(variable.xmlfiles)}'
warn(
warning,
DeprecationWarning,
)
self.objectspace.informations.add(
variable.path, "ymlfiles", variable.xmlfiles
)
if variable.version != "1.0" and variable.type is None:
if isinstance(variable.default, IndexCalculation):
variable.type = "integer"
elif isinstance(variable.default, VariableCalculation):
calculated_variable_path, calculated_variable, identifier = (
variable.default.get_variable(self.objectspace, variable.path)
)
if calculated_variable is not None:
self._default_variable_copy_informations(
variable, calculated_variable
)
self._convert_variable(variable)
if variable.multi and variable.params:
indexes_to_remove = []
for idx, param in enumerate(variable.params):
if param.key == "multi_length":
jinja = f'{{% if var | length != {param.value} %}}{_("{0} values needed, but there are {{{{ var | length }}}}").format(param.value)}{{% endif %}}'
description = _("needs exactly {0} values").format(param.value)
elif param.key == "multi_max_length":
jinja = f'{{% if var | length > {param.value} %}}{_("a maximum of {0} values are needed, but there are {{{{ var | length }}}}").format(param.value)}{{% endif %}}'
description = _("needs a maximum of {0} values").format(
param.value
)
elif param.key == "multi_min_length":
jinja = f'{{% if var | length < {param.value} %}}{_("a minimum of {0} values are needed, but there are {{{{ var | length }}}}").format(param.value)}{{% endif %}}'
description = _("needs a minimum of {0} values").format(
param.value
)
else:
continue
indexes_to_remove.append(idx)
if variable.validators is None:
variable.validators = []
variable.validators.append(
JinjaCalculation(
inside_list=True,
version=variable.version,
xmlfiles=variable.xmlfiles,
attribute_name="validators",
namespace=variable.namespace,
jinja=jinja,
description=description,
params=[
VariableParam(
variable.path,
"validators",
False,
variable.xmlfiles,
key="var",
namespace=variable.namespace,
type="variable",
variable=variable.path,
whole=True,
)
],
)
)
for idx in reversed(indexes_to_remove):
variable.params.pop(idx)
if variable.secret_manager:
self.objectspace.properties.add(variable.path, "novalidator", True)
def _convert_variable_inference(
self,
variable,
) -> None:
# variable has no type
if variable.type is None:
# choice type inference from the `choices` attribute
if variable.choices is not None:
variable.type = "choice"
elif variable.regexp is not None:
variable.type = "regexp"
elif variable.default not in [None, []]:
if isinstance(variable.default, list):
tested_value = variable.default[0]
else:
tested_value = variable.default
variable.type = self.basic_types.get(type(tested_value), None)
# variable has no multi attribute
if variable.multi is None and not (
variable.type is None and isinstance(variable.default, VariableCalculation)
):
if variable.path in self.objectspace.leaders:
variable.multi = True
if variable.type is not None:
return
# choice type inference from the `choices` attribute
if variable.choices is not None:
variable.type = "choice"
elif variable.regexp is not None:
variable.type = "regexp"
elif variable.default not in [None, []]:
if isinstance(variable.default, list):
tested_value = variable.default[0]
else:
variable.multi = isinstance(variable.default, list)
tested_value = variable.default
variable.type = self.basic_types.get(type(tested_value), None)
def _convert_variable_multi(
self,
variable,
) -> None:
# variable has no multi attribute
if variable.multi is not None:
return
if variable.path in self.objectspace.leaders:
variable.multi = self.objectspace.multis[variable.path] = True
elif variable.version != "1.0" and isinstance(
variable.default, VariableCalculation
):
calculated_variable_path, calculated_variable, identifier = (
variable.default.get_variable(self.objectspace, variable.path)
)
if calculated_variable is not None:
if calculated_variable.multi is None:
if (
isinstance(calculated_variable.default, VariableCalculation)
and variable.path == calculated_variable.path
):
msg = _(
'the "{0}" default value is a calculation with itself'
).format(variable.path)
raise DictConsistencyError(msg, 75, variable.xmlfiles)
self._convert_variable_multi(calculated_variable)
variable.multi = calc_multi_for_type_variable(
variable,
calculated_variable_path,
calculated_variable,
self.objectspace,
)[1]
if (
calculated_variable.path in self.objectspace.followers
and variable.mandatory is calculated_variable.mandatory is False
and calculated_variable.path.rsplit(".", 1)[0]
!= variable.path.rsplit(".", 1)[0]
):
variable.empty = False
else:
variable.multi = isinstance(variable.default, list)
def _default_variable_copy_informations(
self,
variable,
calculated_variable,
) -> None:
# if a variable has a variable as default value, that means the type/params or multi should has same value
if variable.type is not None or not isinstance(
variable.default, VariableCalculation
):
return
# copy type and params
calculated_variable_path = variable.default.variable
calculated_variable, identifier = self.objectspace.paths.get_with_dynamic(
calculated_variable_path,
variable.default.path_prefix,
variable.path,
variable.version,
variable.namespace,
variable.xmlfiles,
)
if calculated_variable is None:
return
variable.type = calculated_variable.type
if variable.params is None and calculated_variable.params is not None:
variable.params = calculated_variable.params
# copy multi attribut
if variable.multi is None:
calculated_path = calculated_variable.path
if (
calculated_path in self.objectspace.leaders
and variable.path in self.objectspace.followers
and calculated_path.rsplit(".")[0] == variable.path.rsplit(".")[0]
):
variable.multi = False
else:
variable.multi = calculated_variable.multi
if variable.type == "choice" and variable.choices is None:
variable.choices = calculated_variable.choices
if isinstance(variable.choices, VariableCalculation):
variable.choices = variable.choices.model_copy()
variable.choices.variable = self.objectspace.paths.get_full_path(
variable.choices.variable,
calculated_variable.path,
)
if variable.type == "regexp" and variable.regexp is None:
variable.regexp = calculated_variable.regexp
def _convert_variable(
self,
@ -169,6 +291,10 @@ class Annotator(Walk): # pylint: disable=R0903
# variable without description: description is the name
if not variable.description:
variable.description = variable.name
self.objectspace.forced_descriptions.append(variable.path)
if variable.type is None:
variable.type = "string"
self.objectspace.informations.add(variable.path, "type", variable.type)
if variable.path in self.objectspace.followers:
if not variable.multi:
self.objectspace.multis[variable.path] = True
@ -176,15 +302,6 @@ class Annotator(Walk): # pylint: disable=R0903
self.objectspace.multis[variable.path] = "submulti"
elif variable.multi:
self.objectspace.multis[variable.path] = True
if variable.path in self.objectspace.leaders:
if not self.objectspace.multis.get(variable.path, False):
variable.multi = self.objectspace.multis[variable.path] = True
family = self.objectspace.paths[variable.path.rsplit(".", 1)[0]]
if variable.hidden:
family.hidden = variable.hidden
# elif family.hidden:
# variable.hidden = family.hidden
variable.hidden = None
if variable.regexp is not None and variable.type != "regexp":
msg = _(
'the variable "{0}" has regexp attribut but has not the "regexp" type'

View file

@ -1,497 +0,0 @@
"""
Config file for Rougail
Created by:
EOLE (http://eole.orion.education.fr)
Copyright (C) 2005-2018
Forked by:
Cadoles (http://www.cadoles.com)
Copyright (C) 2019-2021
Silique (https://www.silique.fr)
Copyright (C) 2022-2024
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/>.
"""
from pathlib import Path
from tiramisu import Config
from ruamel.yaml import YAML
from .utils import _, load_modules, normalize_family
from .convert import RougailConvert
RENAMED = {
"dictionaries_dir": "main_dictionaries",
"variable_namespace": "main_namespace",
"functions_file": "functions_files",
}
NOT_IN_TIRAMISU = {
"custom_types": {},
}
SUBMODULES = None
def get_sub_modules():
global SUBMODULES
if SUBMODULES is None:
SUBMODULES = {}
for submodule in Path(__file__).parent.iterdir():
if submodule.name.startswith("_") or not submodule.is_dir():
continue
config_file = submodule / "config.py"
if config_file.is_file():
SUBMODULES[submodule.name] = load_modules(
"rougail." + submodule.name + ".config", str(config_file)
)
return SUBMODULES
def get_level(module):
return module["level"]
class _RougailConfig:
def __init__(self, backward_compatibility: bool, root, extra_vars: dict):
self.backward_compatibility = backward_compatibility
self.root = root
self.config = Config(
self.root,
)
self.config.property.read_only()
self.extra_vars = extra_vars
self.not_in_tiramisu = NOT_IN_TIRAMISU | extra_vars
for variable, default_value in self.not_in_tiramisu.items():
if not isinstance(default_value, str):
default_value = default_value.copy()
setattr(self, variable, default_value)
def copy(self):
rougailconfig = _RougailConfig(
self.backward_compatibility, self.root, self.extra_vars
)
rougailconfig.config.value.importation(self.config.value.exportation())
rougailconfig.config.property.importation(self.config.property.exportation())
rougailconfig.config.property.read_only()
for variable in self.not_in_tiramisu:
value = getattr(self, variable)
if not isinstance(value, str):
value = value.copy()
setattr(rougailconfig, variable, value)
return rougailconfig
def __setitem__(
self,
key,
value,
) -> None:
if key in self.not_in_tiramisu:
setattr(self, key, value)
else:
self.config.property.read_write()
if key == "export_with_import":
key = "not_export_with_import"
key = RENAMED.get(key, key)
option = self.config.option(key)
if option.isoptiondescription() and option.isleadership():
leader = list(value)
option.leader().value.reset()
option.leader().value.set(leader)
follower = option.followers()[0]
for idx, val in enumerate(value.values()):
self.config.option(follower.path(), idx).value.set(val)
elif key == "not_export_with_import":
option.value.set(not value)
else:
option.value.set(value)
self.config.property.read_only()
def __getitem__(
self,
key,
) -> None:
if key in self.not_in_tiramisu:
return getattr(self, key)
if key == "export_with_import":
key = "not_export_with_import"
option = self.config.option(key)
if option.isoptiondescription() and option.isleadership():
return self.get_leadership(option)
ret = self.config.option(key).value.get()
if key == "not_export_with_import":
return not ret
return ret
def get_leadership(self, option) -> dict:
leader = None
followers = []
for opt, value in option.value.get().items():
if opt.issymlinkoption():
continue
if leader is None:
leader = value
else:
followers.append(value)
return dict(zip(leader, followers))
def parse(self, config) -> str:
for option in config:
if option.isoptiondescription():
yield from self.parse(option)
elif not option.issymlinkoption():
yield f"{option.path()}: {option.value.get()}"
def __repr__(self):
self.config.property.read_write()
try:
values = "\n".join(self.parse(self.config))
except Exception as err:
values = str(err)
self.config.property.read_only()
return values
class FakeRougailConvert(RougailConvert):
def __init__(
self,
add_extra_options: bool,
) -> None:
self.add_extra_options = add_extra_options
super().__init__({})
def load_config(self) -> None:
self.sort_dictionaries_all = False
self.main_namespace = None
self.suffix = ""
self.custom_types = {}
self.functions_files = []
self.modes_level = []
self.extra_annotators = []
self.base_option_name = "baseoption"
self.export_with_import = True
self.internal_functions = []
self.plugins = ["structural_commandline"]
self.add_extra_options = self.add_extra_options
def get_rougail_config(
*,
backward_compatibility: bool = True,
add_extra_options: bool = True,
) -> _RougailConfig:
if backward_compatibility:
main_namespace_default = "rougail"
else:
main_namespace_default = "null"
rougail_options = f"""default_dictionary_format_version:
description: Dictionary format version by default, if not specified in dictionary file
alternative_name: v
choices:
- '1.0'
- '1.1'
mandatory: false
main_dictionaries:
description: 'Directories where dictionary files are placed'
type: unix_filename
alternative_name: m
params:
allow_relative: True
test_existence: True
types:
- directory
multi: true
sort_dictionaries_all:
description: Sort dictionaries from differents directories
negative_description: Sort dictionaries directory by directory
default: false
main_namespace:
description: Main namespace name
default: {main_namespace_default}
alternative_name: s
mandatory: false
extra_dictionaries:
description: Extra namespaces
type: leadership
disabled:
variable: main_namespace
when: null
names:
description: 'Extra namespace name'
alternative_name: xn
multi: true
mandatory: false
directories:
description: Directories where extra dictionary files are placed
alternative_name: xd
type: unix_filename
params:
allow_relative: true
test_existence: true
types:
- directory
multi: true
upgrade:
description: Update dictionaries to newest Rougail format version
negative_description: Do not update dictionaries to newest Rougail format version
default: false
upgrade_options:
description: Update informations
disabled:
variable: upgrade
when: false
main_dictionaries:
description: 'Directories where dictionary files will be placed'
default:
variable: __.main_dictionaries
extra_dictionary:
description: 'Directories where extra files will be placed'
type: unix_filename
params:
allow_relative: true
test_existence: true
types:
- directory
disabled:
variable: __.main_namespace
when: null
functions_files:
description: File with functions
alternative_name: c
type: unix_filename
params:
allow_relative: true
test_existence: true
types:
- file
multi: true
mandatory: false
modes_level:
description: All modes level available
multi: true
mandatory: false
"""
if backward_compatibility:
rougail_options += """
default:
- basic
- standard
- advanced
"""
rougail_options += """
default_family_mode:
description: Default mode for a family
default:
jinja: |
{% if modes_level %}
{{ modes_level[0] }}
{% endif %}
disabled:
jinja: |
{% if not modes_level %}
No mode
{% endif %}
validators:
- type: jinja
jinja: |
{% if default_family_mode not in modes_level %}
not in modes_level ({modes_level})
{% endif %}
commandline: false
default_variable_mode:
description: Default mode for a variable
default:
jinja: |
{% if modes_level %}
{% if modes_level | length == 1 %}
{{ modes_level[0] }}
{% else %}
{{ modes_level[1] }}
{% endif %}
{% endif %}
disabled:
jinja: |
{% if not modes_level %}
No mode
{% endif %}
validators:
- type: jinja
jinja: |
{% if default_variable_mode not in modes_level %}
not in modes_level ({modes_level})
{% endif %}
commandline: false
base_option_name:
description: Option name for the base option
default: baseoption
commandline: false
not_export_with_import:
description: In cache file, do not importation of Tiramisu and other dependencies
default: false
commandline: false
tiramisu_cache:
description: Tiramisu cache filename
alternative_name: t
type: unix_filename
mandatory: false
params:
allow_relative: true
internal_functions:
description: Name of internal functions that we can use as a function
multi: true
mandatory: false
commandline: false
extra_annotators:
description: Name of extra annotators
multi: true
mandatory: false
commandline: false
plugins:
description: Name of Rougail plugins
multi: true
mandatory: false
commandline: false
suffix:
description: Suffix add to generated option name
default: ''
mandatory: false
commandline: false
"""
processes = {
"structural": [],
"output": [],
"user data": [],
}
for module in get_sub_modules().values():
data = module.get_rougail_config()
processes[data["process"]].append(data)
# reorder
for process in processes:
processes[process] = list(sorted(processes[process], key=get_level))
rougail_process = """step: # Load and exporter steps
disabled:
variable: upgrade"""
for process in processes:
if processes[process]:
objects = processes[process]
rougail_process += """
{NAME}:
description: Select for {NAME}
alternative_name: {NAME[0]}
choices:
""".format(
NAME=normalize_family(process),
)
for obj in objects:
rougail_process += f" - {obj['name']}\n"
if process == "structural":
rougail_process += " commandline: false"
elif process == "user data":
rougail_process += """ multi: true
mandatory: false
"""
hidden_outputs = [
process["name"]
for process in processes["output"]
if not process.get("allow_user_data", True)
]
if hidden_outputs:
rougail_process += """ hidden:
type: jinja
jinja: |
"""
for hidden_output in hidden_outputs:
rougail_process += """ {% if _.output == 'NAME' %}
Cannot load user data for NAME output
{% endif %}
""".replace(
"NAME", hidden_output
)
elif objects:
rougail_process += " default: {DEFAULT}".format(
DEFAULT=objects[0]["name"]
)
else:
if process == 'output':
prop = 'hidden'
else:
prop = 'disabled'
rougail_process += """
{NAME}:
description: Select for {NAME}
mandatory: false
{PROP}: true
multi: true
default: ["You haven't installed \\\"{NAME}\\\" package for rougail"]
validators:
- jinja: Please install a rougail-{NAME}-* package.
""".format(
NAME=normalize_family(process),
PROP=prop,
)
rougail_options += rougail_process
convert = FakeRougailConvert(add_extra_options)
convert._init()
convert.namespace = None
convert.parse_root_file(
"rougail.config",
"",
"1.1",
YAML().load(rougail_options),
)
extra_vars = {}
for process in processes:
for obj in processes[process]:
if "extra_vars" in obj:
extra_vars |= obj["extra_vars"]
if not "options" in obj:
continue
convert.parse_root_file(
f'rougail.config.{obj["name"]}',
"",
"1.1",
YAML().load(obj["options"]),
)
tiram_obj = convert.save(None)
optiondescription = {}
exec(tiram_obj, {}, optiondescription) # pylint: disable=W0122
return _RougailConfig(
backward_compatibility,
optiondescription["option_0"],
extra_vars=extra_vars,
)
RougailConfig = get_rougail_config()

View file

@ -0,0 +1,604 @@
"""
Config file for Rougail
Created by:
EOLE (http://eole.orion.education.fr)
Copyright (C) 2005-2018
Forked by:
Cadoles (http://www.cadoles.com)
Copyright (C) 2019-2021
Silique (https://www.silique.fr)
Copyright (C) 2022-2026
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/>.
"""
from pathlib import Path
from tiramisu import Config
from tiramisu.error import display_list
from ruamel.yaml import YAML
from ..utils import _, load_modules
from ..tiramisu import normalize_family
from ..convert import RougailConvert
from ..convert.object_model import get_convert_option_types
RENAMED = {
"dictionaries_dir": "main_structural_directories",
"main_dictionaries": "main_structural_directories",
"variable_namespace": "main_namespace",
"functions_file": "functions_files",
}
NOT_IN_TIRAMISU = {
"custom_types": {},
}
SUBMODULES = None
def get_sub_modules():
global SUBMODULES
if SUBMODULES is None:
SUBMODULES = {}
for submodule in Path(__file__).parent.parent.iterdir():
if submodule.name.startswith("_") or not submodule.is_dir():
continue
config_file = submodule / "config.py"
if config_file.is_file():
SUBMODULES[submodule.name] = load_modules(
"rougail." + submodule.name + ".config", str(config_file)
)
return SUBMODULES
def get_level(module):
return float(module["level"]) + {
"structural": 0.1,
"user data": 0.2,
"output": 0.3,
}.get(module["process"])
class _RougailConfig:
def __init__(self, backward_compatibility: bool, add_extra_options: bool):
self.backward_compatibility = backward_compatibility
self.add_extra_options = add_extra_options
self.root = None
def copy(self, backward_compatibility=None):
if not self.root:
self.generate_config()
config = self.config.config.copy()
config.value.importation(self.config.value.exportation())
config.property.importation(
self.config.property.exportation()
)
config.property.read_only()
if backward_compatibility is None:
backward_compatibility = self.backward_compatibility
rougailconfig = _RougailConfig(backward_compatibility, self.add_extra_options)
rougailconfig.root = self.root
rougailconfig.config = config
rougailconfig.extra_vars = self.extra_vars.copy()
rougailconfig.not_in_tiramisu = NOT_IN_TIRAMISU | rougailconfig.extra_vars
for variable in self.not_in_tiramisu:
value = getattr(self, variable)
if not isinstance(value, str):
value = value.copy()
setattr(rougailconfig, variable, value)
return rougailconfig
def generate_config(self):
self.root, extra_vars = _rougail_config(
self.backward_compatibility, self.add_extra_options
)
self.config = Config(
self.root,
)
self.extra_vars = extra_vars
self.not_in_tiramisu = NOT_IN_TIRAMISU | extra_vars
for variable, default_value in self.not_in_tiramisu.items():
if not isinstance(default_value, str):
default_value = default_value.copy()
setattr(self, variable, default_value)
self.config.property.read_only()
def __setitem__(
self,
key,
value,
) -> None:
if self.root is None:
self.generate_config()
if key in self.not_in_tiramisu:
setattr(self, key, value)
else:
self.config.property.read_write()
key = RENAMED.get(key, key)
option = self.config.option(key)
if option.isoptiondescription() and option.isleadership():
if isinstance(value, RConfigLeadership):
leader = value.leader
followers = value.followers
else:
leader = list(value)
followers = value.values()
option.leader().value.reset()
option.leader().value.set(leader)
follower = option.followers()[0]
for idx, val in enumerate(followers):
self.config.option(follower.path(), idx).value.set(val)
else:
option.value.set(value)
self.config.property.read_only()
def __getitem__(
self,
key,
) -> None:
if self.root is None:
self.generate_config()
if key in self.not_in_tiramisu:
return getattr(self, key)
option = self.config.option(key)
if option.isoptiondescription() and option.isleadership():
return self.get_leadership(option)
ret = self.config.option(key).value.get()
return ret
def __contains__(
self,
key,
) -> None:
try:
self.__getitem__(key)
except AttributeError:
return False
return True
def get_leadership(self, option) -> dict:
leader = None
followers = []
for opt, value in option.value.get().items():
if opt.issymlinkoption():
continue
if leader is None:
leader = value
else:
followers.append(value)
return RConfigLeadership(self.config, option, leader, followers)
def parse(self, config) -> str:
for option in config:
if option.isoptiondescription():
yield from self.parse(option)
elif not option.issymlinkoption():
yield f"{option.path()}: {option.value.get()}"
def __repr__(self):
if self.root is None:
self.generate_config()
self.config.property.read_write()
try:
values = "\n".join(self.parse(self.config))
except Exception as err:
values = str(err)
self.config.property.read_only()
return values
class RConfigLeadership:
def __init__(self, config, option, leader, followers):
self.config = config
self.option = option
self.leader = leader
self.followers = followers
def items(self):
return dict(zip(self.leader, self.followers)).items()
def __setitem__(
self,
key,
value,
) -> None:
self.config.property.read_write()
names = self.option.option("names")
leader = names.value.get()
leader.append(key)
names.value.set(leader)
directories = self.option.option("directories", len(leader) - 1)
directories.value.set(value)
self.leader.append(key)
self.followers.append(value)
self.config.property.read_only()
def __getitem__(self, key):
option = self.option.option(key)
if option.isleader():
return option.value.get()
return [option.index(idx).value.get() for idx in range(option.value.len())]
def __repr__(self):
return dict(zip(self.leader, self.followers))
class StaticRougailConvert(RougailConvert):
def __init__(
self,
add_extra_options: bool,
rougailconfig: dict={},
) -> None:
self.add_extra_options = add_extra_options
super().__init__(rougailconfig)
def load_config(self) -> None:
self.sort_structural_files_all = False
self.main_namespace = None
self.suffix = ""
self.custom_types = {}
self.functions_files = []
self.modes_level = []
self.extra_annotators = []
self.base_option_name = "baseoption"
self.export_with_import = True
self.internal_functions = []
self.force_optional = False
self.structurals = ["commandline"]
self.user_data = []
self.output = None
self.tiramisu_cache = False
# self.tiramisu_cache = "a.py"
self.load_unexist_redefine = False
def get_common_rougail_config(
*,
backward_compatibility=True,
) -> str:
rougail_options = f"""default_structural_format_version:
description: {_('Default version of the structural file format')}
help: {_('This value is only used if the version is not set in the structural file')}
alternative_name: v
choices:
- '1.0'
- '1.1'
mandatory: false
types:
description: {_("File with personalize types")}
help: {_("This file contains personalize types in Rougail format for structure files")}
type: unix_filename
params:
allow_relative: true
test_existence: true
multi: true
mandatory: false
functions_files:
description: {_("File with functions")}
help: {_("This file contains filters and additional Jinja2 functions usable in structure files")}
type: unix_filename
params:
allow_relative: true
test_existence: true
types:
- file
multi: true
mandatory: false
modes_level:
description: {_("All modes level available")}
multi: true
mandatory: false
"""
if backward_compatibility:
rougail_options += """ default:
- basic
- standard
- advanced
"""
rougail_options += f"""
default_family_mode:
description: {_("Default mode for a family")}
default:
jinja: |
{{% if modes_level %}}
{{{{ modes_level[0] }}}}
{{% endif %}}
description: {_('the first one defined in "modes_level"')}
disabled:
jinja: |
{{% if not modes_level %}}
No mode
{{% endif %}}
description: {_('when no mode is defined in "modes_level"')}
validators:
- type: jinja
jinja: |
{{% if default_family_mode not in modes_level %}}
not in modes_level ({{modes_level}})
{{% endif %}}
description: {_('this mode must be available in "modes_level"')}
commandline: false
default_variable_mode:
description: {_("Default mode for a variable")}
default:
jinja: |
{{% if modes_level %}}
{{% if modes_level | length == 1 %}}
{{{{ modes_level[0] }}}}
{{% else %}}
{{{{ modes_level[1] }}}}
{{% endif %}}
{{% endif %}}
description: {_('if the variable "modes_level" is defined, the default value is the second available element, otherwise, the first')}
disabled:
jinja: |
{{% if not modes_level %}}
No mode
{{% endif %}}
description: {_('when no mode is defined in "modes_level"')}
validators:
- type: jinja
jinja: |
{{% if default_variable_mode not in modes_level %}}
not in modes_level ({{modes_level}})
{{% endif %}}
description: {_('this mode must be available in "modes_level"')}
commandline: false
base_option_name:
description: {_("Option name for the base option")}
default: baseoption
commandline: false
export_with_import:
description: {_("In cache file, do not importation of Tiramisu and other dependencies")}
default: true
commandline: false
tiramisu_cache:
description: {_("Store Tiramisu cache filename")}
help: "{_("This file contains the Tiramisu instructions used internally to load the variables.\n\nThis file can be used for debugging")}"
alternative_name: t
type: unix_filename
mandatory: false
params:
allow_relative: true
types:
- file
internal_functions:
description: {_("Name of internal functions that we can use as a function")}
multi: true
mandatory: false
commandline: false
extra_annotators:
description: {_("Name of extra annotators")}
multi: true
mandatory: false
commandline: false
suffix:
description: {_("Suffix add to generated options name")}
default: ''
mandatory: false
commandline: false
force_optional:
description: {_("Every variables in calculation are optionals")}
default: False
load_unexist_redefine:
description: {_("Loads redefine variables even if there don't already exists")}
commandline: false
default: False
secret_manager: # {_("The secret manager")}
pattern:
description: {_("The secret pattern to constructing the name of the item searched for in the secret manager")}
help: {_("The pattern is in Jinja2 format")}
default: "{{{{ project }}}} - {{{{ environment }}}} - {{{{ service }}}} - {{{{ user }}}}"
"""
processes = {
"structural": [],
"user data": [],
"output": [],
}
processes_tr = {"structural": _("structural"),
"user data": _("user datas"),
"output": _("output"),
}
processes_empty = []
for module in get_sub_modules().values():
data = module.get_rougail_config(backward_compatibility=backward_compatibility)
if data["process"]:
processes[data["process"]].append(data)
else:
processes_empty.append(data["options"])
# reorder
for process in processes:
processes[process] = list(sorted(processes[process], key=get_level))
rougail_process = "step: # Load and exporter steps"
for process in processes:
if processes[process]:
objects = processes[process]
process_name = normalize_family(process)
tr_process_name = processes_tr[process]
rougail_process += f"""
{process_name}:
description: {_('Select for {0}').format(tr_process_name)}
"""
if process != "structural":
rougail_process += """ alternative_name: {NAME[0]}
""".format(
NAME=normalize_family(process),
)
rougail_process += """ choices:
"""
for obj in objects:
rougail_process += f" - {obj['name']}\n"
if process == "structural":
rougail_process += """ commandline: false
multi: true
default:
- directory
"""
elif process == "user data":
rougail_process += """ multi: true
mandatory: false"""
hidden_outputs = [
process["name"]
for process in processes["output"]
if not process.get("allow_user_data", True)
]
if hidden_outputs:
rougail_process += """
disabled:
type: jinja
jinja: |
"""
for hidden_output in hidden_outputs:
rougail_process += """ {% if _.output is not propertyerror and _.output == 'NAME' %}
Cannot load user data for NAME output
{% endif %}
""".replace(
"NAME", hidden_output
)
rougail_process += f""" description: {_('outputs {0} did not allow user data')}
""".format(display_list(hidden_outputs, add_quote=True, separator="or"))
elif objects:
rougail_process += " default: {DEFAULT}".format(
DEFAULT=objects[0]["name"]
)
else:
if process == "output":
prop = "hidden"
else:
prop = "disabled"
rougail_process += """
{NAME}:
description: Select for {NAME}
mandatory: false
{PROP}: true
multi: true
default: ["You haven't installed \\\"{NAME}\\\" package for rougail"]
validators:
- jinja: Please install a rougail-{NAME}-* package.
""".format(
NAME=normalize_family(process),
PROP=prop,
)
rougail_process += f"""
define_default_params: false # {_('Override default parameters for option type')}
default_params:
description: {_("Default parameters for option type")}
disabled:
variable: _.define_default_params
when: false
"""
for typ, typ_description, params in get_convert_option_types():
rougail_process += f"""
{typ}: # {typ_description}
"""
for key, key_type, description, multi, value, choices in params:
rougail_process += f"""
{key}:
"""
if description:
rougail_process += f""" description: "{description}"
"""
rougail_process += f""" type: {key_type}
multi: {multi}
mandatory: false
default: {value}
"""
if choices:
rougail_process += " choices:\n"
for choice in choices:
rougail_process += f" - {choice}\n"
rougail_options += rougail_process
return processes, processes_empty, rougail_options
def _rougail_config(
backward_compatibility: bool = True,
add_extra_options: bool = True,
) -> "OptionDescription":
processes, processes_empty, rougail_options = get_common_rougail_config(backward_compatibility=backward_compatibility)
convert = StaticRougailConvert(add_extra_options)
convert.init()
convert.namespace = None
convert.parse_root_file(
["rougail.config"],
"",
"1.1",
YAML().load(rougail_options),
)
for process_empty in processes_empty:
convert.parse_root_file(
["rougail.config"],
"",
"1.1",
YAML().load(process_empty),
)
extra_vars = {}
objects = []
for obj in sorted(
[obj for objects in processes.values() for obj in objects], key=get_level
):
if "extra_vars" in obj:
extra_vars |= obj["extra_vars"]
if not "options" in obj:
continue
if not isinstance(obj["options"], list):
options = [obj["options"]]
else:
options = obj["options"]
for option in options:
convert.parse_root_file(
[f'rougail.config.{obj["name"]}'],
"",
"1.1",
YAML().load(option),
)
tiram_obj = convert.save()
optiondescription = {}
exec(tiram_obj, {}, optiondescription) # pylint: disable=W0122
return optiondescription["option_0"], extra_vars
def get_rougail_config(
*,
backward_compatibility: bool = True,
add_extra_options: bool = True,
) -> _RougailConfig:
return _RougailConfig(
backward_compatibility,
add_extra_options,
)
RougailConfig = get_rougail_config()

View file

@ -0,0 +1,79 @@
"""Silique (https://www.silique.fr)
Copyright (C) 2022-2026
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/>.
"""
from pathlib import Path
from typing import Optional
from tiramisu import Config
from warnings import warn
from .convert import RougailConvert
from ..types import rougail_type
from ..config import RougailConfig
from ..user_data import UserData
from ..tiramisu import tiramisu_display_name
class Rougail(UserData):
"""Main Rougail object"""
def __init__(
self,
rougailconfig: Optional[RougailConfig]=None,
load_from_tiramisu_cache: bool=False,
) -> None:
if rougailconfig is None:
rougailconfig = RougailConfig
self.rougailconfig = rougailconfig
self.load_from_tiramisu_cache = load_from_tiramisu_cache and Path(self.rougailconfig["tiramisu_cache"]).is_file()
types = rougail_type(self.rougailconfig)
if not self.load_from_tiramisu_cache:
self.converted = RougailConvert(self.rougailconfig, *types)
self.config = None
def get_root_option(self):
if not self.load_from_tiramisu_cache:
tiram_obj = self.converted.save()
else:
tiramisu_cache = self.rougailconfig["tiramisu_cache"]
with open(tiramisu_cache, "r", encoding="utf-8") as tiramisu:
tiram_obj = tiramisu.read()
optiondescription = {}
custom_types = {
custom.__name__: custom
for custom in self.rougailconfig["custom_types"].values()
}
exec(tiram_obj, custom_types, optiondescription) # pylint: disable=W0122
return optiondescription["option_0"]
def run(self, *, name: Optional[str] = None):
"""Get Tiramisu Config"""
if not self.config:
self.config = Config(
self.get_root_option(),
name=name,
display_name=tiramisu_display_name,
)
self.config.property.read_write()
return self.config
def get_config(self):
warn(
"get_config is deprecated, use run instead",
DeprecationWarning,
stacklevel=2,
)
return self.run()

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

242
src/rougail/convert/path.py Normal file
View file

@ -0,0 +1,242 @@
"""
Copyright (C) 2024-2026
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/>.
"""
from typing import (
Any,
Dict,
List,
Union,
)
import logging
from re import compile, findall
from .object_model import Family, Variable
from ..error import DictConsistencyError
from ..i18n import _
from ..tiramisu import normalize_family
class Paths:
regexp_relative = compile(r"^_*\.(.*)$")
def __init__(
self,
default_namespace: str,
isolated_namespace: bool,
) -> None:
self._data: Dict[str, Union[Variable, Family]] = {}
self._dynamics: Dict[str:str] = {}
if default_namespace is not None:
default_namespace = normalize_family(default_namespace)
self.default_namespace = default_namespace
self.isolated_namespace = isolated_namespace
def has_value(self) -> bool:
return self._data != {}
def add(
self,
path: str,
data: Any,
is_dynamic: bool,
dynamic: str,
*,
force: bool = False,
) -> None:
self._data[path] = data
if not force and is_dynamic:
self._dynamics[path] = dynamic
def get_full_path(
self,
path: str,
current_path: str,
):
if "{{ suffix }}" in path:
# version 1.0 and 1.1
path = path.replace("{{ suffix }}", "{{ identifier }}")
relative, subpath = path.split(".", 1)
relative_len = len(relative)
path_len = current_path.count(".")
if path_len + 1 == relative_len:
return subpath
parent_path = current_path.rsplit(".", relative_len)[0]
return parent_path + "." + subpath
def get_with_dynamic(
self,
path: str,
current_path: str,
version: str,
namespace: str,
xmlfiles: List[str],
) -> Any:
identifier = None
if version != "1.0" and self.regexp_relative.search(path):
path = self.get_full_path(
path,
current_path,
)
# elif identifier_path:
# path = f"{identifier_path}.{path}"
dynamic = None
# version 1.0
if version == "1.0":
if not path in self._data and "{{ suffix }}" not in path:
new_path = None
current_path = None
identifiers = []
for name in path.split("."):
parent_path = current_path
if current_path:
current_path += "." + name
else:
current_path = name
if current_path in self._data:
if new_path:
new_path += "." + name
else:
new_path = name
continue
for dynamic_path in self._dynamics:
if "." in dynamic_path:
parent_dynamic, name_dynamic = dynamic_path.rsplit(".", 1)
else:
parent_dynamic = None
name_dynamic = dynamic_path
if (
parent_dynamic == parent_path
and name_dynamic.endswith("{{ identifier }}")
and name == name_dynamic.replace("{{ identifier }}", "")
):
new_path += "." + name_dynamic
break
regexp = "^" + name_dynamic.replace("{{ identifier }}", "(.*)")
finded = findall(regexp, name)
if len(finded) != 1 or not finded[0]:
continue
if finded[0] == "{{ identifier }}":
identifiers.append(None)
else:
identifiers.append(finded[0])
if new_path is None:
new_path = name_dynamic
else:
new_path += "." + name_dynamic
parent_path = dynamic_path
break
else:
if new_path:
new_path += "." + name
else:
new_path = name
path = new_path
else:
identifiers = None
elif not path in self._data:
new_path = parent_path = current_path = None
identifiers = []
for name in path.split("."):
if current_path:
current_path += "." + name
else:
current_path = name
# parent_path, name_path = path.rsplit('.', 1)
if current_path in self._data:
if new_path:
new_path += "." + name
else:
new_path = name
parent_path = current_path
continue
for dynamic_path in self._dynamics:
if "." in dynamic_path:
parent_dynamic, name_dynamic = dynamic_path.rsplit(".", 1)
else:
parent_dynamic = None
name_dynamic = dynamic_path
if (
"{{ identifier }}" not in name_dynamic
or parent_path != parent_dynamic
):
continue
regexp = "^" + name_dynamic.replace("{{ identifier }}", "(.*)")
finded = findall(regexp, name)
if len(finded) != 1 or not finded[0]:
continue
if finded[0] == "{{ identifier }}":
identifiers.append(None)
else:
identifiers.append(finded[0])
if new_path is None:
new_path = name_dynamic
else:
new_path += "." + name_dynamic
parent_path = dynamic_path
break
else:
if new_path:
new_path += "." + name
else:
new_path = name
if "{{ identifier }}" in name:
identifiers.append(None)
parent_path = current_path
path = new_path
else:
identifiers = None
if path not in self._data:
return None, None
option = self._data[path]
option_namespace = option.namespace
if (
self.isolated_namespace
and self.default_namespace not in [namespace, option_namespace]
and namespace != option_namespace
):
msg = _(
'A variable or a family located in the "{0}" namespace shall not be used in the "{1}" namespace'
).format(option_namespace, namespace)
raise DictConsistencyError(msg, 38, xmlfiles)
return option, identifiers
def __getitem__(
self,
path: str,
) -> Union[Family, Variable]:
if not path in self._data:
raise AttributeError(f"cannot find variable or family {path}")
return self._data[path]
def __contains__(
self,
path: str,
) -> bool:
return path in self._data
def __delitem__(
self,
path: str,
) -> None:
logging.info("remove empty family %s", path)
del self._data[path]
def is_dynamic(self, path: str) -> bool:
return path in self._dynamics
def get(self):
return self._data.values()

View file

@ -10,7 +10,7 @@ Cadoles (http://www.cadoles.com)
Copyright (C) 2019-2021
Silique (https://www.silique.fr)
Copyright (C) 2022-2024
Copyright (C) 2022-2026
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
@ -30,10 +30,10 @@ from typing import Optional, Union
from json import dumps
from os.path import isfile, basename
from .i18n import _
from .error import DictConsistencyError, VariableCalculationDependencyError
from .utils import normalize_family
from .object_model import Calculation, CONVERT_OPTION
from ..i18n import _
from ..error import DictConsistencyError, VariableCalculationDependencyError
from ..tiramisu import normalize_family, CONVERT_OPTION
from .object_model import Calculation
class BaseElt: # pylint: disable=R0903
@ -73,12 +73,7 @@ class TiramisuReflector:
"from tiramisu import *",
"from tiramisu.setting import ALLOWED_LEADER_PROPERTIES",
"from re import compile as re_compile",
]
)
if self.objectspace.export_with_import:
self.text["header"].extend(
[
"from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription"
"from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription",
]
)
if funcs_paths:
@ -87,15 +82,15 @@ class TiramisuReflector:
continue
self.text["header"].append(f"load_functions('{funcs_path}')")
if self.objectspace.export_with_import:
if objectspace.main_namespace:
self.text["header"].extend(
[
"try:",
" groups.namespace",
"except:",
" groups.addgroup('namespace')",
]
)
# if self.objectspace.has_namespace:
self.text["header"].extend(
[
"try:",
" groups.namespace",
"except:",
" groups.addgroup('namespace')",
]
)
for mode in self.objectspace.modes_level:
self.text["header"].append(f'ALLOWED_LEADER_PROPERTIES.add("{mode}")')
self.make_tiramisu_objects()
@ -131,33 +126,6 @@ class TiramisuReflector:
elt,
self,
)
# else:
# path_prefixes = self.objectspace.paths.get_path_prefixes()
# for path_prefix in path_prefixes:
# space = self.objectspace.space.variables[path_prefix]
# self.set_name(space)
# baseprefix = Family(
# space,
# self,
# )
# basefamily.add(baseprefix)
# for elt in self.reorder_family(space):
# self.populate_family(
# baseprefix,
# elt,
# )
# if not hasattr(baseprefix.elt, "information"):
# baseprefix.elt.information = self.objectspace.information(
# baseprefix.elt.xmlfiles
# )
# for key, value in self.objectspace.paths.get_providers_path(
# path_prefix
# ).items():
# setattr(baseprefix.elt.information, key, value)
# for key, value in self.objectspace.paths.get_suppliers_path(
# path_prefix
# ).items():
# setattr(baseprefix.elt.information, key, value)
baseelt.name = normalize_family(self.objectspace.base_option_name)
baseelt.description = self.objectspace.base_option_name
self.reflector_objects[baseelt.path].get(
@ -253,14 +221,31 @@ class Common:
properties = []
calc_properties = []
for property_, value in values.items():
if value is True:
properties.append(self.convert_str(property_))
elif isinstance(value, list):
for val in value:
calc_properties.append(self.calculation_value(val))
else:
calc_properties.append(self.calculation_value(value))
return "frozenset({" + ", ".join(sorted(properties) + calc_properties) + "})"
if not isinstance(value, list):
value = [value]
for val in value:
ret = self.calculation_property(val)
if isinstance(ret, bool):
if ret:
properties.append(self.convert_str(property_))
elif ret is not None:
calc_properties.append(ret)
if properties or calc_properties:
return (
"frozenset({" + ", ".join(sorted(properties) + calc_properties) + "})"
)
raise Exception("ca existe alors ...")
def calculation_property(
self,
value: Union[Calculation, bool],
) -> Optional[bool]:
if isinstance(value, Calculation):
try:
return self.calculation_value(value)
except VariableCalculationDependencyError:
return None
return value
def calc_properties(
self,
@ -295,40 +280,14 @@ class Common:
):
"""Populate variable parameters"""
if not isinstance(param, dict):
if isinstance(param, str):
value = self.convert_str(param)
else:
value = param
return f"ParamValue({value})"
param = {
"type": "any",
"value": param,
}
if param["type"] == "value":
return f"ParamValue({param['value']})"
if param["type"] == "information":
# default? really?
if self.elt.multi:
default = []
else:
default = None
if "variable" in param:
if param["variable"].path == self.elt.path:
return f'ParamSelfInformation("{param["information"]}", {default})'
information_variable_path = param["variable"].path
information_variable = self.tiramisu.reflector_objects[
information_variable_path
]
if information_variable_path not in self.calls:
option_name = information_variable.get(self.calls, self.elt.path)
return f'ParamInformation("{param["information"]}", {default}, option={option_name})'
else:
information = (
f'ParamInformation("{param["information"]}", {default})'
)
information_name = self.tiramisu.get_information_name()
self.tiramisu.text["option"].append(
f"{information_name} = {information}"
)
information_variable.informations.append(information_name)
return information_name
return f'ParamInformation("{param["information"]}", {default})'
return self.build_information_param(param)
if param["type"] == "identifier":
if "identifier" in param and param["identifier"] != None:
return f"ParamIdentifier(identifier_index={param['identifier']})"
@ -336,13 +295,7 @@ class Common:
if param["type"] == "index":
return "ParamIndex()"
if param["type"] == "variable":
return self.build_option_param(
param["variable"],
param.get("propertyerror", True),
param.get("identifier"),
param.get("dynamic"),
param.get("whole", False),
)
return self.build_variable_param(param)
if param["type"] == "any":
if isinstance(param["value"], str):
value = self.convert_str(param["value"])
@ -351,25 +304,63 @@ class Common:
return "ParamValue(" + value + ")"
raise Exception("pfff")
def build_option_param(
def build_information_param(self, param: dict) -> str:
# default? really?
if self.elt.multi:
default = []
else:
default = None
if "variable" in param:
information_variable_path = param["variable"].path
if information_variable_path == self.elt.path:
return f'ParamSelfInformation("{param["information"]}", {default})'
information_variable = self.tiramisu.reflector_objects[
information_variable_path
]
if information_variable_path not in self.calls:
option_name = information_variable.get(self.calls, self.elt.path)
return f'ParamInformation("{param["information"]}", {default}, option={option_name})'
else:
# if we want to get information from the a parent family
information = f'ParamInformation("{param["information"]}", {default})'
information_name = self.tiramisu.get_information_name()
self.tiramisu.text["option"].append(
f"{information_name} = {information}"
)
information_variable.informations.append(information_name)
return information_name
return f'ParamInformation("{param["information"]}", {default})'
def build_variable_param(
self,
variable,
propertyerror,
identifier: Optional[str],
dynamic,
whole: bool,
param: dict,
) -> str:
"""build variable parameters"""
variable = param["variable"]
whole = param.get("whole", False)
dynamic = param.get("dynamic", True)
if variable.path == self.elt.path:
return f"ParamSelfOption(whole={whole})"
ret = f"ParamSelfOption(whole={whole}"
if not dynamic:
ret += ", dynamic=False"
return ret + ')'
if whole:
msg = f'variable param "{variable.path}" has whole attribute but it\'s not allowed for external variable'
raise DictConsistencyError(msg, 34, self.elt.xmlfiles)
msg = _('variable param "{0}" has whole attribute but it\'s not allowed for external variable')
raise DictConsistencyError(msg.format(variable.path), 34, self.elt.xmlfiles)
if not dynamic:
msg = _('variable param "{0}" has dynamic attribute but it\'s not allowed for external variable')
raise DictConsistencyError(msg.format(variable.path), 34, self.elt.xmlfiles)
option_name = self.tiramisu.reflector_objects[variable.path].get(
self.calls, self.elt.path
)
params = [f"{option_name}"]
identifier = param.get("identifier")
if identifier is not None:
if not self.objectspace.paths.is_dynamic(variable.path):
msg = _("internal error, {0} is not a dynamic variable").format(
variable.path
)
raise DictConsistencyError(msg, 49, self.elt.xmlfiles)
param_type = "ParamDynOption"
identifiers = []
for ident in identifier:
@ -377,10 +368,15 @@ class Common:
ident = self.convert_str(ident)
identifiers.append(str(ident))
params.append("[" + ", ".join(identifiers) + "]")
if param.get("optional", False):
params.append("optional=True")
else:
param_type = "ParamOption"
propertyerror = param.get("propertyerror", True)
if not propertyerror:
params.append("notraisepropertyerror=True")
elif propertyerror == "transitive":
params.append("raisepropertyerror=True")
return f'{param_type}({", ".join(params)})'
def calculation_value(
@ -388,12 +384,16 @@ class Common:
function,
) -> str:
"""Generate calculated value"""
child = function.to_function(self.objectspace)
child = function.to_function(self.objectspace, self.elt.path)
if isinstance(child, str):
return self.convert_str(child)
elif not isinstance(child, dict):
return child
new_args = []
kwargs = []
if "params" in child:
for key, value in child["params"].items():
if not key:
if key is None:
for val in value:
new_args.append(self.populate_param(val))
else:
@ -406,8 +406,8 @@ class Common:
if kwargs:
ret += ", kwargs={" + ", ".join(kwargs) + "}"
ret += ")"
if hasattr(child, "warnings_only"):
ret += f", warnings_only={child.warnings_only}"
if "warnings_only" in child:
ret += f", warnings_only={child['warnings_only']}"
if "help" in child:
ret += f", help_function=func['{child['help']}']"
ret = ret + ")"
@ -418,10 +418,10 @@ class Common:
datas: Union[Calculation, str, list],
return_a_tuple: bool = False,
) -> str:
if isinstance(datas, str):
return self.convert_str(datas)
if isinstance(datas, Calculation):
return self.calculation_value(datas)
datas = self.calculation_value(datas)
elif isinstance(datas, str):
datas = self.convert_str(datas)
if not isinstance(datas, list):
return datas
params = []
@ -430,9 +430,11 @@ class Common:
try:
params.append(self.calculation_value(data))
except VariableCalculationDependencyError:
pass
continue
elif isinstance(data, str):
params.append(self.convert_str(data))
elif isinstance(data, dict):
params.append(data)
else:
params.append(str(data))
if return_a_tuple:
@ -473,9 +475,14 @@ class Variable(Common):
)
return
if self.elt.type == "choice":
keys["values"] = self.populate_calculation(
self.elt.choices, return_a_tuple=True
)
try:
keys["values"] = self.populate_calculation(
self.elt.choices, return_a_tuple=True
)
if keys["values"] == "(,)":
keys["values"] = tuple()
except VariableCalculationDependencyError:
keys["values"] = tuple()
if self.elt.type == "regexp":
self.object_type = "Regexp_" + self.option_name
self.tiramisu.text["header"].append(
@ -501,6 +508,8 @@ class Variable(Common):
pass
if self.elt.validators:
keys["validators"] = self.populate_calculation(self.elt.validators)
if self.elt.warnings:
keys["warnings_only"] = True
for key, value in (
CONVERT_OPTION.get(self.elt.type, {}).get("initkwargs", {}).items()
):
@ -548,7 +557,10 @@ class Family(Common):
if self.group_type:
keys["group_type"] = self.group_type
if self.elt.type == "dynamic":
keys["identifiers"] = self.populate_calculation(self.elt.dynamic)
try:
keys["identifiers"] = self.populate_calculation(self.elt.dynamic)
except VariableCalculationDependencyError:
keys["identifiers"] = []
children = []
for path in self.objectspace.parents[self.elt.path]:
children.append(self.objectspace.paths[path])

View file

@ -9,7 +9,7 @@ Cadoles (http://www.cadoles.com)
Copyright (C) 2019-2021
Silique (https://www.silique.fr)
Copyright (C) 2022-2024
Copyright (C) 2022-2026
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,13 +26,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from .i18n import _
def display_xmlfiles(xmlfiles: list) -> str:
"""The function format xmlfiles informations to generate errors"""
if len(xmlfiles) == 1:
return '"' + xmlfiles[0] + '"'
return '"' + '", "'.join(xmlfiles[:-1]) + '"' + " and " + '"' + xmlfiles[-1] + '"'
from .tiramisu import display_xmlfiles
class ConfigError(Exception):
@ -69,10 +63,6 @@ class DictConsistencyError(Exception):
self.errno = errno
class UpgradeError(Exception):
"""Error during XML upgrade"""
## ---- generic exceptions ----
@ -81,6 +71,14 @@ class NotFoundError(Exception):
pass
class ExtensionError(Exception):
pass
class RougailWarning(UserWarning):
pass
## ---- specific exceptions ----

View file

@ -8,7 +8,7 @@ Cadoles (http://www.cadoles.com)
Copyright (C) 2019-2021
Silique (https://www.silique.fr)
Copyright (C) 2022-2024
Copyright (C) 2022-2026
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

View file

@ -1,765 +0,0 @@
"""Rougail object model
Silique (https://www.silique.fr)
Copyright (C) 2023-2024
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/>.
"""
from typing import Optional, Union, get_type_hints, Any, Literal, List, Dict, Iterator
from pydantic import (
BaseModel,
StrictBool,
StrictInt,
StrictFloat,
StrictStr,
ConfigDict,
)
from tiramisu import undefined
from .utils import get_jinja_variable_to_param, get_realpath
from .error import DictConsistencyError, VariableCalculationDependencyError
BASETYPE = Union[StrictBool, StrictInt, StrictFloat, StrictStr, None]
PROPERTY_ATTRIBUTE = ["frozen", "hidden", "disabled", "mandatory"]
def convert_boolean(value: str) -> bool:
"""Boolean coercion. The Rougail XML may contain srings like `True` or `False`"""
if isinstance(value, bool):
return value
value = value.lower()
if value == "true":
return True
elif value == "false":
return False
elif value in ["", None]:
return None
raise Exception(f'unknown boolean value "{value}"')
CONVERT_OPTION = {
"string": dict(opttype="StrOption", example="example"),
"number": dict(opttype="IntOption", func=int, example=42),
"float": dict(opttype="FloatOption", func=float, example=1.42),
"boolean": dict(opttype="BoolOption", func=convert_boolean),
"secret": dict(opttype="PasswordOption", example="secrets"),
"mail": dict(opttype="EmailOption", example="user@example.net"),
"unix_filename": dict(opttype="FilenameOption", example="/tmp/myfile.txt"),
"date": dict(opttype="DateOption", example="2000-01-01"),
"unix_user": dict(opttype="UsernameOption", example="username"),
"ip": dict(
opttype="IPOption", initkwargs={"allow_reserved": True}, example="1.1.1.1"
),
"cidr": dict(opttype="IPOption", initkwargs={"cidr": True}, example="1.1.1.0/24"),
"netmask": dict(opttype="NetmaskOption", example="255.255.255.0"),
"network": dict(opttype="NetworkOption", example="1.1.1.0"),
"network_cidr": dict(
opttype="NetworkOption", initkwargs={"cidr": True}, example="1.1.1.0/24"
),
"broadcast": dict(opttype="BroadcastOption", example="1.1.1.255"),
"netbios": dict(
opttype="DomainnameOption",
initkwargs={"type": "netbios", "warnings_only": True},
example="example",
),
"domainname": dict(
opttype="DomainnameOption",
initkwargs={"type": "domainname", "allow_ip": False},
example="example.net",
),
"hostname": dict(
opttype="DomainnameOption",
initkwargs={"type": "hostname", "allow_ip": False},
example="example",
),
"web_address": dict(
opttype="URLOption",
initkwargs={"allow_ip": False, "allow_without_dot": True},
example="https://example.net",
),
"port": dict(
opttype="PortOption", initkwargs={"allow_private": True}, example="111"
),
"mac": dict(opttype="MACOption", example="00:00:00:00:00"),
"unix_permissions": dict(
opttype="PermissionsOption",
initkwargs={"warnings_only": True},
func=int,
example="644",
),
"choice": dict(opttype="ChoiceOption", example="a_choice"),
"regexp": dict(opttype="RegexpOption"),
#
"symlink": dict(opttype="SymLinkOption"),
}
class Param(BaseModel):
key: str
model_config = ConfigDict(extra="forbid")
def __init__(
self,
path,
attribute,
family_is_dynamic,
is_follower,
xmlfiles,
**kwargs,
) -> None:
super().__init__(**kwargs)
class AnyParam(Param):
type: str
value: Union[BASETYPE, List[BASETYPE]]
class VariableParam(Param):
type: str
variable: str
propertyerror: bool = True
whole: bool = False
optional: bool = False
class IdentifierParam(Param):
type: str
identifier: Optional[int] = None
def __init__(
self,
**kwargs,
) -> None:
if not kwargs["family_is_dynamic"]:
msg = f'identifier parameter for "{kwargs["attribute"]}" in "{kwargs["path"]}" cannot be set none dynamic family'
raise DictConsistencyError(msg, 10, kwargs["xmlfiles"])
super().__init__(**kwargs)
class InformationParam(Param):
type: str
information: str
variable: Optional[str] = None
class IndexParam(Param):
type: str
def __init__(
self,
**kwargs,
) -> None:
if not kwargs["is_follower"]:
msg = f'the variable "{kwargs["path"]}" is not a follower, so cannot have index type for param in "{kwargs["attribute"]}"'
raise DictConsistencyError(msg, 25, kwargs["xmlfiles"])
super().__init__(**kwargs)
PARAM_TYPES = {
"any": AnyParam,
"variable": VariableParam,
"identifier": IdentifierParam,
"information": InformationParam,
"index": IndexParam,
}
class Calculation(BaseModel):
path_prefix: Optional[str]
path: str
inside_list: bool
version: str
ori_path: Optional[str] = None
default_values: Any = None
namespace: Optional[str]
xmlfiles: List[str]
model_config = ConfigDict(extra="forbid")
def get_realpath(
self,
path: str,
) -> str:
return get_realpath(path, self.path_prefix)
def get_params(self, objectspace):
if not self.params:
return {}
params = {}
for param_obj in self.params:
param = param_obj.model_dump()
if param.get("type") == "variable":
if self.ori_path is None:
path = self.path
else:
path = self.ori_path
variable, identifier = objectspace.paths.get_with_dynamic(
param["variable"],
self.path_prefix,
path,
self.version,
self.namespace,
self.xmlfiles,
)
if not variable:
if not param.get("optional"):
msg = f'cannot find variable "{param["variable"]}" defined attribute in "{self.attribute_name}" for "{self.path}"'
raise DictConsistencyError(msg, 22, self.xmlfiles)
continue
if not isinstance(variable, objectspace.variable):
raise Exception("pfff it's a family")
param["variable"] = variable
if identifier:
param["identifier"] = identifier
if param.get("type") == "information":
if param["variable"]:
if self.ori_path is None:
path = self.path
else:
path = self.ori_path
variable, identifier = objectspace.paths.get_with_dynamic(
param["variable"],
self.path_prefix,
path,
self.version,
self.namespace,
self.xmlfiles,
)
if not variable:
msg = f'cannot find variable "{param["variable"]}" defined in "{self.attribute_name}" for "{self.path}"'
raise DictConsistencyError(msg, 14, self.xmlfiles)
param["variable"] = variable
if identifier:
msg = f'variable "{param["variable"]}" defined in "{self.attribute_name}" for "{self.path}" is a dynamic variable'
raise DictConsistencyError(msg, 15, self.xmlfiles)
else:
del param["variable"]
params[param.pop("key")] = param
return params
class JinjaCalculation(Calculation):
attribute_name: Literal[
"frozen",
"hidden",
"mandatory",
"empty",
"disabled",
"default",
"validators",
"choices",
"dynamic",
]
jinja: StrictStr
params: Optional[List[Param]] = None
return_type: BASETYPE = None
description: Optional[StrictStr] = None
def _jinja_to_function(
self,
function,
return_type,
multi,
objectspace,
*,
add_help=False,
params: Optional[dict] = None,
):
variable = objectspace.paths[self.path]
jinja_path = f"{self.attribute_name}_{self.path}"
idx = 0
while jinja_path in objectspace.jinja:
jinja_path = f"{self.attribute_name}_{self.path}_{idx}"
idx += 1
objectspace.jinja[jinja_path] = self.jinja
default = {
"function": function,
"params": {
"__internal_jinja": jinja_path,
"__internal_type": return_type,
"__internal_multi": multi,
"__internal_files": self.xmlfiles,
"__internal_attribute": self.attribute_name,
"__internal_variable": self.path,
},
}
if self.default_values:
default["params"]["__default_value"] = self.default_values
if add_help:
default["help"] = function + "_help"
if self.params:
default["params"] |= self.get_params(objectspace)
if params:
default["params"] |= params
if self.ori_path is None:
path = self.path
else:
path = self.ori_path
for sub_variable, identifier, true_path in get_jinja_variable_to_param(
path,
self.jinja,
objectspace,
variable.xmlfiles,
objectspace.functions,
self.path_prefix,
self.version,
self.namespace,
):
if true_path in default["params"]:
continue
if isinstance(sub_variable, dict):
default["params"][true_path] = {
"type": "value",
"value": sub_variable,
}
else:
default["params"][true_path] = {
"type": "variable",
"variable": sub_variable,
}
if self.version != "1.0":
default["params"][true_path]["propertyerror"] = False
if identifier:
default["params"][true_path]["identifier"] = identifier
return default
def to_function(
self,
objectspace,
) -> dict:
if self.attribute_name == "default":
if self.return_type:
raise Exception("return_type not allowed!")
variable = objectspace.paths[self.path]
return_type = variable.type
if self.inside_list:
multi = False
elif self.path in objectspace.followers:
multi = objectspace.multis[self.path] == "submulti"
else:
multi = self.path in objectspace.multis
return self._jinja_to_function(
"jinja_to_function",
return_type,
multi,
objectspace,
)
elif self.attribute_name == "validators":
if self.return_type:
raise Exception("pfff")
return self._jinja_to_function(
"valid_with_jinja",
"string",
False,
objectspace,
)
elif self.attribute_name in PROPERTY_ATTRIBUTE:
if self.return_type:
raise Exception("return_type not allowed!")
return self._jinja_to_function(
"jinja_to_property",
"string",
False,
objectspace,
add_help=True,
params={None: [self.attribute_name], "when": True, "inverse": False},
)
elif self.attribute_name == "choices":
return_type = self.return_type
if return_type is None:
return_type = "string"
return self._jinja_to_function(
"jinja_to_function",
return_type,
not self.inside_list,
objectspace,
)
elif self.attribute_name == "dynamic":
return self._jinja_to_function(
"jinja_to_function",
"string",
True,
objectspace,
)
raise Exception("hu?")
class _VariableCalculation(Calculation):
variable: StrictStr
propertyerror: bool = True
allow_none: bool = False
def get_variable(
self,
objectspace,
) -> "Variable":
if self.ori_path is None:
path = self.path
else:
path = self.ori_path
variable, identifier = objectspace.paths.get_with_dynamic(
self.variable,
self.path_prefix,
path,
self.version,
self.namespace,
self.xmlfiles,
)
if variable and not isinstance(variable, objectspace.variable):
# FIXME remove the pfff
raise Exception("pfff it's a family")
return variable, identifier
def get_params(
self,
objectspace,
variable: "Variable",
identifier: Optional[str],
*,
needs_multi: Optional[bool] = None,
):
if not variable:
msg = f'Variable not found "{self.variable}" for attribut "{self.attribute_name}" for variable "{self.path}"'
raise DictConsistencyError(msg, 88, self.xmlfiles)
param = {
"type": "variable",
"variable": variable,
"propertyerror": self.propertyerror,
}
if identifier:
param["identifier"] = identifier
params = {None: [param]}
if self.default_values:
params["__default_value"] = self.default_values
if self.allow_none:
params["allow_none"] = True
if needs_multi is None:
if self.attribute_name != "default":
needs_multi = True
else:
needs_multi = self.path in objectspace.multis
calc_variable_is_multi = variable.path in objectspace.multis
if not calc_variable_is_multi:
if variable.path in objectspace.paths._dynamics and (
identifier is None or identifier[-1] is None
):
self_dyn_path = objectspace.paths._dynamics.get(self.path)
if self_dyn_path is not None:
var_dyn_path = objectspace.paths._dynamics[variable.path]
if self_dyn_path != var_dyn_path and not self_dyn_path.startswith(
f"{var_dyn_path}."
):
calc_variable_is_multi = True
else:
calc_variable_is_multi = True
elif identifier and "{{ identifier }}" in identifier:
calc_variable_is_multi = True
if needs_multi:
if calc_variable_is_multi:
if self.inside_list:
msg = f'the variable "{self.path}" has an invalid attribute "{self.attribute_name}", the variable "{variable.path}" is multi but is inside a list'
raise DictConsistencyError(msg, 18, self.xmlfiles)
elif not self.inside_list:
msg = f'the variable "{self.path}" has an invalid attribute "{self.attribute_name}", the variable "{variable.path}" is not multi but is not inside a list'
raise DictConsistencyError(msg, 20, self.xmlfiles)
elif self.inside_list:
msg = f'the variable "{self.path}" has an invalid attribute "{self.attribute_name}", it\'s a list'
raise DictConsistencyError(msg, 23, self.xmlfiles)
elif calc_variable_is_multi:
if (
variable.multi
or variable.path.rsplit(".", 1)[0] != self.path.rsplit(".", 1)[0]
):
# it's not a follower or not in same leadership
msg = f'the variable "{self.path}" has an invalid attribute "{self.attribute_name}", the variable "{variable.path}" is a multi'
raise DictConsistencyError(msg, 21, self.xmlfiles)
else:
params[None][0]["index"] = {"index": {"type": "index"}}
return params
class VariableCalculation(_VariableCalculation):
attribute_name: Literal["default", "choices", "dynamic"]
optional: bool = False
def to_function(
self,
objectspace,
) -> dict:
if self.attribute_name != "default" and self.optional:
msg = f'"{self.attribute_name}" variable shall not have an "optional" attribute for variable "{self.variable}"'
raise DictConsistencyError(msg, 33, self.xmlfiles)
variable, identifier = self.get_variable(objectspace)
if not variable and self.optional:
raise VariableCalculationDependencyError()
params = self.get_params(
objectspace,
variable,
identifier,
)
return {
"function": "calc_value",
"params": params,
}
class VariablePropertyCalculation(_VariableCalculation):
attribute_name: Literal[*PROPERTY_ATTRIBUTE]
when: Any = undefined
when_not: Any = undefined
def to_function(
self,
objectspace,
) -> dict:
variable, identifier = self.get_variable(objectspace)
params = self.get_params(
objectspace,
variable,
identifier,
needs_multi=False,
)
variable = params[None][0]["variable"]
if self.when is not undefined:
if self.version == "1.0":
msg = f'when is not allowed in format version 1.0 for attribute "{self.attribute_name}" for variable "{self.path}"'
raise DictConsistencyError(msg, 103, variable.xmlfiles)
if self.when_not is not undefined:
msg = f'the variable "{self.path}" has an invalid attribute "{self.attribute_name}", when and when_not cannot set together'
raise DictConsistencyError(msg, 31, variable.xmlfiles)
when = self.when
inverse = False
elif self.when_not is not undefined:
if self.version == "1.0":
msg = f'when_not is not allowed in format version 1.0 for attribute "{self.attribute_name}" for variable "{self.path}"'
raise DictConsistencyError(msg, 104, variable.xmlfiles)
when = self.when_not
inverse = True
else:
if variable.type != "boolean":
raise Exception("only boolean!")
when = True
inverse = False
params[None].insert(0, self.attribute_name)
params["when"] = when
params["inverse"] = inverse
return {
"function": "variable_to_property",
"params": params,
"help": "variable_to_property",
}
class InformationCalculation(Calculation):
attribute_name: Literal["default", "choice", "dynamic"]
information: StrictStr
variable: Optional[StrictStr]
def to_function(
self,
objectspace,
) -> dict:
params = {
None: [
{
"type": "information",
"information": self.information,
}
]
}
if self.variable:
if self.ori_path is None:
path = self.path
else:
path = self.ori_path
variable, identifier = objectspace.paths.get_with_dynamic(
self.variable,
self.path_prefix,
path,
self.version,
self.namespace,
self.xmlfiles,
)
if variable is None or identifier is not None:
raise Exception("pfff")
params[None][0]["variable"] = variable
if self.default_values:
params["__default_value"] = self.default_values
return {
"function": "calc_value",
"params": params,
}
class _IdentifierCalculation(Calculation):
identifier: Optional[int] = None
def get_identifier(self) -> dict:
identifier = {"type": "identifier"}
if self.identifier is not None:
identifier["identifier"] = self.identifier
return identifier
class IdentifierCalculation(_IdentifierCalculation):
attribute_name: Literal["default", "choice", "dynamic"]
def to_function(
self,
objectspace,
) -> dict:
identifier = {"type": "identifier"}
if self.identifier is not None:
identifier["identifier"] = self.identifier
return {
"function": "calc_value",
"params": {None: [self.get_identifier()]},
}
class IdentifierPropertyCalculation(_IdentifierCalculation):
attribute_name: Literal[*PROPERTY_ATTRIBUTE]
when: Any = undefined
when_not: Any = undefined
def to_function(
self,
objectspace,
) -> dict:
if self.version == "1.0":
msg = f'when is not allowed in format version 1.0 for attribute "{self.attribute_name}"'
raise DictConsistencyError(msg, 105, variable.xmlfiles)
if self.when is not undefined:
if self.when_not is not undefined:
msg = f'the identifier has an invalid attribute "{self.attribute_name}", when and when_not cannot set together'
raise DictConsistencyError(msg, 35, variable.xmlfiles)
when = self.when
inverse = False
elif self.when_not is not undefined:
when = self.when_not
inverse = True
else:
msg = f'the identifier has an invalid attribute "{self.attribute_name}", when and when_not cannot set together'
raise DictConsistencyError
params = {
None: [self.attribute_name, self.get_identifier()],
"when": when,
"inverse": inverse,
}
return {
"function": "variable_to_property",
"params": params,
"help": "variable_to_property",
}
class IndexCalculation(Calculation):
attribute_name: Literal["default", "choice", "dynamic"]
def to_function(
self,
objectspace,
) -> dict:
if self.path not in objectspace.followers:
msg = f'the variable "{self.path}" is not a follower, so cannot have index type for "{self.attribute_name}"'
raise DictConsistencyError(msg, 60, self.xmlfiles)
return {
"function": "calc_value",
"params": {None: [{"type": "index"}]},
}
CALCULATION_TYPES = {
"jinja": JinjaCalculation,
"variable": VariableCalculation,
"information": InformationCalculation,
"identifier": IdentifierCalculation,
"suffix": IdentifierCalculation,
"index": IndexCalculation,
}
CALCULATION_PROPERTY_TYPES = {
"jinja": JinjaCalculation,
"variable": VariablePropertyCalculation,
"information": InformationCalculation,
"identifier": IdentifierPropertyCalculation,
"index": IndexCalculation,
}
BASETYPE_CALC = Union[StrictBool, StrictInt, StrictFloat, StrictStr, Calculation, None]
class Family(BaseModel):
name: str
description: Optional[str] = None
type: Literal["family", "leadership", "dynamic"] = "family"
path: str
help: Optional[str] = None
mode: Optional[str] = None
hidden: Union[bool, Calculation] = False
disabled: Union[bool, Calculation] = False
namespace: Optional[str]
version: str
xmlfiles: List[str] = []
model_config = ConfigDict(extra="forbid", arbitrary_types_allowed=True)
class Dynamic(Family):
# None only for format 1.0
variable: str = None
dynamic: Union[List[Union[StrictStr, Calculation]], Calculation]
class Variable(BaseModel):
# type will be set dynamically in `annotator/value.py`, default is None
type: str = None
name: str
description: Optional[str] = None
default: Union[List[BASETYPE_CALC], BASETYPE_CALC] = None
choices: Optional[Union[List[BASETYPE_CALC], Calculation]] = None
regexp: Optional[str] = None
params: Optional[List[Param]] = None
validators: Optional[List[Calculation]] = None
multi: Optional[bool] = None
unique: Optional[bool] = None
help: Optional[str] = None
hidden: Union[bool, Calculation] = False
disabled: Union[bool, Calculation] = False
mandatory: Union[None, bool, Calculation] = None
empty: Union[None, bool, Calculation] = True
auto_save: bool = False
mode: Optional[str] = None
test: Optional[list] = None
examples: Optional[list] = None
path: str
namespace: Optional[str]
version: str
path_prefix: Optional[str]
xmlfiles: List[str] = []
model_config = ConfigDict(extra="forbid", arbitrary_types_allowed=True)
class SymLink(BaseModel):
type: Literal["symlink"] = "symlink"
name: str
path: str
opt: Variable
namespace: Optional[str]
version: str
path_prefix: Optional[str]
xmlfiles: List[str] = []
model_config = ConfigDict(extra="forbid")

View file

@ -1,6 +1,6 @@
"""
Silique (https://www.silique.fr)
Copyright (C) 2024
Copyright (C) 2024-2026
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
@ -16,4 +16,7 @@ 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/>.
"""
from .update import RougailUpgrade
from .object_model import Variable, Family
__all__ = ("Variable", "Family")

View file

@ -1,7 +1,7 @@
"""Annotate to add specify attribute for tiramisu-cmdline
Silique (https://www.silique.fr)
Copyright (C) 2024
Copyright (C) 2024-2026
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
@ -50,7 +50,6 @@ class Annotator(Walk):
self.not_for_commandline(variable)
else:
self.manage_alternative_name(variable)
self.manage_negative_description(variable)
def not_for_commandline(self, variable) -> None:
self.objectspace.properties.add(variable.path, "not_for_commandline", True)
@ -60,6 +59,7 @@ class Annotator(Walk):
return
alternative_name = variable.alternative_name
variable_path = variable.path
self.objectspace.informations.add(variable_path, "alternative_name", alternative_name)
all_letters = ""
for letter in alternative_name:
all_letters += letter
@ -79,34 +79,14 @@ class Annotator(Walk):
path = alternative_name
else:
path = variable_path.rsplit(".", 1)[0] + "." + alternative_name
self.objectspace.version = variable.version
self.objectspace.add_variable(
alternative_name,
{"type": "symlink", "path": path, "opt": variable},
path,
{"type": "symlink", "opt": variable},
variable.xmlfiles,
False,
False,
variable.version,
)
def manage_negative_description(self, variable) -> None:
if not variable.negative_description:
if variable.type == "boolean" and not self.objectspace.add_extra_options:
raise DictConsistencyError(
_(
'negative_description is mandatory for boolean variable, but "{0}" hasn\'t'
).format(variable.path),
200,
variable.xmlfiles,
)
return
if variable.type != "boolean":
raise DictConsistencyError(
_(
'negative_description is only available for boolean variable, but "{0}" is "{1}"'
).format(variable.path, variable.type),
201,
variable.xmlfiles,
)
self.objectspace.informations.add(
variable.path, "negative_description", variable.negative_description
False,
False,
)

View file

@ -2,7 +2,7 @@
Config file for Rougail-structural_commandline
Silique (https://www.silique.fr)
Copyright (C) 2024
Copyright (C) 2024-2026
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 @@ def get_rougail_config(
structural_commandline:
description: Configuration rougail-structural_commandline
commandline: false
add_extra_options:
description: Add extra options to tiramisu-cmdline-parser
default: true
"""
return {
"name": "exporter",
"name": "commandline",
"process": "structural",
"options": options,
"level": 20,

View file

@ -1,7 +1,7 @@
"""Annotate to add specify attribute for tiramisu-cmdline
Silique (https://www.silique.fr)
Copyright (C) 2024
Copyright (C) 2024-2026
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
@ -24,11 +24,7 @@ from pydantic import BaseModel
class Variable(BaseModel):
alternative_name: Optional[str] = None
commandline: bool = True
negative_description: Optional[str] = None
class Family(BaseModel):
commandline: bool = True
__all__ = ("Variable", "Family")

View file

@ -0,0 +1,158 @@
"""
Silique (https://www.silique.fr)
Copyright (C) 2022-2026
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/>.
"""
from typing import Union, List, Iterator, Optional
from itertools import chain
from pathlib import Path
from ruamel.yaml import YAML
from ..tiramisu import normalize_family
from ..convert.path import Paths
from ..error import DictConsistencyError
from ..i18n import _
class Walker:
def __init__(
self,
convert,
) -> None:
"""Parse directories content"""
self.convert = convert
self.yaml = YAML()
rougailconfig = self.convert.rougailconfig
self.sort_structural_files_all = rougailconfig["sort_structural_files_all"]
if rougailconfig["main_namespace"]:
self.convert.paths = Paths(
rougailconfig["main_namespace"],
rougailconfig["isolated_namespace"],
)
self.load_with_extra(
rougailconfig["extra_namespaces"],
rougailconfig["main_namespace"],
rougailconfig["main_structural_directories"],
)
else:
self.convert.namespace = None
namespace_path = ""
if namespace_path in self.convert.parents:
raise Exception("pfff")
for filename in self.get_sorted_filename(
rougailconfig["main_structural_directories"]
):
self.parse_variable_file(
filename,
namespace_path,
)
def load_with_extra(
self,
extra_structures: dict,
main_namespace: Optional[str] = None,
main_structures: Optional[List[str]] = None,
) -> None:
self.convert.has_namespace = True
if main_namespace:
directory_dict = chain(
(
(
main_namespace,
main_structures,
),
),
extra_structures.items(),
)
else:
directory_dict = extra_structures.items()
for namespace, extra_dirs in directory_dict:
# if namespace is None:
# self.convert.namespace = namespace
# else:
self.convert.namespace = normalize_family(namespace)
namespace_path = self.convert.namespace
if namespace_path in self.convert.parents:
raise Exception("pfff")
for idx, filename in enumerate(self.get_sorted_filename(extra_dirs)):
if not idx:
# create only for the first file
self.convert.create_namespace(namespace, namespace_path)
self.parse_variable_file(
filename,
namespace_path,
)
def get_sorted_filename(
self,
directories: Union[str, List[str]],
) -> Iterator[str]:
"""Sort filename"""
if not isinstance(directories, list):
directories = [directories]
if self.sort_structural_files_all:
filenames = {}
for directory_name in directories:
directory = Path(directory_name)
if not self.sort_structural_files_all:
filenames = {}
if directory.is_file():
self.get_filename(directory, filenames)
else:
for file_path in directory.iterdir():
self.get_filename(file_path, filenames)
if not self.sort_structural_files_all:
for filename in sorted(filenames):
yield filenames[filename]
if self.sort_structural_files_all:
for filename in sorted(filenames):
yield filenames[filename]
def get_filename(self, file_path, filenames: List[str]) -> None:
if file_path.suffix not in [".yml", ".yaml"]:
return
if file_path.name in filenames:
raise DictConsistencyError(
_("duplicate structural file name {0}").format(file_path.name),
78,
[filenames[file_path.name], str(file_path)],
)
filenames[file_path.name] = str(file_path)
def parse_variable_file(
self,
filename: str,
path: str,
) -> None:
"""Parse file"""
with open(filename, encoding="utf8") as file_fh:
objects = self.yaml.load(file_fh)
if objects is None:
return
version = self.convert.validate_file_version(
objects,
filename,
)
self.convert.parse_root_file(
[filename],
path,
version,
objects,
)
__all__ = ("Walker",)

View file

@ -0,0 +1,116 @@
"""
Silique (https://www.silique.fr)
Copyright (C) 2024-2026
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/>.
"""
from ..utils import _
def get_rougail_config(
*,
backward_compatibility=True,
) -> dict:
if backward_compatibility:
main_namespace_default = "rougail"
else:
main_namespace_default = "null"
options = f"""
main_namespace:
description: {_("Main namespace name")}
default: {main_namespace_default}
alternative_name: s
mandatory: false
disabled:
jinja: >-
{{{{ 'directory' not in _.step.structural and 'string' not in _.step.structural }}}}
return_type: boolean
description: {_('directory or string is not in "_.step.structural"')}
main_structural_directories:
description: {_("Directories where structural files are placed")}
type: unix_filename
alternative_name: m
params:
allow_relative: True
test_existence: True
multi: true
disabled:
jinja: >-
{{% if 'directory' not in _.step.structural %}}
directory is not in _.step.structural
{{% endif %}}
{{% if cli is defined and cli.versions is defined and cli.versions %}}
cli.versions is specified
{{% endif %}}
sort_structural_files_all:
description: {_("Sort structural from differents directories")}
default: false
disabled:
jinja: >-
{{% if 'directory' not in _.step.structural %}}
directory is not in _.step.structural
{{% endif %}}
isolated_namespace:
description: {_("Namespaces are isolated")}
default: true
disabled:
jinja: >-
{{{{ 'directory' not in _.step.structural and 'string' not in _.step.structural }}}}
return_type: boolean
description: {_('directory or string is not in "_.step.structural" or "_.main_namespace" is not set')}
extra_namespaces:
description: {_("Extra namespaces")}
type: leadership
disabled:
jinja: >-
{{{{ ('directory' not in _.step.structural and 'string' not in _.step.structural) or not _.main_namespace }}}}
return_type: boolean
description: directory is not in _.step.structural or main_namespace is not set
names:
description: {_("Extra namespace name")}
alternative_name: xn
multi: true
mandatory: false
directories:
description: {_("Directories where extra structural files are placed")}
alternative_name: xd
type: unix_filename
params:
allow_relative: true
test_existence: true
types:
- directory
multi: true
disabled:
jinja: >-
{{{{ 'directory' not in __.step.structural }}}}
return_type: boolean
description: {_('directory is not in "__.step.structural"')}
"""
return {
"name": "directory",
"process": "structural",
"options": options,
"level": 5,
}
__all__ = "get_rougail_config"

View file

@ -9,7 +9,7 @@ Cadoles (http://www.cadoles.com)
Copyright (C) 2019-2021
Silique (https://www.silique.fr)
Copyright (C) 2022-2024
Copyright (C) 2022-2026
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,27 +27,223 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
from typing import Any
try:
from tiramisu5 import DynOptionDescription, calc_value
except ModuleNotFoundError:
from tiramisu import DynOptionDescription, calc_value
from importlib.machinery import SourceFileLoader as _SourceFileLoader
from importlib.util import (
spec_from_loader as _spec_from_loader,
module_from_spec as _module_from_spec,
)
from unicodedata import normalize, combining
from jinja2 import StrictUndefined, DictLoader
from jinja2.sandbox import SandboxedEnvironment
from rougail.object_model import CONVERT_OPTION
from rougail.error import display_xmlfiles
from tiramisu import function_waiting_for_error
from tiramisu.error import ValueWarning, ConfigError, PropertiesOptionError
from .utils import normalize_family
from re import findall
from tiramisu import (
DynOptionDescription,
calc_value,
function_waiting_for_error,
undefined,
)
from tiramisu.error import (
ValueWarning,
ConfigError,
PropertiesOptionError,
CancelParam,
errors,
)
ori_raise_carry_out_calculation_error = errors.raise_carry_out_calculation_error
try:
from .i18n import _
except ModuleNotFoundError:
# FIXME
def _(msg):
return msg
def display_xmlfiles(xmlfiles: list) -> str:
"""The function format xmlfiles informations to generate errors"""
if not isinstance(xmlfiles, list):
xmlfiles = [xmlfiles]
if len(xmlfiles) == 1:
return '"' + xmlfiles[0] + '"'
return '"' + '", "'.join(xmlfiles[:-1]) + '"' + " and " + '"' + xmlfiles[-1] + '"'
def convert_boolean(value: str) -> bool:
"""Boolean coercion. The Rougail XML may contain srings like `True` or `False`"""
if isinstance(value, bool):
return value
value = value.lower()
if value == "true":
return True
elif value == "false":
return False
elif value in ["", None]:
return None
raise Exception(_('unknown boolean value "{0}"').format(value))
_ip_params = {
"cidr": {"description": _("IP must be in CIDR format")},
"private_only": {"description": _("private IP are allowed")},
"allow_reserved": {"description": _("reserved IP are allowed")},
}
_network_params = {
"cidr": {"description": _("network must be in CIDR format")},
"private_only": {"description": _("private network are allowed")},
"allow_reserved": {"description": _("reserved network are allowed")},
}
_port_params = {
"allow_range": {"description": _("can be range of port")},
"allow_protocol": {"description": _("can have the protocol")},
"allow_zero": {"description": _("port 0 is allowed")},
"allow_wellknown": {"description": _("well-known ports (1 to 1023) are allowed")},
"allow_registred": {"description": _("registred ports (1024 to 49151) are allowed")},
"allow_private": {"description": _("private ports (greater than 49152) are allowed")},
}
_domain_params = {
"type": {"description": _("type of domainname"), "choices": ('domainname', 'netbios', 'hostname'), 'doc': _("type {0}")},
"allow_startswith_dot": {"description": _("the domain name can starts by a dot")},
"allow_without_dot": {"description": _("the domain name can be a hostname")},
"allow_ip": {"description": _("the domain name can be an IP")},
"allow_cidr_network": {"description": _("the domain name can be network in CIDR format")},
"test_existence": {"description": _("the domain name must exist")},
}
_web_params = _port_params | _domain_params
CONVERT_OPTION = {
"string": dict(opttype="StrOption", example="example"),
"number": dict(opttype="IntOption",
func=int,
params={
"min_number": {"description": _("the minimum value"), 'doc': _("the minimum value is {0}")},
"max_number": {"description": _("the maximum value"), 'doc': _("the maximum value is {0}")},
},
example=42),
"integer": dict(opttype="IntOption",
params={
"min_integer": {"description": _("the minimum value"), 'doc': _("the minimum value is {0}")},
"max_integer": {"description": _("the maximum value"), 'doc': _("the maximum value is {0}")},
},
func=int,
example=42,
),
"float": dict(opttype="FloatOption", func=float, example=1.42),
"boolean": dict(opttype="BoolOption", func=convert_boolean),
"secret": dict(opttype="PasswordOption",
params={
"min_len": {"description": _("minimum characters length for the secret"), "doc": _("minimum length for the secret is {0} characters")},
"max_len": {"description": _("maximum characters length for the secret"), "doc": _("maximum length for the secret is {0} characters")},
"forbidden_char": {"description": _("forbidden characters"), "doc": _("forbidden characters: {0}")},
},
example="secrets"),
"mail": dict(opttype="EmailOption", example="user@example.net"),
"unix_filename": dict(opttype="FilenameOption",
msg="UNIX filename",
params={
"allow_relative": {"description": _("this filename could be a relative path")},
"test_existence": {"description": _("this file must exist")},
"types": {"description": _("file type allowed"), "doc": _("file type allowed: {0}"), "choices": ("file", "directory"), "multi": True},
},
example="/tmp/myfile.txt"),
"date": dict(opttype="DateOption", example="2000-01-01"),
"unix_user": dict(opttype="UsernameOption", example="username",
msg="UNIX user"
),
"ip": dict(
opttype="IPOption", initkwargs={"allow_reserved": True},
msg="IP",
params=_ip_params,
example="1.1.1.1"
),
"cidr": dict(opttype="IPOption", msg="CIDR", initkwargs={"cidr": True},
params=_ip_params,
example="1.1.1.0/24"),
"netmask": dict(opttype="NetmaskOption", example="255.255.255.0"),
"network": dict(opttype="NetworkOption",
params=_network_params,
example="1.1.1.0"),
"network_cidr": dict(
opttype="NetworkOption", initkwargs={"cidr": True}, example="1.1.1.0/24",
params=_network_params,
msg="network CIDR",
),
"broadcast": dict(opttype="BroadcastOption", example="1.1.1.255"),
"netbios": dict(
opttype="DomainnameOption",
initkwargs={"type": "netbios", "warnings_only": True},
params=_domain_params,
example="example",
),
"domainname": dict(
opttype="DomainnameOption",
initkwargs={"type": "domainname", "allow_ip": False},
params=_domain_params,
example="example.net",
),
"hostname": dict(
opttype="DomainnameOption",
initkwargs={"type": "hostname", "allow_ip": False},
params=_domain_params,
example="example",
),
"web_address": dict(
opttype="URLOption",
initkwargs={"allow_ip": False, "allow_without_dot": True},
msg="web address",
params=_web_params,
example="https://example.net",
),
"port": dict(
opttype="PortOption", initkwargs={"allow_private": True},
params=_port_params,
example="111", func=str,
),
"mac": dict(opttype="MACOption", example="00:00:00:00:00"),
"unix_permissions": dict(
opttype="PermissionsOption",
msg="UNIX permissions",
initkwargs={"warnings_only": True},
func=int,
example="644",
),
"choice": dict(opttype="ChoiceOption", example="a_choice"),
"regexp": dict(opttype="RegexpOption"),
#
"symlink": dict(opttype="SymLinkOption"),
}
RENAME_TYPE = {"number": "integer"}
def get_identifier_from_dynamic_family(true_name, name) -> str:
if true_name == "{{ identifier }}":
return name
regexp = true_name.replace("{{ identifier }}", "(.*)")
finded = findall(regexp, name)
if len(finded) != 1 or not finded[0]:
return None
return finded[0]
def raise_carry_out_calculation_error(subconfig, *args, **kwargs):
try:
ori_raise_carry_out_calculation_error(subconfig, *args, **kwargs)
except ConfigError as err:
ymlfiles = subconfig.config_bag.context.get_values().get_information(
subconfig, "ymlfiles", []
)
raise ConfigError(_("{0} in {1}").format(err, display_xmlfiles(ymlfiles)), subconfig=subconfig)
errors.raise_carry_out_calculation_error = raise_carry_out_calculation_error
global func
dict_env = {}
ENV = SandboxedEnvironment(loader=DictLoader(dict_env), undefined=StrictUndefined)
ENV.add_extension('jinja2.ext.do')
func = ENV.filters
ENV.compile_templates("jinja_caches", zip=None)
@ -90,8 +286,10 @@ def test_propertyerror(value: Any) -> bool:
ENV.tests["propertyerror"] = test_propertyerror
def load_functions(path):
def load_functions(path, dict_func=None):
global _SourceFileLoader, _spec_from_loader, _module_from_spec, func
if dict_func is None:
dict_func = func
loader = _SourceFileLoader("func", path)
spec = _spec_from_loader(loader.name, loader)
func_ = _module_from_spec(spec)
@ -99,16 +297,94 @@ def load_functions(path):
for function in dir(func_):
if function.startswith("_"):
continue
func[function] = getattr(func_, function)
dict_func[function] = getattr(func_, function)
def rougail_calc_value(*args, __default_value=None, **kwargs):
def normalize_family(family_name: str) -> str:
"""replace space, accent, uppercase, ... by valid character"""
if not family_name:
return
family_name = family_name.lower()
family_name = family_name.replace("-", "_").replace(" ", "_").replace(".", "_")
nfkd_form = normalize("NFKD", family_name)
family_name = "".join([c for c in nfkd_form if not combining(c)])
return family_name.lower()
def tiramisu_display_name(
kls,
subconfig,
with_quote: bool = False,
) -> str:
"""Replace the Tiramisu display_name function to display path + description"""
def get_path():
if description_type in ["description", "name", "name_and_description"]:
path = kls.impl_getname()
else:
path = kls.impl_getpath()
if "{{ identifier }}" in path and subconfig.identifiers:
path = path.replace(
"{{ identifier }}", normalize_family(str(subconfig.identifiers[-1]))
)
return path
config_bag = subconfig.config_bag
context = config_bag.context
values = context.get_values()
context_subconfig = context.get_root(config_bag)
description_type = values.get_information(
context_subconfig, "description_type", "name_and_description"
)
if description_type in ["description", "name_and_description", "path_and_description"]:
doc = values.get_information(subconfig, "doc", None)
description = doc if doc and doc != kls.impl_getname() else ""
if "{{ identifier }}" in description and subconfig.identifiers:
description = description.replace("{{ identifier }}", str(subconfig.identifiers[-1]))
if description_type in ["name", "path", "name_and_description", "path_and_description"]:
path = get_path()
if description_type in ["name_and_description", "path_and_description"]:
if description:
if with_quote:
description = f'"{path}" ({description})'
else:
description = f"{path} ({description})"
else:
if with_quote:
description = f'"{path}"'
else:
description = path
else:
if description_type in ["name", "path"]:
description = path
elif not description:
description = get_path()
if with_quote:
description = f'"{description}"'
return description
def rougail_calc_value(*args, __default_value=None, __internal_multi=False, **kwargs):
values = calc_value(*args, **kwargs)
if values is None and __internal_multi:
values = []
if __default_value is not None and values in [None, []]:
return __default_value
return values
def kw_to_string(kw, root=None):
for name, data in kw.items():
if root is None:
path = name
else:
path = root + "." + name
if isinstance(data, dict):
yield from kw_to_string(data, root=path)
else:
yield f"{path}={data}"
pass
@function_waiting_for_error
def jinja_to_function(
__internal_variable,
@ -123,14 +399,32 @@ def jinja_to_function(
global ENV, CONVERT_OPTION
kw = {}
for key, value in kwargs.items():
if isinstance(value, PropertiesOptionError):
value = JinjaError(value)
if isinstance(value, list):
val = []
for v in value:
if isinstance(v, PropertiesOptionError):
v = JinjaError(v)
if v is None:
v = ''
val.append(v)
value = val
else:
if isinstance(value, PropertiesOptionError):
value = JinjaError(value)
if value is None:
value = ''
if "." in key:
c_kw = kw
path, var = key.rsplit(".", 1)
if isinstance(value, CancelParam):
count_o_path = value.origin_path.count(".") - value.current_path.count(
"."
)
path = path.rsplit(".", count_o_path)[0]
for subkey in path.split("."):
c_kw = c_kw.setdefault(subkey, {})
c_kw[var] = value
if not isinstance(value, CancelParam):
c_kw[var] = value
else:
if key in kw:
raise ConfigError(
@ -140,28 +434,44 @@ def jinja_to_function(
try:
values = ENV.get_template(__internal_jinja).render(kw, **func).strip()
except Exception as err:
raise ConfigError(
f'cannot calculating "{__internal_attribute}" attribute for variable "{__internal_variable}" in {display_xmlfiles(__internal_files)}: {err}'
) from err
kw_str = ", ".join(kw_to_string(kw))
prefix = _('cannot calculate the variable "{0}"').format(__internal_variable)
msg = _('the attribute "{0}" in {1} with the parameters "{2}" causes the error: {3}').format(
__internal_attribute,
display_xmlfiles(__internal_files),
kw_str,
err,
)
raise ConfigError(msg, prefix=prefix) from err
convert = CONVERT_OPTION[__internal_type].get("func", str)
if __internal_multi:
values = [convert(val) for val in values.split("\n") if val != ""]
values = [
convert(val.strip()) for val in values.split("\n") if val.strip() != ""
]
if not values and __default_value is not None:
return __default_value
return values
try:
values = convert(values)
except Exception as err:
raise ConfigError(
f'cannot converting "{__internal_attribute}" attribute for variable "{__internal_variable}" in {display_xmlfiles(__internal_files)}: {err}'
) from err
prefix = _('cannot converting the variable "{0}"').format(__internal_variable)
msg = _('"{0}" is an invalid {1}').format(values, __internal_type)
if __internal_attribute != "default":
msg = _('the attribute "{0}" in {1} causes the error: {2}').format(
__internal_attribute,
display_xmlfiles(__internal_files),
msg,
)
raise ConfigError(msg, prefix=prefix) from err
values = values if values != "" and values != "None" else None
if values is None and __default_value is not None:
return __default_value
return values
def variable_to_property(prop, value, when, inverse):
def variable_to_property(*, prop, value=undefined, when, inverse, **kwargs):
if value is undefined:
return None
if isinstance(value, PropertiesOptionError):
raise value from value
if inverse:
@ -171,27 +481,39 @@ def variable_to_property(prop, value, when, inverse):
return prop if is_match else None
def variable_to_property_transitive(*args, **kwargs):
# do nothing, if associate variable is not accessible, autolib will raise directly
pass
@function_waiting_for_error
def jinja_to_property(prop, when, inverse, **kwargs):
def jinja_to_property(prop, description, when, inverse, **kwargs):
value = func["jinja_to_function"](**kwargs)
return func["variable_to_property"](prop, value is not None, when, inverse)
if kwargs["__internal_type"] == "string":
value = value is not None
return func["variable_to_property"](
prop=prop, value=value, when=when, inverse=inverse
)
@function_waiting_for_error
def jinja_to_property_help(prop, **kwargs):
value = func["jinja_to_function"](**kwargs)
return (prop, f'"{prop}" ({value})')
def jinja_to_property_help(prop, description, **kwargs):
if kwargs["__internal_type"] == "string":
description = func["jinja_to_function"](**kwargs)
return (prop, f'"{prop}" ({description})')
@function_waiting_for_error
def valid_with_jinja(warnings_only=False, **kwargs):
def valid_with_jinja(warnings_only=False, description=None, **kwargs):
global ValueWarning
value = func["jinja_to_function"](**kwargs)
if value:
if description is None:
description = value
if warnings_only:
raise ValueWarning(value)
raise ValueWarning(description)
else:
raise ValueError(value)
raise ValueError(description)
func["calc_value"] = rougail_calc_value
@ -199,7 +521,9 @@ func["jinja_to_function"] = jinja_to_function
func["jinja_to_property"] = jinja_to_property
func["jinja_to_property_help"] = jinja_to_property_help
func["variable_to_property"] = variable_to_property
func["variable_to_property_transitive"] = variable_to_property_transitive
func["valid_with_jinja"] = valid_with_jinja
func["normalize_family"] = normalize_family
class ConvertDynOptionDescription(DynOptionDescription):
@ -207,7 +531,8 @@ class ConvertDynOptionDescription(DynOptionDescription):
Identifier could also contain invalid character, so we should "normalize" it
"""
def convert_identifier_to_path(self, identifier):
@staticmethod
def convert_identifier_to_path(identifier):
if identifier is None:
return identifier
if not isinstance(identifier, str):
@ -236,6 +561,16 @@ class ConvertDynOptionDescription(DynOptionDescription):
if "{{ identifier }}" in display:
return display.replace(
"{{ identifier }}",
self.convert_identifier_to_path(self.get_identifiers(subconfig)[-1]),
self.convert_identifier_to_path(
self.get_identifiers(subconfig, from_display_name=True)[-1]
),
)
return display
def name_could_conflict(self, dynchild, child):
return (
get_identifier_from_dynamic_family(
dynchild.impl_getname(), child.impl_getname()
)
is not None
)

74
src/rougail/types.py Normal file
View file

@ -0,0 +1,74 @@
"""
Silique (https://www.silique.fr)
Copyright (C) 2025-2026
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/>.
"""
from .config import StaticRougailConvert
from .i18n import _
class TypeRougailConvert(StaticRougailConvert):
def __init__(
self,
main_structural_directories: list[str],
) -> None:
super().__init__(False, {"sort_structural_files_all": True,
"main_namespace": None,
"main_structural_directories": main_structural_directories,
})
def load_config(self) -> None:
super().load_config()
self.add_extra_options = self.add_extra_options
self.sort_structural_files_all = False
self.structurals = ["directory"]
def rougail_type(rougailconfig):
types = rougailconfig["types"]
if not types:
return {}, {}
convert = TypeRougailConvert(types)
convert.init()
convert.parse_directories()
return ({typ: to_dict_variable(convert.paths[typ]) for typ in convert.variables},
{typ: to_dict_family(typ, convert.paths, convert.parents, convert.families) for typ in convert.families},
)
def to_dict_variable(obj, with_files=True):
if with_files:
keys = ['name', 'path']
else:
keys = ['name', 'path', 'xmlfiles']
return {key: value for key, value in dict(obj).items() if key not in keys and value is not None}
def to_dict_family(family_name, paths, parents, families, root=True):
ret = to_dict_variable(paths[family_name], root)
for variable_path in parents[family_name]:
variable = paths[variable_path]
variable_name = variable.name
if variable_path in families:
if variable.type == "leadership":
raise DictConsistencyError(_("type is not compatible with leadership family"), variable.xmlfiles)
if variable.type == "dynamic":
raise DictConsistencyError(_("type is not compatible with dynamic family"), variable.xmlfiles)
if variable_name in ret:
ret["_" + variable_name] = ret.pop(variable_name)
ret[variable_name] = to_dict_family(variable.path, paths, parents, families, False)
else:
ret[variable_name] = to_dict_variable(variable, False)
return ret

File diff suppressed because it is too large Load diff

606
src/rougail/user_data.py Normal file
View file

@ -0,0 +1,606 @@
"""
Silique (https://www.silique.fr)
Copyright (C) 2022-2026
distribued with GPL-2 or later license
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""
from typing import List
from tiramisu import Calculation, Params, ParamValue, owners
from tiramisu.error import (
PropertiesOptionError,
AttributeOptionError,
LeadershipError,
ConfigError,
CancelParam,
display_list,
)
from .utils import undefined, get_properties_to_string
from .tiramisu import (
normalize_family,
CONVERT_OPTION,
get_identifier_from_dynamic_family,
)
from .error import DictConsistencyError
from .i18n import _
class UserData:
def __init__(self, config) -> None:
self.config = config
def user_data(
self,
user_data: List[dict],
*,
invalid_user_data_error: bool = False,
unknown_user_data_error: bool = False,
):
self.values = {}
self.errors = []
self.warnings = []
self.invalid_user_data_error = invalid_user_data_error
self.unknown_user_data_error = unknown_user_data_error
if self.invalid_user_data_error:
self.invalids = self.errors
else:
self.invalids = self.warnings
if self.unknown_user_data_error:
self.unknowns = self.errors
else:
self.unknowns = self.warnings
self.show_secrets = False
self._populate_values(user_data)
self._auto_configure_dynamics()
self._populate_config()
self.properties_to_string = get_properties_to_string()
self._populate_error_warnings()
return {
"errors": self.errors,
"warnings": self.warnings,
}
def _populate_values(self, user_data):
for datas in user_data:
options = datas.get("options", {})
source = datas["source"]
for name, data in datas.get("values", {}).items():
self.values[name] = {
"source": source,
"values": data,
"options": options.copy(),
}
self.errors.extend(datas.get("errors", []))
self.warnings.extend(datas.get("warnings", []))
def _get_variable(self, config):
try:
for subconfig in config:
if subconfig.isoptiondescription():
yield from self._get_variable(subconfig)
else:
yield subconfig
except (ConfigError, ValueError) as err:
err.prefix = ""
if self.invalid_user_data_error:
msg = str(err)
else:
msg = _('{0}, it will be ignored').format(err)
self.invalids.append({msg: err.subconfig})
def _auto_configure_dynamics(self):
cache = {}
added = []
for path, data in list(self.values.items()):
try:
option = self.config.option(path)
option.name()
except (ConfigError, PropertiesOptionError):
pass
except AttributeError:
self._not_found_is_dynamic(self.config, path, cache, added, data)
def _not_found_is_dynamic(self, config, path, cache, added, data):
"""if path is not found, check if parent is a dynamic family"""
current_path = ""
identifiers = []
# get parent
for name in path.split(".")[:-1]:
if current_path:
current_path += "."
current_path += name
if current_path in cache:
config, identifier = cache[current_path]
identifiers.append(identifier)
continue
tconfig = config.option(name)
try:
tconfig.group_type()
# object exists, so current config is the temporary config
config = tconfig
if config.isdynamic(only_self=True):
identifiers.append(config.identifiers()[-1])
except AttributeError:
# try to found the good dynamic family
try:
lists = config.list(uncalculated=True)
except PropertiesOptionError:
lists = []
for tconfig in lists:
if not tconfig.isdynamic(only_self=True):
# it's not a dynamic variable
continue
identifier = get_identifier_from_dynamic_family(
tconfig.name(uncalculated=True), name
)
if identifier == "{{ identifier }}":
continue
if identifier != normalize_family(identifier):
msg = _(
'cannot load variable path "{0}", the identifier "{1}" is not valid in {2}'
).format(path, identifier, data["source"])
self.invalids.append(msg)
continue
if identifier is None:
# it's a dynamic variable but doesn't match the current name
continue
# get the variable associate to this dynamic family
dynamic_variable = tconfig.information.get(
"dynamic_variable",
None,
)
if not dynamic_variable:
# it's the good dynamic variable but it's not linked to a variable
# so cannot change the variable
continue
option_type = self.config.option(dynamic_variable).information.get(
"type"
)
dyn_options_values = (
self.config.option(dynamic_variable).get().impl_getdefault()
)
if "{{ identifier }}" in dynamic_variable:
for s in identifiers:
dynamic_variable = dynamic_variable.replace(
"{{ identifier }}", str(s), 1
)
# do not add values in variable if has already a value
if dynamic_variable not in self.values and not dyn_options_values:
self.values[dynamic_variable] = {"values": []}
added.append(dynamic_variable)
elif dynamic_variable not in added:
continue
config = tconfig
identifiers.append(identifier)
typ = CONVERT_OPTION.get(option_type, {}).get("func")
if typ:
identifier = typ(identifier)
if identifier not in self.values[dynamic_variable]["values"]:
self.values[dynamic_variable]["values"].append(identifier)
cache[current_path] = config, identifier
break
def convert_value(self, path, option, options, value):
# converted value
needs_convert = options.get("needs_convert", False)
if option.ismulti():
if options.get("multi_separator") and not isinstance(value, list):
value = value.split(options["multi_separator"])
self.values[path]["values"] = value
if option.issubmulti():
value = [[val] for val in value]
if option.issubmulti():
for idx, val in enumerate(value):
if isinstance(val, list):
value[idx] = [convert_value(option, v, needs_convert) for v in val]
elif isinstance(value, list):
value = [convert_value(option, val, needs_convert) for val in value]
if needs_convert:
self.values[path]["values"] = value
self.values[path]["options"]["needs_convert"] = needs_convert
elif not isinstance(value, list):
value = convert_value(option, value, needs_convert)
return value
def _populate_config(self):
dynamics_variable = []
while self.values:
value_is_set = False
for option in self._get_variable(self.config):
values_path = path = option.path()
if path not in self.values:
if path in dynamics_variable or not option.isdynamic():
continue
values_path = option.path(uncalculated=True)
if values_path not in self.values:
continue
options = self.values[values_path].get("options", {})
if (
options.get("allow_secrets_variables", True) is False
and option.type() == "password"
):
self.errors.append({
_(
'the variable contains secrets and should not be defined in {0}'
).format(self.values[values_path]["source"]): option._subconfig}
)
self.values.pop(path)
continue
value = self.convert_value(
path, option, options, self.values[values_path]["values"]
)
index = option.index()
if index is not None:
if isinstance(value, tuple):
self.values[values_path]["values"] = []
# for i in range(len(option.parent().leader().value.get())):
for i in range(option.value.len()):
self.values[values_path]["values"].append(value)
value = self.values[values_path]["values"]
if not isinstance(value, list) or index >= len(value):
continue
value = value[index]
option_without_index = option.index(None)
else:
option_without_index = option
if option.isleader():
# set value for a leader, it began to remove all values!
len_leader = option.value.len()
if len_leader:
for idx in range(len_leader - 1, -1, -1):
option.value.pop(idx)
try:
self.set_value(option, value, options, index)
value_is_set = True
except Exception as err:
if path != option.path():
self.values[option.path()] = self.values.pop(values_path)
else:
# value is correctly set, remove variable to the set
if index is not None:
# if it's a follower waiting for all followers are sets
self.values[values_path]["values"][index] = undefined
for tmp_value in self.values[values_path]["values"]:
if tmp_value != undefined:
break
else:
if path in self.values:
self.values.pop(path)
else:
dynamics_variable.append(path)
elif path in self.values:
self.values.pop(path)
else:
dynamics_variable.append(path)
if not value_is_set:
break
def _display_value(self, option, value):
if not self.show_secrets and option.type() == "password":
if not isinstance(value, list):
value = "*" * 10
else:
value = ["*" * 10 for val in value]
if isinstance(value, list):
value = display_list(value, add_quote=True)
else:
value = '"' + str(value) + '"'
return value
def _populate_error_warnings(self):
# we don't find variable, apply value just to get error or warning messages
for path, options in self.values.items():
value = options["values"]
if options.get("secret_manager"):
option = self.config.forcepermissive.option(path)
else:
option = self.config.option(path)
try:
if option.isoptiondescription():
if value:
if self.invalid_user_data_error:
msg = _(
'it\'s a family so we cannot set the value {0}, it has been loading from {1}'
)
else:
msg = _(
'it\'s a family so we cannot set the value {0}, it will be ignored when loading from {1}'
)
self.invalids.append({msg.format(
self._display_value(option, value),
options["source"],
): option._subconfig}
)
continue
if option.issymlinkoption():
err = _('it\'s a symlink option so we cannot set the value {0}').format(self._display_value(option, value))
if self.invalid_user_data_error:
msg = _('{0}, it has been loading from {1}').format(err, options["source"])
else:
msg = _('{0}, it will be ignored when loading from {1}').format(err, options["source"])
self.unknowns.append({msg: option._subconfig})
continue
except ConfigError as err:
self.invalids.append({
_("{0}, it has been loaded from {1}").format(err, options["source"]): option._subconfig}
)
continue
except PropertiesOptionError as err:
self.unknowns.append({
_("{0}, it has been loaded from {1}").format(err, options["source"]): option._subconfig}
)
continue
except AttributeOptionError as err:
if err.code == "option-not-found":
err_path = err.path
if "." not in err_path:
subconfig = None
child_name = err_path
else:
parent_path, child_name = err_path.rsplit('.', 1)
subconfig = self.config.option(parent_path)
subconfig._set_subconfig()
err_msg = _(
'variable or family "{0}" does not exist so cannot load "{1}"'
).format(child_name, path)
if self.unknown_user_data_error:
msg = _(
'{0}, it has been loading from {1}'
)
else:
msg = _(
'{0}, it will be ignored when loading from {1}'
)
msg = msg.format(err_msg, options["source"])
if subconfig is not None:
msg = {msg: subconfig._subconfig}
self.unknowns.append(msg)
elif err.code == "option-dynamic":
if self.invalid_user_data_error:
msg = _(
'"{0}" is the name of a dynamic family, it has been loading from {1}'
)
else:
msg = _(
'"{0}" is the name of a dynamic family, it will be ignored when loading from {1}'
)
self.invalids.append({msg.format(option.description(with_quote=True), options["source"]): option._subconfig})
else:
self.invalids.append(
_("{0} loaded from {1}").format(err, options["source"])
)
continue
value = self.convert_value(
path, option, self.values[path].get("options", {}), value
)
if option.isfollower():
if not isinstance(value, tuple):
indexes = range(len(value))
else:
try:
indexes = range(len(option.parent().leader().value.get()))
except:
continue
values = value
else:
indexes = [None]
for index in indexes:
try:
if option.isfollower():
if not isinstance(value, tuple):
value = values[index]
if value is undefined or isinstance(value, CancelParam):
continue
index_ = index
else:
index_ = None
self.set_value(option, value, options.get("options", {}), index_)
except PropertiesOptionError as err:
if err.code == "property-error":
properties = display_list(
[_(prop) for prop in err.proptype], add_quote=False
)
err_path = err.subconfig.path
err_description = err.subconfig.option.impl_get_display_name(err.subconfig, with_quote=True)
display_name = option.description(with_quote=True)
if index is not None:
if path == err_path:
if self.unknown_user_data_error:
msg = _(
'variable {0} at index "{1}" is {2}, it has been loading from {3}'
)
else:
msg = _(
'variable {0} at index "{1}" is {2}, it will be ignored when loading from {3}'
)
self.unknowns.append({
msg.format(
display_name,
index,
properties,
options["source"],
): option._subconfig}
)
else:
if self.unknown_user_data_error:
msg = _(
'family {0} is {1}, {2} at index "{3}", it has been loading from {4}'
)
else:
msg = _(
'family {0} is {1}, {2} at index "{3}", it will be ignored when loading from {4}'
)
self.unknowns.append({
msg.format(
err_description,
properties,
display_name,
index,
options["source"],
): option._subconfig}
)
else:
if path == err_path:
if self.unknown_user_data_error:
msg = _(
"variable has propery {0}, it has been loading from {1}"
)
else:
msg = _(
"variable has property {0}, it will be ignored when loading from {1}"
)
self.unknowns.append({
msg.format(
properties, options["source"]
): option._subconfig}
)
else:
if self.unknown_user_data_error:
msg = _(
"family {0} has property {1}, so cannot access to {2}, it has been loading from {3}"
)
else:
msg = _(
"family {0} has property {1}, so cannot access to {2}, it will be ignored when loading from {3}"
)
self.unknowns.append({
msg.format(
err_description,
properties,
display_name,
options["source"],
): option._subconfig}
)
else:
if self.unknown_user_data_error:
msg = _(
"{0}, it has been loading from {1}"
)
else:
msg = _(
"{0}, it will be ignored when loading from {1}"
)
self.unknowns.append({
msg.format(err, options["source"]): option._subconfig}
)
except LeadershipError as err:
if self.unknown_user_data_error:
msg = _(
"{0}, it has been loading from {1}"
)
else:
msg = _(
"{0}, it will be ignored when loading from {1}"
)
self.unknowns.append({
msg.format(err, options["source"]): option._subconfig}
)
except ConfigError as err:
err.prefix = ""
if self.invalid_user_data_error:
msg = _('{0}, it has been loading from {1}').format(err, options["source"])
else:
msg = _('{0}, it will be ignored when loading from {1}').format(err, options["source"])
self.invalids.append({msg: option._subconfig})
except ValueError as err:
err.prefix = ""
type_ = option.type(translation=True)
msg = _('the value {0} is an invalid {1}, {2}').format(
self._display_value(option, value),
type_,
err,
)
if self.invalid_user_data_error:
msg += _(', it has been loading from {0}').format(options["source"])
else:
msg += _(', it will be ignored when loading from {0}').format(options["source"])
self.invalids.append({msg: option._subconfig})
except AttributeOptionError as err:
err.prefix = ""
if err.code == "option-dynamic":
continue
raise err from err
def set_value(self, option, value, options, index):
is_secret_manager = options.get("secret_manager", False)
option_without_index = option
if is_secret_manager and isinstance(value, tuple):
# it's a function
params = tuple([ParamValue(val) for val in value[1:]])
option.information.set('secret_manager', True)
if index is not None:
option = option.forcepermissive.index(index)
value = Calculation(value[0], Params(params, kwargs={"option": ParamValue(option)}))
option = option.forcepermissive
add_validation = True
else:
if index is not None:
option = option.index(index)
add_validation = False
option.value.set(value)
if add_validation:
option.property.add("validator")
path = option.path()
if "source" in self.values[path]:
if option.isfollower():
key = f"loaded_from_{index}"
else:
key = "loaded_from"
value = _("loaded from {0}").format(
self.values[path]["source"]
)
if options.get("secret_manager"):
# FIXME (true_config ???)
default = option.value.default()
if option.isleader():
default = default[0]
value = _('{0} (the search key is "{1}")').format(value, default)
option_without_index.information.set(
key,
value,
)
def convert_value(option, value, needs_convert):
if value == "":
return None
option_type = option.information.get("type")
if option_type == "port":
func = CONVERT_OPTION[option_type]["func"]
try:
return func(value)
except:
return value
if option_type == "choice":
try:
choices = option.value.list()
if value not in choices and isinstance(value, str):
# FIXME add other tests (boolean, float, ...)
if value.isnumeric() and int(value) in choices:
value = int(value)
except:
pass
func = CONVERT_OPTION.get(option_type, {}).get("func")
if func:
try:
return func(value)
except:
pass
return value

View file

@ -9,7 +9,7 @@ Cadoles (http://www.cadoles.com)
Copyright (C) 2019-2021
Silique (https://www.silique.fr)
Copyright (C) 2022-2024
Copyright (C) 2022-2026
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 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from typing import List, Union
from unicodedata import normalize, combining
import re
from itertools import chain
@ -45,6 +44,8 @@ from .error import DictConsistencyError
NAME_REGEXP = re.compile(r"^[a-z0-9_]*$")
PROPERTY_ATTRIBUTE = ["frozen", "hidden", "disabled", "mandatory"]
def valid_variable_family_name(
name: str,
@ -58,17 +59,6 @@ def valid_variable_family_name(
raise DictConsistencyError(msg, 76, xmlfiles)
def normalize_family(family_name: str) -> str:
"""replace space, accent, uppercase, ... by valid character"""
if not family_name:
return
family_name = family_name.lower()
family_name = family_name.replace("-", "_").replace(" ", "_").replace(".", "_")
nfkd_form = normalize("NFKD", family_name)
family_name = "".join([c for c in nfkd_form if not combining(c)])
return family_name.lower()
def load_modules(name, module) -> List[str]:
"""list all functions in a module"""
loader = SourceFileLoader(name, module)
@ -78,13 +68,10 @@ def load_modules(name, module) -> List[str]:
return eosfunc
def get_realpath(
path: str,
path_prefix: str,
) -> str:
if path_prefix:
return f"{path_prefix}.{path}"
return path
# def get_realpath(
# path: str,
# ) -> str:
# return path
def get_jinja_variable_to_param(
@ -93,12 +80,12 @@ def get_jinja_variable_to_param(
objectspace,
xmlfiles,
functions,
path_prefix,
version,
namespace,
):
try:
env = SandboxedEnvironment(loader=DictLoader({"tmpl": jinja_text}))
env.add_extension('jinja2.ext.do')
env.filters = functions
parsed_content = Parser(env, jinja_text, "", "").parse()
@ -114,10 +101,12 @@ def get_jinja_variable_to_param(
for g in parsed_content.find_all(Getattr):
variables.add(recurse_getattr(g))
except TemplateSyntaxError as err:
msg = _('error in jinja "{0}" for the variable "{1}": {2}').format(
msg = _('error for the variable "{1}" in jinja "{0}": {2}').format(
jinja_text, current_path, err
)
raise DictConsistencyError(msg, 39, xmlfiles) from err
except AttributeError:
pass
variables = list(variables)
variables.sort(reverse=True)
founded_variables = {}
@ -125,7 +114,6 @@ def get_jinja_variable_to_param(
for variable_path in variables:
variable, identifier = objectspace.paths.get_with_dynamic(
variable_path,
path_prefix,
current_path,
version,
namespace,
@ -140,7 +128,6 @@ def get_jinja_variable_to_param(
break
else:
unknown_variables.append(variable_path)
for variable_path in unknown_variables:
for v in founded_variables:
if get_common_path(v, variable_path) == v:
@ -152,7 +139,6 @@ def get_jinja_variable_to_param(
vpath = vpath.rsplit(".", 1)[0]
variable, identifier = objectspace.paths.get_with_dynamic(
vpath,
path_prefix,
current_path,
version,
namespace,
@ -165,3 +151,70 @@ def get_jinja_variable_to_param(
yield {}, None, root_path
for variable_path, data in founded_variables.items():
yield data[1], data[0], variable_path
def calc_multi_for_type_variable(
local_variable: "Variable",
variable_in_calculation_path: str,
variable_in_calculation: "Variable",
objectspace: "RougailConvert",
) -> Union[bool, str]:
variable_in_calculation_multi = variable_in_calculation.multi
if local_variable.path in objectspace.families:
# it's a family
local_variable_multi = None
else:
local_variable_multi = local_variable.multi
# variable is a leader
if variable_in_calculation.path in objectspace.leaders:
local_variable_parent = local_variable.path.rsplit(".", 1)[0]
variable_in_calculation_parent = variable_in_calculation.path.rsplit(
".", 1
)[0]
if local_variable_parent == variable_in_calculation_parent:
variable_in_calculation_multi = False
# variable is a follower
elif variable_in_calculation.path in objectspace.followers:
local_variable_parent = local_variable.path.rsplit(".", 1)[0]
variable_in_calculation_parent = variable_in_calculation.path.rsplit(
".", 1
)[0]
if local_variable_parent != variable_in_calculation_parent:
if variable_in_calculation_multi:
variable_in_calculation_multi = "submulti"
else:
variable_in_calculation_multi = True
# variable is in a dynamic family
if objectspace.paths.is_dynamic(variable_in_calculation.path):
common_path = get_common_path(
local_variable.path, variable_in_calculation_path
)
common_variable_path = variable_in_calculation_path
if common_path:
common_variable_path = common_variable_path[len(common_path) + 1 :]
count_identifiers = common_variable_path.count("{{ identifier }}")
if count_identifiers == 1:
if variable_in_calculation_multi is False:
variable_in_calculation_multi = True
else:
variable_in_calculation_multi = "submulti"
elif count_identifiers > 1:
variable_in_calculation_multi = "submulti"
return local_variable_multi, variable_in_calculation_multi
class Undefined:
pass
def get_properties_to_string():
return [
("mandatory", _("mandatory")),
("hidden", _("hidden")),
("disabled", _("disabled")),
("unique", _("unique")),
("force_store_value", _("auto modified")),
]
undefined = Undefined()

View file

@ -0,0 +1,8 @@
version: 1.1
file:
type: unix_filename
params:
allow_relative: true
default:
test/unknown_file

View file

@ -0,0 +1 @@
{}

View file

@ -2,7 +2,7 @@ from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
load_functions('../rougail-tests/funcs/test.py')
try:
groups.namespace
except:

View file

@ -2,7 +2,11 @@ from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
load_functions('../rougail-tests/funcs/test.py')
try:
groups.namespace
except:
groups.addgroup('namespace')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")

View file

@ -0,0 +1 @@
{}

View file

@ -0,0 +1 @@
{}

View file

@ -0,0 +1 @@
{}

View file

@ -0,0 +1 @@
{}

View file

@ -2,7 +2,7 @@ from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
load_functions('../rougail-tests/funcs/test.py')
try:
groups.namespace
except:
@ -10,6 +10,5 @@ except:
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
optiondescription_1 = OptionDescription(name="1", doc="1", children=[], properties=frozenset({"advanced"}))
optiondescription_2 = OptionDescription(name="2", doc="2", children=[], properties=frozenset({"advanced"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1, optiondescription_2])
optiondescription_1 = OptionDescription(name="rougail", doc="Rougail", group_type=groups.namespace, children=[], properties=frozenset({"advanced"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1])

View file

@ -2,7 +2,7 @@ from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
load_functions('../rougail-tests/funcs/test.py')
try:
groups.namespace
except:
@ -10,6 +10,4 @@ except:
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
optiondescription_1 = OptionDescription(name="1", doc="1", children=[], properties=frozenset({"advanced"}))
optiondescription_5 = OptionDescription(name="2", doc="2", children=[], properties=frozenset({"advanced"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1, optiondescription_5])
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[])

View file

@ -2,7 +2,7 @@ from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
load_functions('../rougail-tests/funcs/test.py')
try:
groups.namespace
except:
@ -10,6 +10,5 @@ except:
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
optiondescription_1 = OptionDescription(name="1", doc="1", children=[], properties=frozenset({"advanced"}))
optiondescription_4 = OptionDescription(name="2", doc="2", children=[], properties=frozenset({"advanced"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1, optiondescription_4])
optiondescription_1 = OptionDescription(name="rougail", doc="Rougail", group_type=groups.namespace, children=[], properties=frozenset({"advanced"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1])

View file

@ -2,7 +2,7 @@ from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
load_functions('../rougail-tests/funcs/test.py')
try:
groups.namespace
except:
@ -10,6 +10,4 @@ except:
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
optiondescription_1 = OptionDescription(name="1", doc="1", children=[], properties=frozenset({"advanced"}))
optiondescription_4 = OptionDescription(name="2", doc="2", children=[], properties=frozenset({"advanced"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1, optiondescription_4])
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[])

View file

@ -0,0 +1,14 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('../rougail-tests/funcs/test.py')
try:
groups.namespace
except:
groups.addgroup('namespace')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
optiondescription_1 = OptionDescription(name="rougail", doc="Rougail", group_type=groups.namespace, children=[], properties=frozenset({"advanced"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1])

View file

@ -0,0 +1,13 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('../rougail-tests/funcs/test.py')
try:
groups.namespace
except:
groups.addgroup('namespace')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[])

View file

@ -1,3 +0,0 @@
---
_version: '1.1'
version: # a variable

View file

@ -0,0 +1,3 @@
{
"rougail.version": null
}

View file

@ -2,7 +2,7 @@ from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
load_functions('../rougail-tests/funcs/test.py')
try:
groups.namespace
except:
@ -10,6 +10,6 @@ except:
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_2 = StrOption(name="version", doc="a variable", properties=frozenset({"basic", "mandatory"}), informations={'type': 'string'})
option_2 = StrOption(name="version", doc="a variable", properties=frozenset({"basic", "mandatory"}), informations={'ymlfiles': ['../rougail-tests/structures/00_0version_underscore/rougail/00-base.yml'], 'type': 'string'})
optiondescription_1 = OptionDescription(name="rougail", doc="Rougail", group_type=groups.namespace, children=[option_2], properties=frozenset({"basic"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1])

View file

@ -1,19 +0,0 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
try:
groups.namespace
except:
groups.addgroup('namespace')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_3 = StrOption(name="version", doc="a variable", properties=frozenset({"basic", "mandatory"}), informations={'type': 'string'})
optiondescription_2 = OptionDescription(name="rougail", doc="Rougail", group_type=groups.namespace, children=[option_3], properties=frozenset({"basic"}))
optiondescription_1 = OptionDescription(name="1", doc="1", children=[optiondescription_2], properties=frozenset({"basic"}))
option_6 = StrOption(name="version", doc="a variable", properties=frozenset({"basic", "mandatory"}), informations={'type': 'string'})
optiondescription_5 = OptionDescription(name="rougail", doc="Rougail", group_type=groups.namespace, children=[option_6], properties=frozenset({"basic"}))
optiondescription_4 = OptionDescription(name="2", doc="2", children=[optiondescription_5], properties=frozenset({"basic"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1, optiondescription_4])

View file

@ -2,9 +2,13 @@ from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
load_functions('../rougail-tests/funcs/test.py')
try:
groups.namespace
except:
groups.addgroup('namespace')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_1 = StrOption(name="version", doc="a variable", properties=frozenset({"basic", "mandatory"}), informations={'type': 'string'})
option_1 = StrOption(name="version", doc="a variable", properties=frozenset({"basic", "mandatory"}), informations={'ymlfiles': ['../rougail-tests/structures/00_0version_underscore/rougail/00-base.yml'], 'type': 'string'})
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[option_1])

View file

@ -1,3 +0,0 @@
---
version: '1.0'
empty:

View file

@ -0,0 +1,3 @@
{
"rougail.empty": null
}

View file

@ -2,7 +2,7 @@ from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
load_functions('../rougail-tests/funcs/test.py')
try:
groups.namespace
except:
@ -10,6 +10,6 @@ except:
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_2 = StrOption(name="empty", doc="empty", properties=frozenset({"basic", "mandatory"}), informations={'type': 'string'})
option_2 = StrOption(name="empty", doc="empty", properties=frozenset({"basic", "mandatory"}), informations={'ymlfiles': ['../rougail-tests/structures/00_1empty_variable/rougail/00-base.yml'], 'type': 'string'})
optiondescription_1 = OptionDescription(name="rougail", doc="Rougail", group_type=groups.namespace, children=[option_2], properties=frozenset({"basic"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1])

View file

@ -1,19 +0,0 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
try:
groups.namespace
except:
groups.addgroup('namespace')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_3 = StrOption(name="empty", doc="empty", properties=frozenset({"basic", "mandatory"}), informations={'type': 'string'})
optiondescription_2 = OptionDescription(name="rougail", doc="Rougail", group_type=groups.namespace, children=[option_3], properties=frozenset({"basic"}))
optiondescription_1 = OptionDescription(name="1", doc="1", children=[optiondescription_2], properties=frozenset({"basic"}))
option_6 = StrOption(name="empty", doc="empty", properties=frozenset({"basic", "mandatory"}), informations={'type': 'string'})
optiondescription_5 = OptionDescription(name="rougail", doc="Rougail", group_type=groups.namespace, children=[option_6], properties=frozenset({"basic"}))
optiondescription_4 = OptionDescription(name="2", doc="2", children=[optiondescription_5], properties=frozenset({"basic"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1, optiondescription_4])

View file

@ -2,9 +2,13 @@ from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
load_functions('../rougail-tests/funcs/test.py')
try:
groups.namespace
except:
groups.addgroup('namespace')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_1 = StrOption(name="empty", doc="empty", properties=frozenset({"basic", "mandatory"}), informations={'type': 'string'})
option_1 = StrOption(name="empty", doc="empty", properties=frozenset({"basic", "mandatory"}), informations={'ymlfiles': ['../rougail-tests/structures/00_1empty_variable/rougail/00-base.yml'], 'type': 'string'})
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[option_1])

View file

@ -1,10 +0,0 @@
---
version: 1.1
var1: "no" # a first variable
var2:
description: a second variable
multi: true
default:
jinja: |
{{ _.var1 }}
description: the value of var1

View file

@ -0,0 +1,6 @@
{
"rougail.var1": "no",
"rougail.var2": [
"no"
]
}

View file

@ -2,7 +2,7 @@ from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
load_functions('../rougail-tests/funcs/test.py')
try:
groups.namespace
except:
@ -11,7 +11,7 @@ ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
dict_env['default_rougail.var2'] = "{{ _.var1 }}\n"
option_2 = StrOption(name="var1", doc="a first variable", default="no", properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
option_3 = StrOption(name="var2", doc="a second variable", multi=True, default=Calculation(func['jinja_to_function'], Params((), kwargs={'__internal_jinja': ParamValue("default_rougail.var2"), '__internal_type': ParamValue("string"), '__internal_multi': ParamValue(True), '__internal_files': ParamValue(['tests/dictionaries/00_2default_calculated/dictionaries/rougail/00-base.yml']), '__internal_attribute': ParamValue("default"), '__internal_variable': ParamValue("rougail.var2"), '_.var1': ParamOption(option_2, notraisepropertyerror=True)})), properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
option_2 = StrOption(name="var1", doc="a first variable", default="no", properties=frozenset({"mandatory", "standard"}), informations={'ymlfiles': ['../rougail-tests/structures/00_2default_calculated/rougail/00-base.yml'], 'type': 'string'})
option_3 = StrOption(name="var2", doc="a second variable", multi=True, default=Calculation(func['jinja_to_function'], Params((), kwargs={'__internal_jinja': ParamValue("default_rougail.var2"), '__internal_type': ParamValue("string"), '__internal_multi': ParamValue(True), '__internal_files': ParamValue(['../rougail-tests/structures/00_2default_calculated/rougail/00-base.yml']), '__internal_attribute': ParamValue("default"), '__internal_variable': ParamValue("rougail.var2"), '_.var1': ParamOption(option_2, notraisepropertyerror=True)})), properties=frozenset({"mandatory", "standard"}), informations={'ymlfiles': ['../rougail-tests/structures/00_2default_calculated/rougail/00-base.yml'], 'type': 'string'})
optiondescription_1 = OptionDescription(name="rougail", doc="Rougail", group_type=groups.namespace, children=[option_2, option_3], properties=frozenset({"standard"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1])

View file

@ -1,23 +0,0 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
try:
groups.namespace
except:
groups.addgroup('namespace')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
dict_env['default_1.rougail.var2'] = "{{ _.var1 }}\n"
dict_env['default_2.rougail.var2'] = "{{ _.var1 }}\n"
option_3 = StrOption(name="var1", doc="a first variable", default="no", properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
option_4 = StrOption(name="var2", doc="a second variable", multi=True, default=Calculation(func['jinja_to_function'], Params((), kwargs={'__internal_jinja': ParamValue("default_1.rougail.var2"), '__internal_type': ParamValue("string"), '__internal_multi': ParamValue(True), '__internal_files': ParamValue(['tests/dictionaries/00_2default_calculated/dictionaries/rougail/00-base.yml']), '__internal_attribute': ParamValue("default"), '__internal_variable': ParamValue("1.rougail.var2"), '_.var1': ParamOption(option_3, notraisepropertyerror=True)})), properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
optiondescription_2 = OptionDescription(name="rougail", doc="Rougail", group_type=groups.namespace, children=[option_3, option_4], properties=frozenset({"standard"}))
optiondescription_1 = OptionDescription(name="1", doc="1", children=[optiondescription_2], properties=frozenset({"standard"}))
option_7 = StrOption(name="var1", doc="a first variable", default="no", properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
option_8 = StrOption(name="var2", doc="a second variable", multi=True, default=Calculation(func['jinja_to_function'], Params((), kwargs={'__internal_jinja': ParamValue("default_2.rougail.var2"), '__internal_type': ParamValue("string"), '__internal_multi': ParamValue(True), '__internal_files': ParamValue(['tests/dictionaries/00_2default_calculated/dictionaries/rougail/00-base.yml']), '__internal_attribute': ParamValue("default"), '__internal_variable': ParamValue("2.rougail.var2"), '_.var1': ParamOption(option_7, notraisepropertyerror=True)})), properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
optiondescription_6 = OptionDescription(name="rougail", doc="Rougail", group_type=groups.namespace, children=[option_7, option_8], properties=frozenset({"standard"}))
optiondescription_5 = OptionDescription(name="2", doc="2", children=[optiondescription_6], properties=frozenset({"standard"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1, optiondescription_5])

View file

@ -2,11 +2,15 @@ from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
load_functions('../rougail-tests/funcs/test.py')
try:
groups.namespace
except:
groups.addgroup('namespace')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
dict_env['default_var2'] = "{{ _.var1 }}\n"
option_1 = StrOption(name="var1", doc="a first variable", default="no", properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
option_2 = StrOption(name="var2", doc="a second variable", multi=True, default=Calculation(func['jinja_to_function'], Params((), kwargs={'__internal_jinja': ParamValue("default_var2"), '__internal_type': ParamValue("string"), '__internal_multi': ParamValue(True), '__internal_files': ParamValue(['tests/dictionaries/00_2default_calculated/dictionaries/rougail/00-base.yml']), '__internal_attribute': ParamValue("default"), '__internal_variable': ParamValue("var2"), '_.var1': ParamOption(option_1, notraisepropertyerror=True)})), properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
option_1 = StrOption(name="var1", doc="a first variable", default="no", properties=frozenset({"mandatory", "standard"}), informations={'ymlfiles': ['../rougail-tests/structures/00_2default_calculated/rougail/00-base.yml'], 'type': 'string'})
option_2 = StrOption(name="var2", doc="a second variable", multi=True, default=Calculation(func['jinja_to_function'], Params((), kwargs={'__internal_jinja': ParamValue("default_var2"), '__internal_type': ParamValue("string"), '__internal_multi': ParamValue(True), '__internal_files': ParamValue(['../rougail-tests/structures/00_2default_calculated/rougail/00-base.yml']), '__internal_attribute': ParamValue("default"), '__internal_variable': ParamValue("var2"), '_.var1': ParamOption(option_1, notraisepropertyerror=True)})), properties=frozenset({"mandatory", "standard"}), informations={'ymlfiles': ['../rougail-tests/structures/00_2default_calculated/rougail/00-base.yml'], 'type': 'string'})
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[option_1, option_2])

View file

@ -1,15 +0,0 @@
---
version: 1.1
var1: # a first variable
- 'no'
- 'yes'
- maybe
var2:
description: a second variable
multi: true
default:
jinja: |
{% for val in _.var1 %}
{{ val }}
{% endfor %}
description: the value of _.var1

View file

@ -0,0 +1,12 @@
{
"rougail.var1": [
"no",
"yes",
"maybe"
],
"rougail.var2": [
"no",
"yes",
"maybe"
]
}

View file

@ -2,7 +2,7 @@ from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
load_functions('../rougail-tests/funcs/test.py')
try:
groups.namespace
except:
@ -11,7 +11,7 @@ ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
dict_env['default_rougail.var2'] = "{% for val in _.var1 %}\n{{ val }}\n{% endfor %}\n"
option_2 = StrOption(name="var1", doc="a first variable", multi=True, default=["no", "yes", "maybe"], default_multi="no", properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
option_3 = StrOption(name="var2", doc="a second variable", multi=True, default=Calculation(func['jinja_to_function'], Params((), kwargs={'__internal_jinja': ParamValue("default_rougail.var2"), '__internal_type': ParamValue("string"), '__internal_multi': ParamValue(True), '__internal_files': ParamValue(['tests/dictionaries/00_2default_calculated_multi/dictionaries/rougail/00-base.yml']), '__internal_attribute': ParamValue("default"), '__internal_variable': ParamValue("rougail.var2"), '_.var1': ParamOption(option_2, notraisepropertyerror=True)})), properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
option_2 = StrOption(name="var1", doc="a first variable", multi=True, default=["no", "yes", "maybe"], default_multi="no", properties=frozenset({"mandatory", "standard"}), informations={'ymlfiles': ['../rougail-tests/structures/00_2default_calculated_multi/rougail/00-base.yml'], 'type': 'string'})
option_3 = StrOption(name="var2", doc="a second variable", multi=True, default=Calculation(func['jinja_to_function'], Params((), kwargs={'__internal_jinja': ParamValue("default_rougail.var2"), '__internal_type': ParamValue("string"), '__internal_multi': ParamValue(True), '__internal_files': ParamValue(['../rougail-tests/structures/00_2default_calculated_multi/rougail/00-base.yml']), '__internal_attribute': ParamValue("default"), '__internal_variable': ParamValue("rougail.var2"), '_.var1': ParamOption(option_2, notraisepropertyerror=True)})), properties=frozenset({"mandatory", "standard"}), informations={'ymlfiles': ['../rougail-tests/structures/00_2default_calculated_multi/rougail/00-base.yml'], 'type': 'string'})
optiondescription_1 = OptionDescription(name="rougail", doc="Rougail", group_type=groups.namespace, children=[option_2, option_3], properties=frozenset({"standard"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1])

View file

@ -1,23 +0,0 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
try:
groups.namespace
except:
groups.addgroup('namespace')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
dict_env['default_1.rougail.var2'] = "{% for val in _.var1 %}\n{{ val }}\n{% endfor %}\n"
dict_env['default_2.rougail.var2'] = "{% for val in _.var1 %}\n{{ val }}\n{% endfor %}\n"
option_3 = StrOption(name="var1", doc="a first variable", multi=True, default=["no", "yes", "maybe"], default_multi="no", properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
option_4 = StrOption(name="var2", doc="a second variable", multi=True, default=Calculation(func['jinja_to_function'], Params((), kwargs={'__internal_jinja': ParamValue("default_1.rougail.var2"), '__internal_type': ParamValue("string"), '__internal_multi': ParamValue(True), '__internal_files': ParamValue(['tests/dictionaries/00_2default_calculated_multi/dictionaries/rougail/00-base.yml']), '__internal_attribute': ParamValue("default"), '__internal_variable': ParamValue("1.rougail.var2"), '_.var1': ParamOption(option_3, notraisepropertyerror=True)})), properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
optiondescription_2 = OptionDescription(name="rougail", doc="Rougail", group_type=groups.namespace, children=[option_3, option_4], properties=frozenset({"standard"}))
optiondescription_1 = OptionDescription(name="1", doc="1", children=[optiondescription_2], properties=frozenset({"standard"}))
option_7 = StrOption(name="var1", doc="a first variable", multi=True, default=["no", "yes", "maybe"], default_multi="no", properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
option_8 = StrOption(name="var2", doc="a second variable", multi=True, default=Calculation(func['jinja_to_function'], Params((), kwargs={'__internal_jinja': ParamValue("default_2.rougail.var2"), '__internal_type': ParamValue("string"), '__internal_multi': ParamValue(True), '__internal_files': ParamValue(['tests/dictionaries/00_2default_calculated_multi/dictionaries/rougail/00-base.yml']), '__internal_attribute': ParamValue("default"), '__internal_variable': ParamValue("2.rougail.var2"), '_.var1': ParamOption(option_7, notraisepropertyerror=True)})), properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
optiondescription_6 = OptionDescription(name="rougail", doc="Rougail", group_type=groups.namespace, children=[option_7, option_8], properties=frozenset({"standard"}))
optiondescription_5 = OptionDescription(name="2", doc="2", children=[optiondescription_6], properties=frozenset({"standard"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1, optiondescription_5])

View file

@ -2,11 +2,15 @@ from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('tests/dictionaries/../eosfunc/test.py')
load_functions('../rougail-tests/funcs/test.py')
try:
groups.namespace
except:
groups.addgroup('namespace')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
dict_env['default_var2'] = "{% for val in _.var1 %}\n{{ val }}\n{% endfor %}\n"
option_1 = StrOption(name="var1", doc="a first variable", multi=True, default=["no", "yes", "maybe"], default_multi="no", properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
option_2 = StrOption(name="var2", doc="a second variable", multi=True, default=Calculation(func['jinja_to_function'], Params((), kwargs={'__internal_jinja': ParamValue("default_var2"), '__internal_type': ParamValue("string"), '__internal_multi': ParamValue(True), '__internal_files': ParamValue(['tests/dictionaries/00_2default_calculated_multi/dictionaries/rougail/00-base.yml']), '__internal_attribute': ParamValue("default"), '__internal_variable': ParamValue("var2"), '_.var1': ParamOption(option_1, notraisepropertyerror=True)})), properties=frozenset({"mandatory", "standard"}), informations={'type': 'string'})
option_1 = StrOption(name="var1", doc="a first variable", multi=True, default=["no", "yes", "maybe"], default_multi="no", properties=frozenset({"mandatory", "standard"}), informations={'ymlfiles': ['../rougail-tests/structures/00_2default_calculated_multi/rougail/00-base.yml'], 'type': 'string'})
option_2 = StrOption(name="var2", doc="a second variable", multi=True, default=Calculation(func['jinja_to_function'], Params((), kwargs={'__internal_jinja': ParamValue("default_var2"), '__internal_type': ParamValue("string"), '__internal_multi': ParamValue(True), '__internal_files': ParamValue(['../rougail-tests/structures/00_2default_calculated_multi/rougail/00-base.yml']), '__internal_attribute': ParamValue("default"), '__internal_variable': ParamValue("var2"), '_.var1': ParamOption(option_1, notraisepropertyerror=True)})), properties=frozenset({"mandatory", "standard"}), informations={'ymlfiles': ['../rougail-tests/structures/00_2default_calculated_multi/rougail/00-base.yml'], 'type': 'string'})
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[option_1, option_2])

View file

@ -0,0 +1,20 @@
{
"rougail.leadership.var1": {
"owner": "default",
"value": [
"a_value"
]
},
"rougail.leadership.var2": {
"owner": [
"default"
],
"value": [
"a_value"
]
},
"rougail.var2": {
"owner": "default",
"value": "a_value"
}
}

View file

@ -0,0 +1,9 @@
{
"rougail.leadership.var1": [
{
"rougail.leadership.var1": "a_value",
"rougail.leadership.var2": "a_value"
}
],
"rougail.var2": "a_value"
}

View file

@ -0,0 +1,20 @@
{
"rougail.leadership.var1": {
"owner": "default",
"value": [
"a_value"
]
},
"rougail.leadership.var2": {
"owner": [
"default"
],
"value": [
"a_value"
]
},
"rougail.var2": {
"owner": "default",
"value": "a_value"
}
}

View file

@ -0,0 +1,3 @@
{
"rougail.var2": "a_value"
}

View file

@ -0,0 +1,19 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('../rougail-tests/funcs/test.py')
try:
groups.namespace
except:
groups.addgroup('namespace')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
dict_env['default_rougail.var2'] = "{{ var1[0] }}"
option_3 = StrOption(name="var1", doc="a first variable", multi=True, default=["a_value"], properties=frozenset({"force_default_on_freeze", "frozen", "mandatory", "standard"}), informations={'ymlfiles': ['../rougail-tests/structures/00_2default_calculated_params_permissive/rougail/00-base.yml'], 'type': 'string'})
option_4 = StrOption(name="var2", doc="a first variable", multi=True, default_multi="a_value", properties=frozenset({"force_default_on_freeze", "frozen", "mandatory", "standard"}), informations={'ymlfiles': ['../rougail-tests/structures/00_2default_calculated_params_permissive/rougail/00-base.yml'], 'type': 'string'})
optiondescription_2 = Leadership(name="leadership", doc="leadership", children=[option_3, option_4], properties=frozenset({"hidden", "standard"}), informations={'ymlfiles': ['../rougail-tests/structures/00_2default_calculated_params_permissive/rougail/00-base.yml']})
option_5 = StrOption(name="var2", doc="a second variable", default=Calculation(func['jinja_to_function'], Params((), kwargs={'__internal_jinja': ParamValue("default_rougail.var2"), '__internal_type': ParamValue("string"), '__internal_multi': ParamValue(False), '__internal_files': ParamValue(['../rougail-tests/structures/00_2default_calculated_params_permissive/rougail/00-base.yml']), '__internal_attribute': ParamValue("default"), '__internal_variable': ParamValue("rougail.var2"), 'var1': ParamOption(option_3)})), properties=frozenset({"mandatory", "standard"}), informations={'ymlfiles': ['../rougail-tests/structures/00_2default_calculated_params_permissive/rougail/00-base.yml'], 'type': 'string'})
optiondescription_1 = OptionDescription(name="rougail", doc="Rougail", group_type=groups.namespace, children=[optiondescription_2, option_5], properties=frozenset({"standard"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1])

View file

@ -0,0 +1,18 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('../rougail-tests/funcs/test.py')
try:
groups.namespace
except:
groups.addgroup('namespace')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
dict_env['default_var2'] = "{{ var1[0] }}"
option_2 = StrOption(name="var1", doc="a first variable", multi=True, default=["a_value"], properties=frozenset({"force_default_on_freeze", "frozen", "mandatory", "standard"}), informations={'ymlfiles': ['../rougail-tests/structures/00_2default_calculated_params_permissive/rougail/00-base.yml'], 'type': 'string'})
option_3 = StrOption(name="var2", doc="a first variable", multi=True, default_multi="a_value", properties=frozenset({"force_default_on_freeze", "frozen", "mandatory", "standard"}), informations={'ymlfiles': ['../rougail-tests/structures/00_2default_calculated_params_permissive/rougail/00-base.yml'], 'type': 'string'})
optiondescription_1 = Leadership(name="leadership", doc="leadership", children=[option_2, option_3], properties=frozenset({"hidden", "standard"}), informations={'ymlfiles': ['../rougail-tests/structures/00_2default_calculated_params_permissive/rougail/00-base.yml']})
option_4 = StrOption(name="var2", doc="a second variable", default=Calculation(func['jinja_to_function'], Params((), kwargs={'__internal_jinja': ParamValue("default_var2"), '__internal_type': ParamValue("string"), '__internal_multi': ParamValue(False), '__internal_files': ParamValue(['../rougail-tests/structures/00_2default_calculated_params_permissive/rougail/00-base.yml']), '__internal_attribute': ParamValue("default"), '__internal_variable': ParamValue("var2"), 'var1': ParamOption(option_2)})), properties=frozenset({"mandatory", "standard"}), informations={'ymlfiles': ['../rougail-tests/structures/00_2default_calculated_params_permissive/rougail/00-base.yml'], 'type': 'string'})
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1, option_4])

View file

@ -0,0 +1,10 @@
{
"rougail.var1": {
"owner": "default",
"value": []
},
"rougail.var2": {
"owner": "default",
"value": []
}
}

View file

@ -0,0 +1,4 @@
{
"rougail.var1": [],
"rougail.var2": []
}

View file

@ -0,0 +1,10 @@
{
"rougail.var1": {
"owner": "default",
"value": []
},
"rougail.var2": {
"owner": "default",
"value": []
}
}

View file

@ -0,0 +1 @@
["rougail.var1", "rougail.var2"]

View file

@ -0,0 +1,4 @@
{
"rougail.var1": [],
"rougail.var2": []
}

View file

@ -0,0 +1,16 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('../rougail-tests/funcs/test.py')
try:
groups.namespace
except:
groups.addgroup('namespace')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_2 = DomainnameOption(name="var1", doc="a first variable", multi=True, type="domainname", allow_ip=True, properties=frozenset({"basic", "mandatory"}), informations={'ymlfiles': ['../rougail-tests/structures/00_2default_calculated_variable/rougail/00-base.yml'], 'type': 'domainname'})
option_3 = DomainnameOption(name="var2", doc="a second variable", multi=True, default=Calculation(func['calc_value'], Params((ParamOption(option_2)), kwargs={'__internal_multi': ParamValue(True)})), type="domainname", allow_ip=False, properties=frozenset({"mandatory", "standard"}), informations={'ymlfiles': ['../rougail-tests/structures/00_2default_calculated_variable/rougail/00-base.yml'], 'type': 'domainname'})
optiondescription_1 = OptionDescription(name="rougail", doc="Rougail", group_type=groups.namespace, children=[option_2, option_3], properties=frozenset({"basic"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1])

View file

@ -0,0 +1,15 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription
load_functions('../rougail-tests/funcs/test.py')
try:
groups.namespace
except:
groups.addgroup('namespace')
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
option_1 = DomainnameOption(name="var1", doc="a first variable", multi=True, type="domainname", allow_ip=True, properties=frozenset({"basic", "mandatory"}), informations={'ymlfiles': ['../rougail-tests/structures/00_2default_calculated_variable/rougail/00-base.yml'], 'type': 'domainname'})
option_2 = DomainnameOption(name="var2", doc="a second variable", multi=True, default=Calculation(func['calc_value'], Params((ParamOption(option_1)), kwargs={'__internal_multi': ParamValue(True)})), type="domainname", allow_ip=False, properties=frozenset({"mandatory", "standard"}), informations={'ymlfiles': ['../rougail-tests/structures/00_2default_calculated_variable/rougail/00-base.yml'], 'type': 'domainname'})
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[option_1, option_2])

View file

@ -0,0 +1,10 @@
{
"rougail.var1": {
"owner": "default",
"value": null
},
"rougail.var2": {
"owner": "default",
"value": null
}
}

View file

@ -0,0 +1,4 @@
{
"rougail.var1": null,
"rougail.var2": null
}

View file

@ -0,0 +1,10 @@
{
"rougail.var1": {
"owner": "default",
"value": null
},
"rougail.var2": {
"owner": "default",
"value": null
}
}

View file

@ -0,0 +1 @@
["rougail.var1", "rougail.var2"]

Some files were not shown because too many files have changed in this diff Show more