diff --git a/docs/tutorial/multiple.rst b/docs/tutorial/multiple.rst index b70f02272..053265556 100644 --- a/docs/tutorial/multiple.rst +++ b/docs/tutorial/multiple.rst @@ -4,6 +4,7 @@ Variable with multiple values .. objectives:: Objectives After creating another variable for the needs of our use case, we will introduce the concept of multiple type variable. + It is more or less some kind of a container variable. .. prerequisites:: Prerequisites @@ -50,7 +51,7 @@ Note that this variable has a :term:`disabled` property defined: when_not: Automatic proxy configuration URL ... -If the `proxy_mode` variable has the `"Automatic proxy configuration URL"` value, this `auto` variable is enabled. +If the `proxy_mode` variable has the `"Automatic proxy configuration URL"` value, the `auto` variable is enabled. It is :term:`disabled` otherwise. Let's launch the Rougail CLI on this :term:`user data file `: @@ -91,9 +92,196 @@ A conditional disabled non mandatory variable with type domainname and parameter git switch --detach v1.1_110 -In order to fit with our use case, we need to define a variable in which we could store domain names on which the proxy could be disabled. -We already used before in this tutorial the `domainname` type, which perfectly matches our needs. -We will just need to add certain parameters to this `domainname` type, as we will see. +In order to fit with our use case, we need a variable that takes as its value the domain names that are allowed to pass through the proxy, if it is enabled. We already used before in this tutorial the `domainname` type, which perfectly matches our needs here. +We will just need to add certain parameters associated to this `domainname` type, as we will see. +We're gonna put it in another :term:`structure file` named :file:`firefox/40-no_proxy.yml`. -.. This time we would need some kind of a container type, which would allow us to list the web addresses for which the proxy will be disabled. +.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_110/firefox/40-no_proxy.yml + :language: yaml + :caption: The :file:`firefox/40-no_proxy.yml` structure file with the domains that are allowed to pass through the proxy +.. + %YAML 1.2 + --- + version: 1.1 + + no_proxy: + description: Address for which proxy will be desactivated + type: domainname + params: + allow_ip: true + allow_cidr_network: true + allow_without_dot: true + allow_startswith_dot: true + mandatory: false + disabled: + variable: _.proxy_mode + when: No proxy + ... + +This `no_proxy` variable is a `domainname` with some additional parameters, we authorize +values like: + +- IP +- CIDR networks +- machine names (without `'.'`) +- sub-domaines like `.example` + +To clarify things, let's launch the Rougail CLI + +.. raw:: html + :url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_110/config/02/cmd_ro.txt + :class: terminal + +.. + rougail -m firefox/ --types types/proxy -u yaml -yf config/02/config.yml + +On this :term:`user data`: + +.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_110/config/02/config.yml + :language: yaml + :caption: Automatic proxy configuration :file:`config/02/config.yml` user data file with a pass through domain name + +.. + --- + proxy_mode: Automatic proxy configuration URL + auto: https://auto.proxy.net/wpad.dat + no_proxy: 192.168.1.0/24 + +We then have this output: + +.. raw:: html + :url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_110/config/02/output_ro.html + :class: output + +.. + ╭────────────── Caption ───────────────╮ + │ Variable Modified value │ + │ (⏳ Original default value) │ + ╰──────────────────────────────────────╯ + Variables: + ┣━━ 📓 Configure Proxy Access to the Internet: Automatic proxy configuration URL ◀ loaded from the YAML file "config/02/config.yml" (⏳ No proxy) + ┣━━ 📓 Automatic proxy configuration URL: https://auto.proxy.net/wpad.dat ◀ loaded from the YAML file "config/02/config.yml" + ┗━━ 📓 Address for which proxy will be desactivated: 192.168.1.0/24 ◀ loaded from the YAML file "config/02/config.yml" + +We can see the address for which proxy will be desactivated in the output. + +A variable with multiple values +----------------------------------- + +.. type-along:: For those who follow the tutorial with the help of the git repository + + Now you need to checkout the :tutorial:`v1.1_111 ` version:: + + git switch --detach v1.1_111 + +It's easy to find out what the next step is: we would now need some kind of a container type, +which would allow us to set not only one domain name but a list of domain names for which the proxy will be disabled. + +Making this change requires adding one line, just one, to our variable, +the `multi: true` parameter: + +.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_111/firefox/40-no_proxy.yml + :language: yaml + :caption: The :file:`firefox/40-no_proxy.yml` structure file with the pass through domains set to `multi` + +.. + %YAML 1.2 + --- + version: 1.1 + + no_proxy: + description: Address for which proxy will be desactivated + type: domainname + params: + allow_ip: true + allow_cidr_network: true + allow_without_dot: true + allow_startswith_dot: true + multi: true + mandatory: false + disabled: + variable: _.proxy_mode + when: No proxy + ... + + +.. questions:: Question + + + What difference does it make? + + Fist, note that the `no_proxy` variable is still a `domainname` + + +Now let's launch the Rougail CLI with the `no_proxy` variable containing a list: + +.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_111/config/02/config.yml + :language: yaml + :caption: Automatic proxy configuration :file:`config/02/config.yml` user data file with a pass through domain name + +.. + %YAML 1.2 + --- + version: 1.1 + + no_proxy: + description: Address for which proxy will be desactivated + type: domainname + params: + allow_ip: true + allow_cidr_network: true + allow_without_dot: true + allow_startswith_dot: true + multi: true + mandatory: false + disabled: + variable: _.proxy_mode + when: No proxy + ... + +.. raw:: html + :url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_111/config/02/cmd_ro.txt + :class: terminal + +.. + rougail -m firefox/ --types types/proxy -u yaml -yf config/02/config.yml + +Now we have this output: + +.. raw:: html + :url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_110/config/02/output_ro.html + :class: output + +.. + ╭────────────── Caption ───────────────╮ + │ Variable Modified value │ + │ (⏳ Original default value) │ + ╰──────────────────────────────────────╯ + Variables: + ┣━━ 📓 Configure Proxy Access to the Internet: Automatic proxy configuration URL ◀ loaded from the YAML file "config/02/config.yml" (⏳ No proxy) + ┣━━ 📓 Automatic proxy configuration URL: https://auto.proxy.net/wpad.dat ◀ loaded from the YAML file "config/02/config.yml" + ┗━━ 📓 Address for which proxy will be desactivated: + ┣━━ example.net ◀ loaded from the YAML file "config/02/config.yml" + ┗━━ 192.168.1.0/24 ◀ loaded from the YAML file "config/02/config.yml" + +.. questions:: Answer to the question + + So, the difference it makes is: yes, we have a list now. + + We call this a :term:`multiple ` variable. + +.. glossary:: + + multi + + A multiple variable, in short, a multi, is a variable that has a list of values. + + Note that we have more than just a simple container here. + The real challenge is maintaining the consistency of the :term:`configuration` + exactly the same way as if we only had one value to manage. + + A multi is a multiple variable, that is a variable that can have multiple values. + + +.. keywords:: diff --git a/docs/tutorial/tutorial.rst b/docs/tutorial/tutorial.rst deleted file mode 100644 index 93f1ac73e..000000000 --- a/docs/tutorial/tutorial.rst +++ /dev/null @@ -1,628 +0,0 @@ -:orphan: - -HTTPS proxy configuration detail ------------------------------------ - -Let's add a new subfamily named `ssl_proxy`, containing the `address` and `port` variables. - -Let's create the :file:`dict/05-proxy_manual_ssl_proxy.yml` file: - -.. code-block:: yaml - :caption: the :file:`dict/04-proxy_manual_http_use_for_https.yml` file - :linenos: - - --- - version: '1.1' - proxy: - manual: - ssl_proxy: - description: HTTPS Proxy - hidden: - type: variable - variable: rougail.proxy.manual.use_for_https - address: - description: HTTPS address - type: domainname - default: - type: jinja - jinja: | - {% if rougail.proxy.manual.use_for_https %} - {{ rougail.proxy.manual.http_proxy.address }} - {% endif %} - port: - description: HTTPS Port - type: port - default: - type: jinja - jinja: | - {% if rougail.proxy.manual.use_for_https %} - {{ rougail.proxy.manual.http_proxy.port }} - {% endif %} - - -Depending on the value of the `rougail.proxy.mandatory.use_for_https` variable, this family will appear or disappear (the `hidden` setting line 7). Unlike earlier, this time it is not necessary to use a Jinja function. - -Let's notice that the family is not disabled because the variables will need to remain accessible (yet in `read-only` mode). - -The address and port variables are copied from HTTP to HTTPS if `rougail.proxy.use_for_https` is set to `True`. - -Now let's test all of it: - ->>> from rougail import Rougail, RougailConfig ->>> from pprint import pprint ->>> RougailConfig['dictionaries_dir'] = ['dict'] ->>> rougail = Rougail() ->>> config = rougail.get_config() ->>> config.property.read_only() ->>> pprint(config.value.get(), sort_dicts=False) -{'rougail.proxy.proxy_mode': 'No proxy'} - -At this time the proxy is not configured yet, so we do not see any variables. -Let's look at what happens if we try to access the `rougail.proxy.manual` variable if we are not in manual mode: - -.. code-block:: python - - >>> pprint(config.option('rougail.proxy.manual').value.get(), sort_dicts=False) - -We have an error (with the message defined in the Jinja template): - - -.. code-block:: shell - - tiramisu.error.PropertiesOptionError: cannot access to - optiondescription "Manual proxy configuration" because - has property "disabled" (the mode proxy is not manual) - - -Let's configure the proxy in manual mode - ->>> config.property.read_write() ->>> config.option('rougail.proxy.proxy_mode').value.set('Manual proxy configuration') ->>> config.option('rougail.proxy.manual.http_proxy.address').value.set('proxy.example') ->>> pprint(config.value.get(), sort_dicts=False) - -We can see that the returned variables does have the desired values: - -.. code-block:: python - - {'rougail.proxy.proxy_mode': 'Manual proxy configuration', - 'rougail.proxy.manual.http_proxy.address': 'proxy.example', - 'rougail.proxy.manual.http_proxy.port': '8080', - 'rougail.proxy.manual.use_for_https': True} - -Let's set the `read_only` mode and have a look at the configuration again: - -.. code-block:: python - - >>> config.property.read_only() - >>> pprint(config.value.get(), sort_dicts=False) - {'rougail.proxy.proxy_mode': 'Manual proxy configuration', - 'rougail.proxy.manual.http_proxy.address': 'proxy.example', - 'rougail.proxy.manual.http_proxy.port': '8080', - 'rougail.proxy.manual.use_for_https': True, - 'rougail.proxy.manual.ssl_proxy.address': 'proxy.example', - 'rougail.proxy.manual.ssl_proxy.port': '8080'} - -In the `read_only` mode, we can see that the HTTPS configuration appears. - -.. note:: We can see that `rougail.proxy.manual.http_proxy` values have been copied - in `rougail.proxy.manual.ssl_proxy` too. - -Changing values programmatically --------------------------------------- - -We are going to use the :term:`Tiramisu` API to manipulate programmatically the different variables. - -First, let's set `rougail.proxy.manual.use_for_https` to `False`. It is now possible -to configure the HTTPS: - -.. code-block:: python - - >>> config.property.read_write() - >>> config.option('rougail.proxy.manual.use_for_https').value.set(False) - >>> config.option('rougail.proxy.manual.ssl_proxy.address').value.set('other.proxy.example') - >>> pprint(config.value.get(), sort_dicts=False) - {'rougail.proxy.proxy_mode': 'Manual proxy configuration', - 'rougail.proxy.manual.http_proxy.address': 'proxy.example', - 'rougail.proxy.manual.http_proxy.port': '8080', - 'rougail.proxy.manual.use_for_https': False, - 'rougail.proxy.manual.ssl_proxy.address': 'other.proxy.example', - 'rougail.proxy.manual.ssl_proxy.port': '8080'} - -The value of the variable `rougail.proxy.manual.ssl_proxy.address` has actually been modified. -But if this variable is hidden again, then the value comes back to the default value: - -.. code-block:: python - - >>> config.option('rougail.proxy.manual.use_for_https').value.set(False) - >>> config.property.read_only() - >>> pprint(config.value.get(), sort_dicts=False) - {'rougail.proxy.proxy_mode': 'Manual proxy configuration', - 'rougail.proxy.manual.http_proxy.address': 'proxy.example', - 'rougail.proxy.manual.http_proxy.port': '8080', - 'rougail.proxy.manual.use_for_https': False, - 'rougail.proxy.manual.ssl_proxy.address': 'proxy.example', - 'rougail.proxy.manual.ssl_proxy.port': '8080'} - -SOCK's proxy configuration -------------------------------- - -Let's add a new :term:`subfamily` named `socks_proxy` with the `address`, -`port` and `version` variables. - -Let's create the :file:`dict/06-proxy_manual_socks_proxy.yml` file: - -.. code-block:: yaml - :caption: the :file:`dict/06-proxy_manual_socks_proxy.yml` file - - --- - version: '1.1' - proxy: - manual: - socks_proxy: - description: SOCKS Proxy - address: - description: SOCKS Address - type: domainname - port: - description: SOCKS Port - type: port - version: - description: SOCKS host version used by proxy - type: choice - choices: - - v4 - - v5 - default: v5 - -There's nothing new to learn with this file. - -The automatic detection mode ------------------------------- - -Let's add a new variable named `auto`. - -Let's create the :file:`dict/07-proxy_auto.yml` file: - -.. code-block:: yaml - :caption: the :file:`dict/07-proxy_auto.yml` file - - --- - version: '1.1' - proxy: - auto: - type: web_address - description: Automatic proxy configuration URL - disabled: - type: jinja - jinja: | - {% if rougail.proxy.proxy_mode != 'Automatic proxy configuration URL' %} - the proxy mode is not automatic - {% endif %} - -The `web_address` type imposes a value starting with `http://` or `https://`. -This variable is activated when the proxy is in automatic mode. - -The proxy's exceptions ---------------------------- - -Finally, let's add a variable containing proxy exceptions. - -Let's create the :file:`dict/07-proxy_no_proxy.yml` file: - -.. code-block:: yaml - :caption: the :file:`dict/07-proxy_no_proxy.yml` file - :linenos: - - --- - version: '1.1' - proxy: - no_proxy: - description: Address for which proxy will be desactivated - multi: true - type: "domainname" - params: - allow_ip: true - allow_cidr_network: true - allow_without_dot: true - allow_startswith_dot: true - disabled: - type: jinja - jinja: | - {% if rougail.proxy.proxy_mode == 'No proxy' %} - proxy mode is no proxy - {% endif %} - mandatory: false - -This `no_proxy` variable is much like a `domainname` type except that we add -a `params` line 7, we authorize the : - -- IP -- CIDR networks -- machine names (without `'.'`) -- sub-domaines like `.example` - -There can be multiple exceptions to the proxy, so the variable is :term:`multi` (line5). -This variable is only accessible if no proxy is defined (`disabled`). - -.. glossary:: - - multi - - A multi is a multiple variable, that is a variable that can have multiple values. - - -The `no_proxy` variable do not requires a value (that is, `None` is an option), -there is line 19 this statement `mandatory: false` which means that this variable is not mandatory. - - -Let's test it: - - ->>> from rougail import Rougail, RougailConfig ->>> from pprint import pprint ->>> RougailConfig['dictionaries_dir'] = ['dict'] ->>> rougail = Rougail() ->>> config = rougail.get_config() ->>> config.property.read_write() ->>> config.option('rougail.proxy.proxy_mode').value.set('Manual proxy configuration') ->>> config.option('rougail.proxy.manual.http_proxy.address').value.set('proxy.example') ->>> config.option('rougail.proxy.no_proxy').value.set(['.example', '192.168.1.1']) ->>> config.property.read_only() ->>> pprint(config.value.get(), sort_dicts=False) - -It outputs: - -.. code-block:: python - - {'rougail.proxy.proxy_mode': 'Manual proxy configuration', - 'rougail.proxy.manual.http_proxy.address': 'proxy.example', - 'rougail.proxy.manual.http_proxy.port': '8080', - 'rougail.proxy.manual.use_for_https': True, - 'rougail.proxy.manual.ssl_proxy.address': 'proxy.example', - 'rougail.proxy.manual.ssl_proxy.port': '8080', - 'rougail.proxy.manual.socks_proxy.address': None, - 'rougail.proxy.manual.socks_proxy.port': None, - 'rougail.proxy.manual.socks_proxy.version': 'v5', - 'rougail.proxy.no_proxy': ['.example', '192.168.1.1']} - -But not possible to put an invalid value: - -.. code-block:: python - - >>> config.option('rougail.proxy.no_proxy').value.set(['.example', '192.168.1.1', 'not valid']) - [..] - tiramisu.error.ValueOptionError: "not valid" is an invalid domain name for "Address for which proxy will be desactivated", could be a IP, otherwise must start with lowercase characters followed by lowercase characters, number, "-" and "." characters are allowed - - -The authentification request --------------------------------- - -Nothing special when creating the authentication request. To do this, let's create a `dict/08-proxy_prompt_authentication.yml` file: - - -.. code-block:: yaml - :caption: the :file:`dict/08-proxy_prompt_authentication.yml` file - :linenos: - - --- - version: '1.1' - proxy: - prompt_authentication: - description: Prompt for authentication if password is saved - type: boolean - default: true - disabled: - type: jinja - jinja: | - {% if rougail.proxy.proxy_mode == 'No proxy' %} - proxy mode is no proxy - {% endif %} - -The proxy SOCKS v5's DNS ------------------------------- - -The DNS variable for the SOCKS v5 proxy only appears if the proxy is configured and the version of the SOCKS proxy selected is `v5`. - -Let's create a `dict/09-proxy_proxy_dns_socks5.yml` file: - -.. code-block:: yaml - :caption: the :file:`dict/09-proxy_proxy_dns_socks5.yml` file - :linenos: - - --- - version: '1.1' - proxy: - proxy_dns_socks5: - description: Use proxy DNS when using SOCKS v5 - type: boolean - default: false - disabled: - type: jinja - params: - socks_version: - type: variable - variable: rougail.proxy.manual.socks_proxy.version - propertyerror: false - jinja: | - {% if rougail.proxy.proxy_mode == 'No proxy' %} - the proxy mode is no proxy - {% elif socks_version is undefined or socks_version == 'v4' %} - socks version is v4 - {% endif %} - -The difficulty here is that the `rougail.proxy.manual.socks_proxy.version` variable -can be deactivated (and therefore not usable in a calculation). - -.. FIXME definir ce qu'est une calculation - -In this case, we will add a parameter (here called `socks_version`) which will contain, -if there is no property error, the value of the variable. -Otherwise the parameter will not be passed to the Jinja template. - -This is why it is necessary to test in the Jinja template whether the `socks_version` variable really exists. - -The DNS over HTTPS ----------------------- - -Finally we will configure DNS over HTTPS in the 10-proxy_dns_over_https.yml file: - -Let's create a `dict/10-proxy_dns_over_https.yml` file: - -.. code-block:: yaml - :caption: the :file:`dict/10-proxy_dns_over_https.yml` file - :linenos: - - --- - version: '1.1' - proxy: - dns_over_https: - description: DNS over HTTPS - enable_dns_over_https: - description: Enable DNS over HTTPS - type: boolean - default: false - provider: - description: Use Provider - type: choice - choices: - - Cloudflare - - NextDNS - - Custom - default: Cloudflare - disabled: - type: jinja - jinja: | - {% if not rougail.proxy.dns_over_https.enable_dns_over_https %} - Enable DNS over HTTPS is False - {% endif %} - custom_dns_url: - description: Custom DNS URL - type: web_address - disabled: - type: jinja - params: - provider: - type: variable - variable: rougail.proxy.dns_over_https.provider - propertyerror: false - jinja: | - {% if provider is not defined or provider != 'Custom' %} - provider is not custom - {% endif %} - validators: - - type: jinja - jinja: | - {% if rougail.proxy.dns_over_https.custom_dns_url.startswith('http://') %} - only https is allowed - {% endif %} - -.. FIXME : define validators - -The only particularity here is that we added additional validation (validators) to the `custom_dns_url` variable. Only an address starting with `https://` is allowed (not `http://`). - ----- - -The FoxyProxy type's proxy configuration --------------------------------------------- - -Here is now the integration of part of the Firefox FoxyProxy plugin. - -The idea is to have a namespace specific to FoxyProxy and to find in it part of the settings that we will have made in the main namespace. - -This is what the page looks like: - -.. image:: images/foxyproxy.png - -It is possible, in this plugin, to specify an unlimited number of proxies. -Our `proxy` family will no longer be of the `family` type as before but of another type : the :term:`leadership` type. - -.. FIXME: expliquer ce qu'est le type leardership - -Here is the complete content of the FoxyProxy type proxy configuration -(to be put in the `foxyproxy/00-base.yml` file): - -.. code-block:: yaml - :caption: the :file:``foxyproxy/00-base.yml`` file - :linenos: - - --- - version: '1.1' - proxy: - _type: leadership - title: - description: Title or Description - multi: true - color: - description: Color - type: - type: choice - choices: - - HTTP - - HTTPS/SSL - - SOCKS5 - - SOCKS4 - - PAC URL - - WPAD - - System (use system settings) - - Direct (no proxy) - default: Direct (no proxy) - address: - description: IP address, DNS name, server name - multi: true - disabled: - type: jinja - jinja: | - {% if foxyproxy.proxy.type not in ['HTTP', 'HTTPS/SSL', 'SOCKS5', 'SOCKS4'] %} - proxy does not need address - {% endif %} - default: - type: jinja - params: - firefox_address: - type: variable - variable: rougail.proxy.manual.http_proxy.address - propertyerror: false - jinja: | - {% if firefox_address is not undefined %} - {{ firefox_address }} - {% endif %} - port: - description: Port - type: port - default: - type: jinja - params: - firefox_port: - type: variable - variable: rougail.proxy.manual.http_proxy.port - propertyerror: false - jinja: | - {% if firefox_port is not undefined %} - {{ firefox_port }} - {% endif %} - disabled: - type: jinja - jinja: | - {% if foxyproxy.proxy.type not in ['HTTP', 'HTTPS/SSL', 'SOCKS5', 'SOCKS4'] %} - proxy does not need port - {% endif %} - username: - description: Username - type: unix_user - mandatory: - type: jinja - jinja: | - {% if foxyproxy.proxy.password %} - username is mandatory - {% endif %} - disabled: - type: jinja - jinja: | - {% if foxyproxy.proxy.type not in ['HTTP', 'HTTPS/SSL', 'SOCKS5', 'SOCKS4'] %} - proxy does not need username - {% endif %} - password: - description: Password - type: secret - disabled: - type: jinja - jinja: | - {% if foxyproxy.proxy.type not in ['HTTP', 'HTTPS/SSL', 'SOCKS5', 'SOCKS4'] %} - proxy does not need password - {% endif %} - url: - type: web_address - disabled: - type: jinja - jinja: | - {% if foxyproxy.proxy.type not in ['PAC URL', 'WPAD'] %} - proxy does not need url - {% endif %} - - -A few comments: - -- in the `foxyproxy.proxy` :term:`leader` family there is a variable named `type` (line 4), this may conflict with the `type` attribute (specified line 10). In this case, to specify the type we use the `_type` attribute -- a :term:`follower` variable can also be multiple - (which is the case for `foxyproxy.proxy.address`) -- `foxyproxy.proxy.username` (line 62) becomes :term:`mandatory` if `foxyproxy.proxy.password` - is specified, in fact a password without a username is meaningless - -Let's test it: - ->>> from rougail import Rougail, RougailConfig ->>> from pprint import pprint ->>> RougailConfig['dictionaries_dir'] = ['dict'] ->>> RougailConfig['extra_dictionaries']['foxyproxy'] = ['foxyproxy/'] ->>> rougail = Rougail() ->>> config = rougail.get_config() ->>> config.option('rougail.proxy.proxy_mode').value.set('Manual proxy configuration') ->>> config.option('rougail.proxy.manual.http_proxy.address').value.set('proxy.example') ->>> config.option('foxyproxy.proxy.title').value.set(['MyProxy']) ->>> config.option('foxyproxy.proxy.type', 0).value.set('HTTP') ->>> config.option('foxyproxy.proxy.color', 0).value.set('#00000') ->>> config.property.read_only() ->>> pprint(config.value.get(), sort_dicts=False) - -The output is: - -.. code-block:: python - - {'rougail.proxy.proxy_mode': 'Manual proxy configuration', - 'rougail.proxy.manual.http_proxy.address': 'proxy.example', - 'rougail.proxy.manual.http_proxy.port': '8080', - 'rougail.proxy.manual.use_for_https': True, - 'rougail.proxy.manual.ssl_proxy.address': 'proxy.example', - 'rougail.proxy.manual.ssl_proxy.port': '8080', - 'rougail.proxy.manual.socks_proxy.address': None, - 'rougail.proxy.manual.socks_proxy.port': None, - 'rougail.proxy.manual.socks_proxy.version': 'v5', - 'rougail.proxy.no_proxy': [], - 'rougail.proxy.proxy_dns_socks5': False, - 'rougail.proxy.dns_over_https.enable_dns_over_https': False, - 'foxyproxy.proxy.title': [{'foxyproxy.proxy.title': 'MyProxy', - 'foxyproxy.proxy.color': '#00000', - 'foxyproxy.proxy.type': 'HTTP', - 'foxyproxy.proxy.address': ['proxy.example'], - 'foxyproxy.proxy.port': '8080', - 'foxyproxy.proxy.username': None, - 'foxyproxy.proxy.password': None}]} - -The choice we made here is to make `foxyproxy.proxy.username` :term:`mandatory` if a password is specified in the `foxyproxy.proxy.password` variable. - -It makes sense to have a username without a password (in this case the password will be requested when connecting to the proxy). But the opposite does not make sense. - -From a user point of view this may seem disturbing (if you enter the password, you have to return to the previous option to specify the password). - -It is possible to reverse the logic. If the `foxyproxy.proxy.username` variable is set, the `foxyproxy.proxy.password` variable becomes editable. - -None of this two variables needs to be :term:`mandatory`. - -If you prefer this option, here is a second extra dictionary :file:`foxyproxy/01-redefine.yml` which will redefine the behavior only of the `foxyproxy.proxy.username` and `foxyproxy.proxy.password` variables: - - - - -.. code-block:: yaml - :caption: the :file:`foxyproxy/01-redefine.yml` file - :linenos: - - --- - version: '1.1' - proxy: - username: - redefine: true - # suppress mandatory constrainte - mandatory: false - password: - redefine: true - hidden: - type: jinja - jinja: | - {% if not foxyproxy.proxy.username %} - no username defined - {% endif %} - - -**It's up to you to play now !**