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) ## 1.1.1 (2024-11-06)
### Fix ### 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 gitea: none
# describe a variable my_first_variable include_toc: true
# and a family with a variable my_second_variable ---
my_first_variable: my_value [🇬🇧 (EN)](README.md) - [🇫🇷 (FR)](README.fr.md)
my_family:
my_second_variable: 1
```
## 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 > [!NOTE]
# rougail -m dict >
Variables: > **Path**: secret_manager\
┣━━ 📓 my_first_variable: my_value > `standard`
┗━━ 📂 my_family
┗━━ 📓 my_second_variable: 1
``` | 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 | Variable | Description | Default value | Type | Access control | Validator |
from rougail import Rougail, RougailConfig |------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------|------------------|------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
from pprint import pprint | **<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'] | Variable | Description | Default value | Type | Access control |
rougail = Rougail() |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------|-----------------|-------------------------------------------------------------------------------------------------|------------------|
config = rougail.run() | **<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` |
pprint(config.value.get(), sort_dicts=False)
```
The result is: ## Default parameters for option type
```json > [!NOTE]
{<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}}} > **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 "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "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" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -15,75 +15,437 @@ msgstr ""
"Generated-By: pygettext.py 1.5\n" "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}" msgid "default variable mode \"{0}\" is not a valid mode, valid modes are {1}"
msgstr "" 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}" msgid "default family mode \"{0}\" is not a valid mode, valid modes are {1}"
msgstr "" 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}" msgid "mode \"{0}\" for \"{1}\" is not a valid mode, valid modes are {2}"
msgstr "" 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" msgid "mode \"{0}\" for \"{1}\" is not a valid mode, no modes are available"
msgstr "" 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}\"" msgid "the variable \"{0}\" is mandatory so in \"{1}\" mode but family has the higher family mode \"{2}\""
msgstr "" 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}\"" msgid "the follower \"{0}\" is in \"{1}\" mode but leader have the higher mode \"{2}\""
msgstr "" 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}\"" msgid "the family \"{0}\" is in \"{1}\" mode but variables and families inside have the higher modes \"{2}\""
msgstr "" 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}\"" msgid "the variable \"{0}\" is in \"{1}\" mode but family has the higher family mode \"{2}\""
msgstr "" msgstr ""
#: src/rougail/annotator/value.py:77 #: src/rougail/annotator/property.py:181
msgid "the follower \"{0}\" without multi attribute can only have one value" msgid "invalid tag name \"{0}\" should only contains lowercase ascii character, number or _"
msgstr "" 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" msgid "the variable \"{0}\" is multi but has a non list default value"
msgstr "" 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" msgid "the variable \"{0}\" has regexp attribut but has not the \"regexp\" type"
msgstr "" 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" msgid "the variable \"{0}\" has choices attribut but has not the \"choice\" type"
msgstr "" 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}" msgid "the variable \"{0}\" has an unvalid default value \"{1}\" should be in {2}"
msgstr "" msgstr ""
#: src/rougail/convert.py:281 #: src/rougail/config/__init__.py:272
msgid "A variable or a family located in the \"{0}\" namespace shall not be used in the \"{1}\" namespace" msgid "Default version of the structural file format"
msgstr "" 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}" msgid "unknown type {0} for {1}"
msgstr "" msgstr ""
#: src/rougail/convert.py:1345 #: src/rougail/convert/convert.py:444
msgid "duplicate dictionary file name {0}" msgid "family \"{0}\" define multiple time"
msgstr "" 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" msgid "Cannot execute annotate multiple time"
msgstr "" 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}" msgid "{0} in {1}"
msgstr "" msgstr ""
@ -95,23 +457,368 @@ msgstr ""
msgid "conflict alternative_name \"{0}\": \"{1}\" and \"{2}\"" msgid "conflict alternative_name \"{0}\": \"{1}\" and \"{2}\""
msgstr "" msgstr ""
#: src/rougail/structural_commandline/annotator.py:95 #: src/rougail/structural_directory/__init__.py:130
msgid "negative_description is mandatory for boolean variable, but \"{0}\" hasn't" msgid "duplicate structural file name {0}"
msgstr "" msgstr ""
#: src/rougail/structural_commandline/annotator.py:104 #: src/rougail/structural_directory/config.py:32
msgid "negative_description is only available for boolean variable, but \"{0}\" is \"{1}\"" msgid "Main namespace name"
msgstr "" msgstr ""
#: src/rougail/update/update.py:738 #: src/rougail/structural_directory/config.py:40
msgid "not a XML file: {0}" msgid "directory or string is not in \"_.step.structural\""
msgstr "" 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 _" msgid "invalid variable or family name \"{0}\" must only contains lowercase ascii character, number or _"
msgstr "" msgstr ""
#: src/rougail/utils.py:117 #: src/rougail/utils.py:104
msgid "error in jinja \"{0}\" for the variable \"{1}\": {2}" 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 "" msgstr ""

View file

@ -1,50 +1,18 @@
[build-system]
build-backend = "flit_core.buildapi"
requires = ["flit_core >=3.8.0,<4"]
[project] [project]
name = "rougail" name = "rougail"
version = "1.1.1" 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.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"
[tool.commitizen] [tool.commitizen]
name = "cz_conventional_commits" name = "cz_conventional_commits"
tag_format = "$version" tag_format = "$version"
version_scheme = "pep440" version_scheme = "pep440"
version_provider = "pep621" 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 update_changelog_on_bump = true
changelog_merge_prerelease = 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 Copyright (C) 2019-2021
Silique (https://www.silique.fr) 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 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 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/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
""" """
from tiramisu import Config, undefined from .__version__ import __version__
from tiramisu.error import PropertiesOptionError, LeadershipError, ConfigError
from warnings import warn
from typing import List
from re import compile, findall
from .convert import RougailConvert try:
from .config import RougailConfig from .convert import Rougail
from .update import RougailUpgrade from .config import RougailConfig
from .object_model import CONVERT_OPTION
from .utils import normalize_family
__all__ = ("Rougail", "RougailConfig", "__version__")
def tiramisu_display_name( except ModuleNotFoundError as err:
kls, __all__ = ("__version__",)
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")

View file

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

View file

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

View file

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

View file

@ -9,7 +9,7 @@ Cadoles (http://www.cadoles.com)
Copyright (C) 2019-2021 Copyright (C) 2019-2021
Silique (https://www.silique.fr) 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 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 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/>. 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.i18n import _
from rougail.error import DictConsistencyError from rougail.error import DictConsistencyError
from rougail.annotator.variable import Walk 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 = ( PROPERTIES = (
@ -49,33 +52,56 @@ class Annotator(Walk):
def __init__(self, objectspace, *args) -> None: def __init__(self, objectspace, *args) -> None:
self.objectspace = objectspace self.objectspace = objectspace
if not self.objectspace.paths:
return
self.frozen = {} self.frozen = {}
if self.objectspace.paths: self.variables_default_transitive = []
self.convert_leadership()
self.convert_family() self.convert_family()
self.convert_variable() 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: def convert_family(self) -> None:
"""convert families""" """convert families"""
for family in self.get_families(): for family in self.get_families():
self._convert_property(family) self.family_variable_property(family)
# collect for force_default_on_freeze # collect for force_default_on_freeze
if family.hidden: 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.path,
family.hidden, frozen,
) )
def set_variable_frozen( def set_variable_frozen_inside_family(
self, self,
family_path: str, family_path: str,
hidden: Union[bool, Calculation], frozen: Union[bool, Calculation],
) -> None: ) -> None:
for variable_path in self.objectspace.parents[family_path]: for variable_path in self.objectspace.parents[family_path]:
if variable_path in self.objectspace.families: if variable_path in self.objectspace.families:
# it's a family # it's a family
self.set_variable_frozen( self.set_variable_frozen_inside_family(
variable_path, variable_path,
hidden, frozen,
) )
else: else:
# it's a variable # it's a variable
@ -84,51 +110,48 @@ class Annotator(Walk):
if ( if (
self.frozen.get(variable.path) is True self.frozen.get(variable.path) is True
or variable.hidden is True or variable.hidden is True
or hidden is True or frozen is True
): ):
self.frozen[variable.path] = True self.frozen[variable.path] = True
elif variable.path in self.frozen:
self.frozen[variable.path].append(hidden)
else: 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: def convert_variable(self) -> None:
"""convert variables""" """convert variables"""
for variable in self.get_variables(): for variable in self.get_variables():
if variable.path.startswith("services."):
continue
if variable.type == "symlink": if variable.type == "symlink":
continue continue
self._convert_variable_property(variable) self.convert_variable_property(variable)
def _convert_variable_property( def convert_variable_property(
self, self,
variable: dict, variable: dict,
) -> None: ) -> None:
"""convert properties""" """convert properties"""
path = variable.path path = variable.path
self._convert_property(variable) self.family_variable_property(variable)
if variable.hidden: if variable.hidden:
if variable.hidden is True: if variable.hidden is True:
self.frozen[path] = True self.frozen[path] = True
elif self.frozen.get(path) is not 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 path in self.frozen:
frozen = self.frozen[path] if not isinstance(self.frozen, list):
if frozen is True: self.frozen[path] = [self.frozen[path]]
value = True self.frozen[path].append(frozen)
else: else:
value = [] self.frozen[path] = frozen
for calculation in frozen: if path in self.frozen:
calculation_copy = calculation.copy() self.objectspace.properties.add(path, "frozen", self.frozen[path])
calculation_copy.attribute_name = "frozen" if not variable.auto_save and not variable.secret_manager:
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:
# if auto_save, save calculated value # if auto_save, save calculated value
self.objectspace.properties.add(path, "force_default_on_freeze", True) self.objectspace.properties.add(path, "force_default_on_freeze", True)
if not variable.empty and self.objectspace.multis.get(variable.path, False): 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) self.objectspace.properties.add(path, "notunique", True)
if variable.auto_save: if variable.auto_save:
self.objectspace.properties.add(path, "force_store_value", True) 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, self,
obj: dict, obj: dict,
) -> None: ) -> None:

View file

@ -9,7 +9,7 @@ Cadoles (http://www.cadoles.com)
Copyright (C) 2019-2021 Copyright (C) 2019-2021
Silique (https://www.silique.fr) 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 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 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.i18n import _
from rougail.error import DictConsistencyError from rougail.error import DictConsistencyError
from rougail.object_model import Calculation from rougail.convert.object_model import Calculation
class Annotator(Walk): # pylint: disable=R0903 class Annotator(Walk): # pylint: disable=R0903
@ -47,6 +47,7 @@ class Annotator(Walk): # pylint: disable=R0903
self.objectspace = objectspace self.objectspace = objectspace
self.convert_value() self.convert_value()
self.valid_choices() self.valid_choices()
self.valid_regexp()
def convert_value(self) -> None: def convert_value(self) -> None:
"""convert value""" """convert value"""
@ -75,8 +76,8 @@ class Annotator(Walk): # pylint: disable=R0903
raise DictConsistencyError(msg, 68, variable.xmlfiles) raise DictConsistencyError(msg, 68, variable.xmlfiles)
if variable.path in self.objectspace.followers and multi != "submulti": if variable.path in self.objectspace.followers and multi != "submulti":
msg = _( msg = _(
'the follower "{0}" without multi attribute can only have one value' 'the follower "{0}" is not multi, so cannot have a list has default value'
).format(variable.name) ).format(variable.path)
raise DictConsistencyError(msg, 87, variable.xmlfiles) raise DictConsistencyError(msg, 87, variable.xmlfiles)
if not variable.default: if not variable.default:
variable.default = None variable.default = None
@ -92,7 +93,7 @@ class Annotator(Walk): # pylint: disable=R0903
elif variable.multi: elif variable.multi:
msg = _( msg = _(
'the variable "{0}" is multi but has a non list default value' 'the variable "{0}" is multi but has a non list default value'
).format(variable.name) ).format(variable.path)
raise DictConsistencyError(msg, 12, variable.xmlfiles) raise DictConsistencyError(msg, 12, variable.xmlfiles)
elif variable.path in self.objectspace.followers: elif variable.path in self.objectspace.followers:
self.objectspace.default_multi[variable.path] = variable.default self.objectspace.default_multi[variable.path] = variable.default
@ -114,7 +115,9 @@ class Annotator(Walk): # pylint: disable=R0903
if isinstance(variable.choices, Calculation): if isinstance(variable.choices, Calculation):
continue continue
if variable.choices is None: 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) raise DictConsistencyError(msg, 19, variable.xmlfiles)
if not variable.mandatory and not variable.multi: if not variable.mandatory and not variable.multi:
self.add_choice_nil(variable) self.add_choice_nil(variable)
@ -125,3 +128,13 @@ class Annotator(Walk): # pylint: disable=R0903
if choice is None: if choice is None:
return return
variable.choices.append(None) 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 Copyright (C) 2019-2021
Silique (https://www.silique.fr) 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 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 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/>. 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 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: class Walk:
@ -41,8 +51,6 @@ class Walk:
for path in self.objectspace.variables: for path in self.objectspace.variables:
yield self.objectspace.paths[path] yield self.objectspace.paths[path]
# yield from get_variables(self.objectspace)
def get_families(self): def get_families(self):
"""Iter all families from the objectspace""" """Iter all families from the objectspace"""
for path in self.objectspace.families: for path in self.objectspace.families:
@ -62,50 +70,146 @@ class Annotator(Walk): # pylint: disable=R0903
if not objectspace.paths: if not objectspace.paths:
return return
self.objectspace = objectspace 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` # default type inference from a default value with :term:`basic types`
self.basic_types = { self.basic_types = {
str: "string", str: "string",
int: "number", int: "integer",
bool: "boolean", bool: "boolean",
float: "float", float: "float",
} }
self.verify_secret_managers()
self.verify_choices() self.verify_choices()
self.convert_variable() self.convert_variable()
self.convert_test() self.convert_test()
self.convert_examples() self.convert_examples()
self.convert_help() 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): def convert_variable(self):
"""convert variable""" """convert variable"""
for variable in self.get_variables(): for variable in self.get_variables():
if variable.version != "1.0":
if variable.type == "symlink": if variable.type == "symlink":
continue continue
if variable.version != "1.0":
self._convert_variable_inference(variable) self._convert_variable_inference(variable)
self._convert_variable_multi(variable)
for variable in self.get_variables(): for variable in self.get_variables():
if variable.type == "symlink": if variable.type == "symlink":
continue continue
if variable.version != "1.0": if variable.type in RENAME_TYPE:
self._default_variable_copy_informations(variable) warning = f'the variable "{ variable.path }" has a depreciated type "{variable.type}", please use "{RENAME_TYPE[variable.type]}" instead in {display_xmlfiles(variable.xmlfiles)}'
if variable.multi is None: warn(
variable.multi = False warning,
if variable.type is None: DeprecationWarning,
variable.type = "string" )
self.objectspace.informations.add(variable.path, "type", variable.type) 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) 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( def _convert_variable_inference(
self, self,
variable, variable,
) -> None: ) -> None:
# variable has no type # variable has no type
if variable.type is None: if variable.type is not None:
return
# choice type inference from the `choices` attribute # choice type inference from the `choices` attribute
if variable.choices is not None: if variable.choices is not None:
variable.type = "choice" variable.type = "choice"
@ -117,50 +221,68 @@ class Annotator(Walk): # pylint: disable=R0903
else: else:
tested_value = variable.default tested_value = variable.default
variable.type = self.basic_types.get(type(tested_value), None) variable.type = self.basic_types.get(type(tested_value), None)
def _convert_variable_multi(
self,
variable,
) -> None:
# variable has no multi attribute # variable has no multi attribute
if variable.multi is None and not ( if variable.multi is not None:
variable.type is None and isinstance(variable.default, VariableCalculation) return
):
if variable.path in self.objectspace.leaders: if variable.path in self.objectspace.leaders:
variable.multi = True 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: else:
variable.multi = isinstance(variable.default, list) variable.multi = isinstance(variable.default, list)
def _default_variable_copy_informations( def _default_variable_copy_informations(
self, self,
variable, variable,
calculated_variable,
) -> None: ) -> 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 # 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 variable.type = calculated_variable.type
if variable.params is None and calculated_variable.params is not None: if variable.params is None and calculated_variable.params is not None:
variable.params = calculated_variable.params variable.params = calculated_variable.params
# copy multi attribut if variable.type == "choice" and variable.choices is None:
if variable.multi is None: variable.choices = calculated_variable.choices
calculated_path = calculated_variable.path if isinstance(variable.choices, VariableCalculation):
if ( variable.choices = variable.choices.model_copy()
calculated_path in self.objectspace.leaders variable.choices.variable = self.objectspace.paths.get_full_path(
and variable.path in self.objectspace.followers variable.choices.variable,
and calculated_path.rsplit(".")[0] == variable.path.rsplit(".")[0] calculated_variable.path,
): )
variable.multi = False if variable.type == "regexp" and variable.regexp is None:
else: variable.regexp = calculated_variable.regexp
variable.multi = calculated_variable.multi
def _convert_variable( def _convert_variable(
self, self,
@ -169,6 +291,10 @@ class Annotator(Walk): # pylint: disable=R0903
# variable without description: description is the name # variable without description: description is the name
if not variable.description: if not variable.description:
variable.description = variable.name 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 variable.path in self.objectspace.followers:
if not variable.multi: if not variable.multi:
self.objectspace.multis[variable.path] = True self.objectspace.multis[variable.path] = True
@ -176,15 +302,6 @@ class Annotator(Walk): # pylint: disable=R0903
self.objectspace.multis[variable.path] = "submulti" self.objectspace.multis[variable.path] = "submulti"
elif variable.multi: elif variable.multi:
self.objectspace.multis[variable.path] = True 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": if variable.regexp is not None and variable.type != "regexp":
msg = _( msg = _(
'the variable "{0}" has regexp attribut but has not the "regexp" type' '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 Copyright (C) 2019-2021
Silique (https://www.silique.fr) 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 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 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 json import dumps
from os.path import isfile, basename from os.path import isfile, basename
from .i18n import _ from ..i18n import _
from .error import DictConsistencyError, VariableCalculationDependencyError from ..error import DictConsistencyError, VariableCalculationDependencyError
from .utils import normalize_family from ..tiramisu import normalize_family, CONVERT_OPTION
from .object_model import Calculation, CONVERT_OPTION from .object_model import Calculation
class BaseElt: # pylint: disable=R0903 class BaseElt: # pylint: disable=R0903
@ -73,12 +73,7 @@ class TiramisuReflector:
"from tiramisu import *", "from tiramisu import *",
"from tiramisu.setting import ALLOWED_LEADER_PROPERTIES", "from tiramisu.setting import ALLOWED_LEADER_PROPERTIES",
"from re import compile as re_compile", "from re import compile as re_compile",
] "from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription",
)
if self.objectspace.export_with_import:
self.text["header"].extend(
[
"from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription"
] ]
) )
if funcs_paths: if funcs_paths:
@ -87,7 +82,7 @@ class TiramisuReflector:
continue continue
self.text["header"].append(f"load_functions('{funcs_path}')") self.text["header"].append(f"load_functions('{funcs_path}')")
if self.objectspace.export_with_import: if self.objectspace.export_with_import:
if objectspace.main_namespace: # if self.objectspace.has_namespace:
self.text["header"].extend( self.text["header"].extend(
[ [
"try:", "try:",
@ -131,33 +126,6 @@ class TiramisuReflector:
elt, elt,
self, 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.name = normalize_family(self.objectspace.base_option_name)
baseelt.description = self.objectspace.base_option_name baseelt.description = self.objectspace.base_option_name
self.reflector_objects[baseelt.path].get( self.reflector_objects[baseelt.path].get(
@ -253,14 +221,31 @@ class Common:
properties = [] properties = []
calc_properties = [] calc_properties = []
for property_, value in values.items(): for property_, value in values.items():
if value is True: if not isinstance(value, list):
properties.append(self.convert_str(property_)) value = [value]
elif isinstance(value, list):
for val in value: for val in value:
calc_properties.append(self.calculation_value(val)) ret = self.calculation_property(val)
else: if isinstance(ret, bool):
calc_properties.append(self.calculation_value(value)) if ret:
return "frozenset({" + ", ".join(sorted(properties) + calc_properties) + "})" 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( def calc_properties(
self, self,
@ -295,40 +280,14 @@ class Common:
): ):
"""Populate variable parameters""" """Populate variable parameters"""
if not isinstance(param, dict): if not isinstance(param, dict):
if isinstance(param, str): param = {
value = self.convert_str(param) "type": "any",
else: "value": param,
value = param }
return f"ParamValue({value})"
if param["type"] == "value": if param["type"] == "value":
return f"ParamValue({param['value']})" return f"ParamValue({param['value']})"
if param["type"] == "information": if param["type"] == "information":
# default? really? return self.build_information_param(param)
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})'
if param["type"] == "identifier": if param["type"] == "identifier":
if "identifier" in param and param["identifier"] != None: if "identifier" in param and param["identifier"] != None:
return f"ParamIdentifier(identifier_index={param['identifier']})" return f"ParamIdentifier(identifier_index={param['identifier']})"
@ -336,13 +295,7 @@ class Common:
if param["type"] == "index": if param["type"] == "index":
return "ParamIndex()" return "ParamIndex()"
if param["type"] == "variable": if param["type"] == "variable":
return self.build_option_param( return self.build_variable_param(param)
param["variable"],
param.get("propertyerror", True),
param.get("identifier"),
param.get("dynamic"),
param.get("whole", False),
)
if param["type"] == "any": if param["type"] == "any":
if isinstance(param["value"], str): if isinstance(param["value"], str):
value = self.convert_str(param["value"]) value = self.convert_str(param["value"])
@ -351,25 +304,63 @@ class Common:
return "ParamValue(" + value + ")" return "ParamValue(" + value + ")"
raise Exception("pfff") 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, self,
variable, param: dict,
propertyerror,
identifier: Optional[str],
dynamic,
whole: bool,
) -> str: ) -> str:
"""build variable parameters""" """build variable parameters"""
variable = param["variable"]
whole = param.get("whole", False)
dynamic = param.get("dynamic", True)
if variable.path == self.elt.path: 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: if whole:
msg = f'variable param "{variable.path}" has whole attribute but it\'s not allowed for external variable' msg = _('variable param "{0}" has whole attribute but it\'s not allowed for external variable')
raise DictConsistencyError(msg, 34, self.elt.xmlfiles) 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( option_name = self.tiramisu.reflector_objects[variable.path].get(
self.calls, self.elt.path self.calls, self.elt.path
) )
params = [f"{option_name}"] params = [f"{option_name}"]
identifier = param.get("identifier")
if identifier is not None: 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" param_type = "ParamDynOption"
identifiers = [] identifiers = []
for ident in identifier: for ident in identifier:
@ -377,10 +368,15 @@ class Common:
ident = self.convert_str(ident) ident = self.convert_str(ident)
identifiers.append(str(ident)) identifiers.append(str(ident))
params.append("[" + ", ".join(identifiers) + "]") params.append("[" + ", ".join(identifiers) + "]")
if param.get("optional", False):
params.append("optional=True")
else: else:
param_type = "ParamOption" param_type = "ParamOption"
propertyerror = param.get("propertyerror", True)
if not propertyerror: if not propertyerror:
params.append("notraisepropertyerror=True") params.append("notraisepropertyerror=True")
elif propertyerror == "transitive":
params.append("raisepropertyerror=True")
return f'{param_type}({", ".join(params)})' return f'{param_type}({", ".join(params)})'
def calculation_value( def calculation_value(
@ -388,12 +384,16 @@ class Common:
function, function,
) -> str: ) -> str:
"""Generate calculated value""" """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 = [] new_args = []
kwargs = [] kwargs = []
if "params" in child: if "params" in child:
for key, value in child["params"].items(): for key, value in child["params"].items():
if not key: if key is None:
for val in value: for val in value:
new_args.append(self.populate_param(val)) new_args.append(self.populate_param(val))
else: else:
@ -406,8 +406,8 @@ class Common:
if kwargs: if kwargs:
ret += ", kwargs={" + ", ".join(kwargs) + "}" ret += ", kwargs={" + ", ".join(kwargs) + "}"
ret += ")" ret += ")"
if hasattr(child, "warnings_only"): if "warnings_only" in child:
ret += f", warnings_only={child.warnings_only}" ret += f", warnings_only={child['warnings_only']}"
if "help" in child: if "help" in child:
ret += f", help_function=func['{child['help']}']" ret += f", help_function=func['{child['help']}']"
ret = ret + ")" ret = ret + ")"
@ -418,10 +418,10 @@ class Common:
datas: Union[Calculation, str, list], datas: Union[Calculation, str, list],
return_a_tuple: bool = False, return_a_tuple: bool = False,
) -> str: ) -> str:
if isinstance(datas, str):
return self.convert_str(datas)
if isinstance(datas, Calculation): 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): if not isinstance(datas, list):
return datas return datas
params = [] params = []
@ -430,9 +430,11 @@ class Common:
try: try:
params.append(self.calculation_value(data)) params.append(self.calculation_value(data))
except VariableCalculationDependencyError: except VariableCalculationDependencyError:
pass continue
elif isinstance(data, str): elif isinstance(data, str):
params.append(self.convert_str(data)) params.append(self.convert_str(data))
elif isinstance(data, dict):
params.append(data)
else: else:
params.append(str(data)) params.append(str(data))
if return_a_tuple: if return_a_tuple:
@ -473,9 +475,14 @@ class Variable(Common):
) )
return return
if self.elt.type == "choice": if self.elt.type == "choice":
try:
keys["values"] = self.populate_calculation( keys["values"] = self.populate_calculation(
self.elt.choices, return_a_tuple=True self.elt.choices, return_a_tuple=True
) )
if keys["values"] == "(,)":
keys["values"] = tuple()
except VariableCalculationDependencyError:
keys["values"] = tuple()
if self.elt.type == "regexp": if self.elt.type == "regexp":
self.object_type = "Regexp_" + self.option_name self.object_type = "Regexp_" + self.option_name
self.tiramisu.text["header"].append( self.tiramisu.text["header"].append(
@ -501,6 +508,8 @@ class Variable(Common):
pass pass
if self.elt.validators: if self.elt.validators:
keys["validators"] = self.populate_calculation(self.elt.validators) keys["validators"] = self.populate_calculation(self.elt.validators)
if self.elt.warnings:
keys["warnings_only"] = True
for key, value in ( for key, value in (
CONVERT_OPTION.get(self.elt.type, {}).get("initkwargs", {}).items() CONVERT_OPTION.get(self.elt.type, {}).get("initkwargs", {}).items()
): ):
@ -548,7 +557,10 @@ class Family(Common):
if self.group_type: if self.group_type:
keys["group_type"] = self.group_type keys["group_type"] = self.group_type
if self.elt.type == "dynamic": if self.elt.type == "dynamic":
try:
keys["identifiers"] = self.populate_calculation(self.elt.dynamic) keys["identifiers"] = self.populate_calculation(self.elt.dynamic)
except VariableCalculationDependencyError:
keys["identifiers"] = []
children = [] children = []
for path in self.objectspace.parents[self.elt.path]: for path in self.objectspace.parents[self.elt.path]:
children.append(self.objectspace.paths[path]) children.append(self.objectspace.paths[path])

View file

@ -9,7 +9,7 @@ Cadoles (http://www.cadoles.com)
Copyright (C) 2019-2021 Copyright (C) 2019-2021
Silique (https://www.silique.fr) 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 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 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 _ from .i18n import _
from .tiramisu import display_xmlfiles
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] + '"'
class ConfigError(Exception): class ConfigError(Exception):
@ -69,10 +63,6 @@ class DictConsistencyError(Exception):
self.errno = errno self.errno = errno
class UpgradeError(Exception):
"""Error during XML upgrade"""
## ---- generic exceptions ---- ## ---- generic exceptions ----
@ -81,6 +71,14 @@ class NotFoundError(Exception):
pass pass
class ExtensionError(Exception):
pass
class RougailWarning(UserWarning):
pass
## ---- specific exceptions ---- ## ---- specific exceptions ----

View file

@ -8,7 +8,7 @@ Cadoles (http://www.cadoles.com)
Copyright (C) 2019-2021 Copyright (C) 2019-2021
Silique (https://www.silique.fr) 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 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 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) 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 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 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/>. 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 """Annotate to add specify attribute for tiramisu-cmdline
Silique (https://www.silique.fr) 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 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 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) self.not_for_commandline(variable)
else: else:
self.manage_alternative_name(variable) self.manage_alternative_name(variable)
self.manage_negative_description(variable)
def not_for_commandline(self, variable) -> None: def not_for_commandline(self, variable) -> None:
self.objectspace.properties.add(variable.path, "not_for_commandline", True) self.objectspace.properties.add(variable.path, "not_for_commandline", True)
@ -60,6 +59,7 @@ class Annotator(Walk):
return return
alternative_name = variable.alternative_name alternative_name = variable.alternative_name
variable_path = variable.path variable_path = variable.path
self.objectspace.informations.add(variable_path, "alternative_name", alternative_name)
all_letters = "" all_letters = ""
for letter in alternative_name: for letter in alternative_name:
all_letters += letter all_letters += letter
@ -79,34 +79,14 @@ class Annotator(Walk):
path = alternative_name path = alternative_name
else: else:
path = variable_path.rsplit(".", 1)[0] + "." + alternative_name path = variable_path.rsplit(".", 1)[0] + "." + alternative_name
self.objectspace.version = variable.version
self.objectspace.add_variable( self.objectspace.add_variable(
alternative_name, alternative_name,
{"type": "symlink", "path": path, "opt": variable}, path,
{"type": "symlink", "opt": variable},
variable.xmlfiles, variable.xmlfiles,
False, False,
False, False,
variable.version, False,
) False,
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
) )

View file

@ -2,7 +2,7 @@
Config file for Rougail-structural_commandline Config file for Rougail-structural_commandline
Silique (https://www.silique.fr) 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 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 under the terms of the GNU Lesser General Public License as published by the
@ -27,12 +27,13 @@ def get_rougail_config(
structural_commandline: structural_commandline:
description: Configuration rougail-structural_commandline description: Configuration rougail-structural_commandline
commandline: false commandline: false
add_extra_options: add_extra_options:
description: Add extra options to tiramisu-cmdline-parser description: Add extra options to tiramisu-cmdline-parser
default: true default: true
""" """
return { return {
"name": "exporter", "name": "commandline",
"process": "structural", "process": "structural",
"options": options, "options": options,
"level": 20, "level": 20,

View file

@ -1,7 +1,7 @@
"""Annotate to add specify attribute for tiramisu-cmdline """Annotate to add specify attribute for tiramisu-cmdline
Silique (https://www.silique.fr) 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 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 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): class Variable(BaseModel):
alternative_name: Optional[str] = None alternative_name: Optional[str] = None
commandline: bool = True commandline: bool = True
negative_description: Optional[str] = None
class Family(BaseModel): class Family(BaseModel):
commandline: bool = True 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 Copyright (C) 2019-2021
Silique (https://www.silique.fr) 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 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 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 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.machinery import SourceFileLoader as _SourceFileLoader
from importlib.util import ( from importlib.util import (
spec_from_loader as _spec_from_loader, spec_from_loader as _spec_from_loader,
module_from_spec as _module_from_spec, module_from_spec as _module_from_spec,
) )
from unicodedata import normalize, combining
from jinja2 import StrictUndefined, DictLoader from jinja2 import StrictUndefined, DictLoader
from jinja2.sandbox import SandboxedEnvironment from jinja2.sandbox import SandboxedEnvironment
from rougail.object_model import CONVERT_OPTION from re import findall
from rougail.error import display_xmlfiles from tiramisu import (
from tiramisu import function_waiting_for_error DynOptionDescription,
from tiramisu.error import ValueWarning, ConfigError, PropertiesOptionError calc_value,
from .utils import normalize_family 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 global func
dict_env = {} dict_env = {}
ENV = SandboxedEnvironment(loader=DictLoader(dict_env), undefined=StrictUndefined) ENV = SandboxedEnvironment(loader=DictLoader(dict_env), undefined=StrictUndefined)
ENV.add_extension('jinja2.ext.do')
func = ENV.filters func = ENV.filters
ENV.compile_templates("jinja_caches", zip=None) ENV.compile_templates("jinja_caches", zip=None)
@ -90,8 +286,10 @@ def test_propertyerror(value: Any) -> bool:
ENV.tests["propertyerror"] = test_propertyerror 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 global _SourceFileLoader, _spec_from_loader, _module_from_spec, func
if dict_func is None:
dict_func = func
loader = _SourceFileLoader("func", path) loader = _SourceFileLoader("func", path)
spec = _spec_from_loader(loader.name, loader) spec = _spec_from_loader(loader.name, loader)
func_ = _module_from_spec(spec) func_ = _module_from_spec(spec)
@ -99,16 +297,94 @@ def load_functions(path):
for function in dir(func_): for function in dir(func_):
if function.startswith("_"): if function.startswith("_"):
continue 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) values = calc_value(*args, **kwargs)
if values is None and __internal_multi:
values = []
if __default_value is not None and values in [None, []]: if __default_value is not None and values in [None, []]:
return __default_value return __default_value
return values 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 @function_waiting_for_error
def jinja_to_function( def jinja_to_function(
__internal_variable, __internal_variable,
@ -123,13 +399,31 @@ def jinja_to_function(
global ENV, CONVERT_OPTION global ENV, CONVERT_OPTION
kw = {} kw = {}
for key, value in kwargs.items(): for key, value in kwargs.items():
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): if isinstance(value, PropertiesOptionError):
value = JinjaError(value) value = JinjaError(value)
if value is None:
value = ''
if "." in key: if "." in key:
c_kw = kw c_kw = kw
path, var = key.rsplit(".", 1) 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("."): for subkey in path.split("."):
c_kw = c_kw.setdefault(subkey, {}) c_kw = c_kw.setdefault(subkey, {})
if not isinstance(value, CancelParam):
c_kw[var] = value c_kw[var] = value
else: else:
if key in kw: if key in kw:
@ -140,28 +434,44 @@ def jinja_to_function(
try: try:
values = ENV.get_template(__internal_jinja).render(kw, **func).strip() values = ENV.get_template(__internal_jinja).render(kw, **func).strip()
except Exception as err: except Exception as err:
raise ConfigError( kw_str = ", ".join(kw_to_string(kw))
f'cannot calculating "{__internal_attribute}" attribute for variable "{__internal_variable}" in {display_xmlfiles(__internal_files)}: {err}' prefix = _('cannot calculate the variable "{0}"').format(__internal_variable)
) from err 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) convert = CONVERT_OPTION[__internal_type].get("func", str)
if __internal_multi: 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: if not values and __default_value is not None:
return __default_value return __default_value
return values return values
try: try:
values = convert(values) values = convert(values)
except Exception as err: except Exception as err:
raise ConfigError( prefix = _('cannot converting the variable "{0}"').format(__internal_variable)
f'cannot converting "{__internal_attribute}" attribute for variable "{__internal_variable}" in {display_xmlfiles(__internal_files)}: {err}' msg = _('"{0}" is an invalid {1}').format(values, __internal_type)
) from err 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 values = values if values != "" and values != "None" else None
if values is None and __default_value is not None: if values is None and __default_value is not None:
return __default_value return __default_value
return values 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): if isinstance(value, PropertiesOptionError):
raise value from value raise value from value
if inverse: if inverse:
@ -171,27 +481,39 @@ def variable_to_property(prop, value, when, inverse):
return prop if is_match else None 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 @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) 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 @function_waiting_for_error
def jinja_to_property_help(prop, **kwargs): def jinja_to_property_help(prop, description, **kwargs):
value = func["jinja_to_function"](**kwargs) if kwargs["__internal_type"] == "string":
return (prop, f'"{prop}" ({value})') description = func["jinja_to_function"](**kwargs)
return (prop, f'"{prop}" ({description})')
@function_waiting_for_error @function_waiting_for_error
def valid_with_jinja(warnings_only=False, **kwargs): def valid_with_jinja(warnings_only=False, description=None, **kwargs):
global ValueWarning global ValueWarning
value = func["jinja_to_function"](**kwargs) value = func["jinja_to_function"](**kwargs)
if value: if value:
if description is None:
description = value
if warnings_only: if warnings_only:
raise ValueWarning(value) raise ValueWarning(description)
else: else:
raise ValueError(value) raise ValueError(description)
func["calc_value"] = rougail_calc_value 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"] = jinja_to_property
func["jinja_to_property_help"] = jinja_to_property_help func["jinja_to_property_help"] = jinja_to_property_help
func["variable_to_property"] = variable_to_property func["variable_to_property"] = variable_to_property
func["variable_to_property_transitive"] = variable_to_property_transitive
func["valid_with_jinja"] = valid_with_jinja func["valid_with_jinja"] = valid_with_jinja
func["normalize_family"] = normalize_family
class ConvertDynOptionDescription(DynOptionDescription): class ConvertDynOptionDescription(DynOptionDescription):
@ -207,7 +531,8 @@ class ConvertDynOptionDescription(DynOptionDescription):
Identifier could also contain invalid character, so we should "normalize" it 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: if identifier is None:
return identifier return identifier
if not isinstance(identifier, str): if not isinstance(identifier, str):
@ -236,6 +561,16 @@ class ConvertDynOptionDescription(DynOptionDescription):
if "{{ identifier }}" in display: if "{{ identifier }}" in display:
return display.replace( return display.replace(
"{{ identifier }}", "{{ 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 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 Copyright (C) 2019-2021
Silique (https://www.silique.fr) 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 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 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 typing import List, Union
from unicodedata import normalize, combining
import re import re
from itertools import chain from itertools import chain
@ -45,6 +44,8 @@ from .error import DictConsistencyError
NAME_REGEXP = re.compile(r"^[a-z0-9_]*$") NAME_REGEXP = re.compile(r"^[a-z0-9_]*$")
PROPERTY_ATTRIBUTE = ["frozen", "hidden", "disabled", "mandatory"]
def valid_variable_family_name( def valid_variable_family_name(
name: str, name: str,
@ -58,17 +59,6 @@ def valid_variable_family_name(
raise DictConsistencyError(msg, 76, xmlfiles) 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]: def load_modules(name, module) -> List[str]:
"""list all functions in a module""" """list all functions in a module"""
loader = SourceFileLoader(name, module) loader = SourceFileLoader(name, module)
@ -78,13 +68,10 @@ def load_modules(name, module) -> List[str]:
return eosfunc return eosfunc
def get_realpath( # def get_realpath(
path: str, # path: str,
path_prefix: str, # ) -> str:
) -> str: # return path
if path_prefix:
return f"{path_prefix}.{path}"
return path
def get_jinja_variable_to_param( def get_jinja_variable_to_param(
@ -93,12 +80,12 @@ def get_jinja_variable_to_param(
objectspace, objectspace,
xmlfiles, xmlfiles,
functions, functions,
path_prefix,
version, version,
namespace, namespace,
): ):
try: try:
env = SandboxedEnvironment(loader=DictLoader({"tmpl": jinja_text})) env = SandboxedEnvironment(loader=DictLoader({"tmpl": jinja_text}))
env.add_extension('jinja2.ext.do')
env.filters = functions env.filters = functions
parsed_content = Parser(env, jinja_text, "", "").parse() 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): for g in parsed_content.find_all(Getattr):
variables.add(recurse_getattr(g)) variables.add(recurse_getattr(g))
except TemplateSyntaxError as err: 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 jinja_text, current_path, err
) )
raise DictConsistencyError(msg, 39, xmlfiles) from err raise DictConsistencyError(msg, 39, xmlfiles) from err
except AttributeError:
pass
variables = list(variables) variables = list(variables)
variables.sort(reverse=True) variables.sort(reverse=True)
founded_variables = {} founded_variables = {}
@ -125,7 +114,6 @@ def get_jinja_variable_to_param(
for variable_path in variables: for variable_path in variables:
variable, identifier = objectspace.paths.get_with_dynamic( variable, identifier = objectspace.paths.get_with_dynamic(
variable_path, variable_path,
path_prefix,
current_path, current_path,
version, version,
namespace, namespace,
@ -140,7 +128,6 @@ def get_jinja_variable_to_param(
break break
else: else:
unknown_variables.append(variable_path) unknown_variables.append(variable_path)
for variable_path in unknown_variables: for variable_path in unknown_variables:
for v in founded_variables: for v in founded_variables:
if get_common_path(v, variable_path) == v: if get_common_path(v, variable_path) == v:
@ -152,7 +139,6 @@ def get_jinja_variable_to_param(
vpath = vpath.rsplit(".", 1)[0] vpath = vpath.rsplit(".", 1)[0]
variable, identifier = objectspace.paths.get_with_dynamic( variable, identifier = objectspace.paths.get_with_dynamic(
vpath, vpath,
path_prefix,
current_path, current_path,
version, version,
namespace, namespace,
@ -165,3 +151,70 @@ def get_jinja_variable_to_param(
yield {}, None, root_path yield {}, None, root_path
for variable_path, data in founded_variables.items(): for variable_path, data in founded_variables.items():
yield data[1], data[0], variable_path 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 tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription 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: try:
groups.namespace groups.namespace
except: except:

View file

@ -2,7 +2,11 @@ from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription 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("basic")
ALLOWED_LEADER_PROPERTIES.add("standard") ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced") 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 tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription 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: try:
groups.namespace groups.namespace
except: except:
@ -10,6 +10,5 @@ except:
ALLOWED_LEADER_PROPERTIES.add("basic") ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard") ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced") ALLOWED_LEADER_PROPERTIES.add("advanced")
optiondescription_1 = OptionDescription(name="1", doc="1", children=[], properties=frozenset({"advanced"})) optiondescription_1 = OptionDescription(name="rougail", doc="Rougail", group_type=groups.namespace, 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])
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1, optiondescription_2])

View file

@ -2,7 +2,7 @@ from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription 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: try:
groups.namespace groups.namespace
except: except:
@ -10,6 +10,4 @@ except:
ALLOWED_LEADER_PROPERTIES.add("basic") ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard") ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced") ALLOWED_LEADER_PROPERTIES.add("advanced")
optiondescription_1 = OptionDescription(name="1", doc="1", children=[], properties=frozenset({"advanced"})) option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[])
optiondescription_5 = OptionDescription(name="2", doc="2", children=[], properties=frozenset({"advanced"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1, optiondescription_5])

View file

@ -2,7 +2,7 @@ from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription 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: try:
groups.namespace groups.namespace
except: except:
@ -10,6 +10,5 @@ except:
ALLOWED_LEADER_PROPERTIES.add("basic") ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard") ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced") ALLOWED_LEADER_PROPERTIES.add("advanced")
optiondescription_1 = OptionDescription(name="1", doc="1", children=[], properties=frozenset({"advanced"})) optiondescription_1 = OptionDescription(name="rougail", doc="Rougail", group_type=groups.namespace, 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])
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1, optiondescription_4])

View file

@ -2,7 +2,7 @@ from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription 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: try:
groups.namespace groups.namespace
except: except:
@ -10,6 +10,4 @@ except:
ALLOWED_LEADER_PROPERTIES.add("basic") ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard") ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced") ALLOWED_LEADER_PROPERTIES.add("advanced")
optiondescription_1 = OptionDescription(name="1", doc="1", children=[], properties=frozenset({"advanced"})) option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[])
optiondescription_4 = OptionDescription(name="2", doc="2", children=[], properties=frozenset({"advanced"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1, optiondescription_4])

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 tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription 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: try:
groups.namespace groups.namespace
except: except:
@ -10,6 +10,6 @@ except:
ALLOWED_LEADER_PROPERTIES.add("basic") ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard") ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced") 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"})) 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]) 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 tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription 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("basic")
ALLOWED_LEADER_PROPERTIES.add("standard") ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced") 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]) 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 tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription 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: try:
groups.namespace groups.namespace
except: except:
@ -10,6 +10,6 @@ except:
ALLOWED_LEADER_PROPERTIES.add("basic") ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard") ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced") 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"})) 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]) 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 tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription 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("basic")
ALLOWED_LEADER_PROPERTIES.add("standard") ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced") 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]) 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 tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription 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: try:
groups.namespace groups.namespace
except: except:
@ -11,7 +11,7 @@ ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard") ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced") ALLOWED_LEADER_PROPERTIES.add("advanced")
dict_env['default_rougail.var2'] = "{{ _.var1 }}\n" 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_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(['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_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"})) 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]) 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 tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription 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("basic")
ALLOWED_LEADER_PROPERTIES.add("standard") ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced") ALLOWED_LEADER_PROPERTIES.add("advanced")
dict_env['default_var2'] = "{{ _.var1 }}\n" 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_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(['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_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]) 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 tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription 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: try:
groups.namespace groups.namespace
except: except:
@ -11,7 +11,7 @@ ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard") ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced") ALLOWED_LEADER_PROPERTIES.add("advanced")
dict_env['default_rougail.var2'] = "{% for val in _.var1 %}\n{{ val }}\n{% endfor %}\n" 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_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(['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_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"})) 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]) 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 tiramisu.setting import ALLOWED_LEADER_PROPERTIES
from re import compile as re_compile from re import compile as re_compile
from rougail.tiramisu import func, dict_env, load_functions, ConvertDynOptionDescription 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("basic")
ALLOWED_LEADER_PROPERTIES.add("standard") ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced") ALLOWED_LEADER_PROPERTIES.add("advanced")
dict_env['default_var2'] = "{% for val in _.var1 %}\n{{ val }}\n{% endfor %}\n" 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_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(['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_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]) 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