fix(validation)

This commit is contained in:
egarette@silique.fr 2026-06-15 19:32:28 +02:00
parent 2e826db3f4
commit 3be1324da3
6 changed files with 230 additions and 216 deletions

View file

@ -6,7 +6,18 @@ Synopsis
A verification is a complementary validation to the type which allows the content of a variable to be validated more precisely. A verification is a complementary validation to the type which allows the content of a variable to be validated more precisely.
A :term:`validator` is necessarily a Jinja type calculation. The purpose of validation is to verify that the variable is of :ref:`good quality <data_quality>` and/or that the variable is :ref:`consistent <consistency>`.
.. glossary::
validator
A validator is a Jinja code that parses a variable's value and checks
that this value corresponds to some stated criteria.
This is a `validator` parameter of our variable, and another `jinja` sub-parameter
contains validation code for the variable's value.
.. seealso:: The tutorial with a real world sample :ref:`validators <tutorial_validators>`
Parameters Parameters
-------------- --------------
@ -14,91 +25,127 @@ Parameters
Depending on the types of calculation, the parameters will be different: Depending on the types of calculation, the parameters will be different:
.. list-table:: .. list-table::
:widths: 15 25 20 15
:header-rows: 1 :header-rows: 1
* - **Calculation type** * - **Calculation type**
- **Parameter** - **Comment**
- **Comments**
- **Sample**
* - * - **type**
- **type**
`string` `string`
- The value is `jinja`
`mandatory`
- Type of calculation, the only possible value is: jinja
- jinja
* - **jinja** * - **jinja**
`string` `string`
`mandatory` `mandatory`
- Jinja template - Please set a Jinja template.
- {% if rougail.variable == 'not_allowed' %}not allowed!{% endif %}
-
* - **params** * - **params**
`list` `dict`
- Additional parameters passed to the Jinja template - Additional parameters passed to the Jinja template (see below).
-
-
There are two types of parameter: * - **return_type**
- the standard parameters (string, boolean, integer, null), in this case just do: "key: value" `string`
- advanced settings: - A validation could returns the error message directly, so return_type is `string` (the default behavior).
Or a `boolean`, in this case if it's return `true` this means that the value is not valid.
* - **description**
`string`
- Additional information for the :ref:`documentation <data_documentation>` and the error message in case of return_type is a boolean.
* - **warnings**
`boolean`
- If `true` the validation did not raise, it only display a warning.
Params
~~~~~~
There are two types of params:
- the standard parameters (string, boolean, integer, float or null), in this case just do: "key: value"
- advanced settings (with something like "key: {}":
- parameter via a variable - parameter via a variable
- parameter via an information - parameter via an information
- parameter via a suffix: in the case of a variable in a dynamic family - parameter via an identifier: in a dynamic family returns the current identifier
- parameter via an index: in the case of a :term:`follower` variable - parameter via an index: in the case of a :term:`follower` variable returns the current index
- parameter via :ref:`the current namespace name <namespace>`
Variable params
"""""""""""""""
.. list-table:: .. list-table::
:widths: 15 25 20 15
:header-rows: 1 :header-rows: 1
* - **Parameter's type** * - **Parameter**
- **Parameter**
- **Comments** - **Comments**
- **Sample** - **Sample**
* -
- **name** * - **type**
`string`
- Type of parameter, which is variable.
- variable
* - **variable**
`string` `string`
`mandatory` `mandatory`
- Parameter's name - Variable's path.
- my_param
* -
- **type**
`string`
`mandatory`
- Type of parameter, possible values are: variable, information, suffix or index
- suffix
* - Variable
- **variable**
`string`
`mandatory`
- variable's name
- rougail.variable - rougail.variable
* - Variable (`mandatory`) information
- **propertyerror** * - **propertyerror**
`boolean` `boolean`
- If access to the variable is not possible due to a property - If access to the variable is not possible due to a property
(for example `disabled`) by default an error is returned. (for example `disabled`) by default an error is returned.
If the attribute is `False`, the parameter is not passed to the Jinja template. If the attribute is `false`, the parameter is not passed to the Jinja template.
**Default value**: `True` **Default value**: `false`
- True - `true`
* - Information
- **information** * - **optional**
`boolean`
- If the variable is not defined the value is always `null`.
**Default value**: `false`
- `true`
* - **whole**
`boolean`
- In :term:`dynamically built family` only the value of the current index is retrieve. If this parameter is set to `true` it returns all
If this parameter is set to `true`, it returns the set of values for all indices.
**Default value**: `false`
- `true`
Information params
~~~~~~~~~~~~~~~~~~
.. list-table::
:header-rows: 1
* - **Parameter**
- **Comments**
- **Sample**
* - **type**
`string`
- Type of parameter, which is information
- information
* - **information**
`string` `string`
@ -106,6 +153,12 @@ There are two types of parameter:
- Name of the information whose value we want to retrieve. - Name of the information whose value we want to retrieve.
- doc - doc
* - **variable**
`string`
- By default, the information is a context information. It is possible to get a variable information. In this case just specify a path.
- rougail.variable
Samples Samples
-------------- --------------
@ -116,23 +169,24 @@ Here is a simple example of validating values:
.. code-block:: yaml .. code-block:: yaml
--- %YAML 1.2
version: 1.1 ---
my_variable: version: 1.1
validators:
- type: jinja
jinja: |
{% if rougail.my_variable and not rougail.my_variable.islower() %}
{{ rougail.my_variable }} is not lowercase string
{% endif %}
my_variable:
validators:
- jinja: |-
{% if my_variable is not none and not my_variable.islower() %}
{{ my_variable }} is not lowercase string
{% endif %}
...
A verification function must take into account 2 important aspects: A verification function must take into account 2 important aspects:
- the value may not be entered (even if the variable is mandatory), the None value must be taken into account - the value may not be entered (even if the variable is mandatory), the None value must be taken into account
- if the value is invalid, a sentence must be returned with an explicit message. - if return_type is `string` and the value is invalid, a sentence must be returned with an explicit message.
From now on only `None` and lowercase values will be allowed. From now on only `null` and lowercase values will be allowed.
Checking values with warning Checking values with warning
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -141,17 +195,19 @@ In the constraint, it is possible to specify the error level and put it as a war
.. code-block:: yaml .. code-block:: yaml
--- %YAML 1.2
version: 1.1 ---
my_variable: version: 1.1
validators:
- type: jinja my_variable:
jinja: |+ validators:
{% if rougail.my_variable and not rougail.my_variable.islower() %} - jinja: |-
{{ rougail.my_variable }} is not lowercase string {% if my_variable is not none and not my_variable.islower() %}
{% endif %} {{ my_variable }} is not lowercase string
params: {% endif %}
warnings_only: true params:
warnings: true
...
In this case a value with a capital letter will be accepted, but a warning message will appear. In this case a value with a capital letter will be accepted, but a warning message will appear.
@ -160,127 +216,88 @@ Verification with parameters
.. code-block:: yaml .. code-block:: yaml
--- %YAML 1.2
version: 1.1 ---
my_hidden_variable: version: 1.1
disabled: true
my_variable:
validators:
- type: jinja
jinja: |
{% if param1 is defined and rougail.my_variable == param1 %}
has same value as rougail.unknown_variable
{% endif %}
{% if param2 is defined and rougail.my_variable == param2 %}
has same value as rougail.my_hidden_variable
{% endif %}
params:
param1:
type: variable
variable: rougail.unknown_variable
optional: true
param2:
type: variable
variable: rougail.my_hidden_variable
propertyerror: false
An example with a suffix type parameter: my_hidden_variable:
disabled: true
my_variable:
validators:
- type: jinja
jinja: |-
{% if param1 is defined and my_variable == param1 %}
has same value as unknown_variable
{% endif %}
{% if param2 is defined and my_variable == param2 %}
has same value as my_hidden_variable
{% endif %}
params:
param1:
variable: unknown_variable
optional: true
param2:
variable: my_hidden_variable
propertyerror: false
...
An example with an identifier type parameter:
.. code-block:: yaml .. code-block:: yaml
--- %YAML 1.2
version: 1.1 ---
varname: version: 1.1
multi: true
default:
- val1
- val2
my_dyn_family_:
type: dynamic
variable: rougail.varname
description: 'Describe '
my_dyn_var:
type: string
validators:
- type: jinja
jinja: |
{% if rougail.my_dyn_family_.my_dyn_var == param1 %}
forbidden!
{% endif %}
params:
param1:
type: suffix
In this example, we see a dynamic family. Two families will be created: `rougail.my_dyn_family_val1.my_dyn_var` and `rougail.my_dyn_family_val2.my_dyn_var`. my_dyn_family_{{ identifier }}:
type: dynamic
dynamic:
- val1
- val2
description: 'Describe {{ identifier }}'
my_dyn_var:
validators:
- jinja: |
{% if my_dyn_family_.my_dyn_var == param1 %}
forbidden!
{% endif %}
params:
param1:
type: identifier
...
In this example, we see a :term:`dynamically built family`. Two families will be created: `my_dyn_family_val1.my_dyn_var` and `my_dyn_family_val2.my_dyn_var`.
The value of the variable within this family cannot be equal to the value The value of the variable within this family cannot be equal to the value
of the suffix (`val1` and `val2` respectively). of the identifier (`val1` and `val2` respectively).
An example with an index type parameter: An example with an index type parameter:
.. code-block:: yaml .. code-block:: yaml
--- %YAML 1.2
version: 1.1 ---
family: version: 1.1
type: sequence
leader:
multi: true
default:
- val1
- val2
follower1:
type: integer
validators:
- type: jinja
jinja: |
{% if rougail.family.follower1 == param1 %}
forbidden!
{% endif %}
params:
param1:
type: index
Redefinition family:
--------------- type: sequence
In a first dictionary, let's declare our variable and its verification function: leader:
default:
- val1
- val2
.. code-block:: yaml follower1:
type: integer
--- validators:
version: 1.1 - type: jinja
my_variable: jinja: |-
validators: {% if family.follower1 == param1 %}
- type: jinja forbidden!
jinja: | {% endif %}
{% if rougail.my_variable and not rougail.my_variable.islower() %} params:
{{ rougail.my_variable }} is not lowercase string param1:
{% endif %} type: index
...
In a second dictionary it is possible to redefine the calculation:
.. code-block:: yaml
---
version: 1.1
my_variable:
redefine: true
validators:
- type: jinja
jinja: |
{% if rougail.my_variable and ' ' in rougail.my_variable %}
{{ rougail.my_variable }} has a space
{% endif %}
In this case only this validator will be executed.
Here is a third dictionary in which we remove the validation:
.. code-block:: yaml
---
version: 1.1
my_variable:
redefine: true
validators:

View file

@ -51,6 +51,7 @@ Overall coherence
which will validate the value of a variable in relation to others. which will validate the value of a variable in relation to others.
But it also depends on the availability of the variable depending on the context. But it also depends on the availability of the variable depending on the context.
.. _consistency:
Consistency Consistency
~~~~~~~~~~~ ~~~~~~~~~~~

View file

@ -1,3 +1,5 @@
.. _data_documentation:
Data documentation Data documentation
================== ==================

View file

@ -145,6 +145,8 @@ It is possible to create subfamilies.
.. seealso:: :doc:`the family documentation <family>` .. seealso:: :doc:`the family documentation <family>`
.. _dynamically_built_family:
The dynamically built family The dynamically built family
~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View file

@ -27,7 +27,7 @@ Regexp type with calculation
A regexp variable A regexp variable
----------------- -----------------
We have already seen the :ref:`validator mechanism <tutorial_validator>` for managing the :ref:`quality of data values <data_quality>`. We have already seen the :ref:`validator mechanism <tutorial_validators>` for managing the :ref:`quality of data values <data_quality>`.
This mechanism is undeniably interesting and powerful. This mechanism is undeniably interesting and powerful.
But for strings that can be validated using a regular expression, it is preferable to use this type. But for strings that can be validated using a regular expression, it is preferable to use this type.
@ -89,7 +89,7 @@ Why not offer a default value to the user?
If the user has a specific color in mind, they can specify it. Otherwise, Rougail will suggest a default value. If the user has a specific color in mind, they can specify it. Otherwise, Rougail will suggest a default value.
We've already seen how to use :ref:`Jinja <tutorial_jinja>` for :ref:`validation <tutorial_validator>` and :ref:`access control <tutorial_disabled>` calculations. We've already seen how to use :ref:`Jinja <tutorial_jinja>` for :ref:`validation <tutorial_validators>` and :ref:`access control <tutorial_disabled>` calculations.
We've also seen how to calculate the default value by :ref:`retrieving the value of another variable <tutorial_calc_variable>`. We've also seen how to calculate the default value by :ref:`retrieving the value of another variable <tutorial_calc_variable>`.

View file

@ -1,4 +1,4 @@
.. _tutorial_validator: .. _tutorial_validators:
Validating a variable's value Validating a variable's value
================================ ================================
@ -49,15 +49,6 @@ It is possible, instead of creating a new type, to add custom validation of the
We call it a :term:`validator`. We call it a :term:`validator`.
.. glossary::
validator
A validator is a Jinja code that parses a variable's value and checks
that this value corresponds to some stated criteria.
This is a `validator` parameter of our variable, and another `jinja` sub-parameter
contains validation code for the variable's value.
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_170/firefox/60-dns_over_https.yml .. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_170/firefox/60-dns_over_https.yml
:language: yaml :language: yaml
:caption: The :file:`firefox/60-dns_over_https.yml` with the jinja validator :caption: The :file:`firefox/60-dns_over_https.yml` with the jinja validator
@ -68,6 +59,7 @@ Here we can see that the validation code is:
{{ _.custom_dns_url.startswith("http://") }} {{ _.custom_dns_url.startswith("http://") }}
First of all, you can see that we use the path of the current variable for validation.
A validator can return a string, in fact it is its default behavior. A validator can return a string, in fact it is its default behavior.
If it returns a string of characters, it indicates the validation error. If it returns a string of characters, it indicates the validation error.