diff --git a/docs/.gitlab-ci.yml b/docs/.gitlab-ci.yml
index 73ad79616369f8e390d1fd9174e0aeeb8fa8d5ab..54bcdfd14e971b92a2541be9f09b3d8f16264119 100644
--- a/docs/.gitlab-ci.yml
+++ b/docs/.gitlab-ci.yml
@@ -116,6 +116,8 @@ variables:
   - &rules_regexp_dev $CI_COMMIT_BRANCH =~ /^((release|feature|hotfix|bugfix)-|merge_request_)*/
   - &rules_regexp_pre_prod $CI_COMMIT_BRANCH =~ /(develop|master)/
   - &rules_regexp_prod $CI_COMMIT_TAG
+  - &rules_regexp_trigger_main (($CI_COMMIT_BRANCH =~ /(develop|master)/) || $CI_COMMIT_TAG) && ($MAIN_PROJECT && $MAIN_PROJECT != $CI_PROJECT_PATH)
+  - &rules_regexp_trigger_info (($CI_COMMIT_BRANCH =~ /(develop|master)/) || $CI_COMMIT_TAG) && ($MAIN_PROJECT == "")
 
 # Defining rules that now replace only to run jobs under specific condition
 # and define variables
@@ -134,6 +136,12 @@ variables:
   variables:
     CI_DEPLOY_TYPE: "prod"
 
+.rules_trigger_main: &rules_trigger_main
+  if: *rules_regexp_trigger_main
+
+.rules_trigger_info: &rules_trigger_info
+  if: *rules_regexp_trigger_info
+
 # Tag anchors
 # -----------------------------------------------------------------------------
 # https://docs.gitlab.com/ee/ci/yaml/README.html#tag
@@ -343,9 +351,13 @@ script_deploy_html: &script_deploy_html
       esac
     - export RSYNC_PATH="${PROJECT_PATH}${LAST_TAG}"
     - export ONLINE_PATH="${ONLINE_DEST}${PROJECT_PATH}latest"
-    - echo "$PROJECT_PATH"
     - mkdir -p "tmp/${RSYNC_PATH}"
     - mv site/* "tmp/${RSYNC_PATH}/"
+    - |
+      if [[ -f "tmp/${RSYNC_PATH}/versions.json" ]]
+      then
+        cp tmp/${RSYNC_PATH}/versions.json tmp/${RSYNC_PATH}/../versions.json
+      fi
     - ln -s "${LAST_TAG}" "latest"
     - mv "latest" "tmp/${PROJECT_PATH}"
     - rsync -avz "tmp/" "${RSYNC_DEST}"
@@ -367,12 +379,6 @@ script_deploy_html: &script_deploy_html
       </body>\n
       </html>" > index.html
     - rsync -avz index.html "${RSYNC_DEST}${PROJECT_PATH}/"
-    - |
-      if [[ -f "site/versions.json" ]]
-      then
-        cp site/versions.json versions.json
-        rsync -avz versions.json "${RSYNC_DEST}${PROJECT_PATH}/"
-      fi
   rules:
     - *rules_dev
     - *rules_pre_prod
@@ -391,9 +397,7 @@ trigger_main_repo:
   variables:
     MAIN_PROJECT_CI_PATH: ${MAIN_PROJECT_CI_PATH:-"."}
   rules:
-    - *rules_pre_prod
-    - *rules_prod
-    - if: $MAIN_PROJECT && $MAIN_PROJECT != $CI_PROJECT_PATH
+    - *rules_trigger_main
 
 inform_triggers_variables:
   <<: *tag_docker
@@ -413,9 +417,7 @@ inform_triggers_variables:
           INFO - the \`MAIN_PROJECT\`."
       fi
   rules:
-    - *rules_pre_prod
-    - *rules_prod
-    - if: ! $MAIN_PROJECT
+    - *rules_trigger_info
 
 # *****************************************************************************
 # VIM MODELINE
diff --git a/docs/_data/plugins.py b/docs/_data/plugins.py
index c3fae711f0507b49ac8a10d60e89d5c5ad2430f9..dbfe47fb0cd9f568e921b116b7219a648225a210 100644
--- a/docs/_data/plugins.py
+++ b/docs/_data/plugins.py
@@ -1,5 +1,6 @@
 #!/usr/bin/env python3
-"""
+"""Set of methods to manage mkdocs configuration dynamically.
+
 Set of methods for
 [mkdocs-macros-plugin](https://mkdocs-macros-plugin.readthedocs.io/) Set of
 which :
@@ -424,7 +425,6 @@ def set_repo_name(env: dict, repo_slug: str) -> None:
         env: Mkdocs macro plugin environment dictionary.
         repo_slug: Repo slug or name of the repo folder.
     """
-
     if "repo_name" not in env.conf or not env.conf["repo_name"]:
         if "repo_name" in env.variables:
             env.conf["repo_name"] = env.variables["repo_name"]
@@ -533,7 +533,6 @@ def set_config(env: dict) -> None:
     Arguments:
         env: Mkdocs macro plugin environment dictionary.
     """
-
     git_repo = git.Repo(search_parent_directories=True)
     repo_slug = get_repo_slug(env, git_repo)
 
@@ -557,7 +556,7 @@ def set_config(env: dict) -> None:
 
 
 def load_yaml_file(path: str, filename: str) -> None:
-    """Ensure a YAML file is valid again a schema and return its content
+    """Ensure a YAML file is valid again a schema and return its content.
 
     Depending on the name of the YAML file, compare its content to a schema to
     validate its content. If content is not valid, an error will be raised.
@@ -602,7 +601,7 @@ def update_subrepo_logo_src(
     path: str,
     external: bool,
 ) -> None:
-    """Update the content of the key `logo` and `src_path` of subrepo
+    """Update the content of the key `logo` and `src_path` of subrepo.
 
     Update value of keys `logo` and `src_path` of cloned subrepo, i.e. value
     from file `docs/_data/repo.yaml` in the cloned subrepo, relative to the main
@@ -740,7 +739,7 @@ def update_subrepo(
 def update_logo_src_repo(
     env: dict, curr_repo: dict, repo_name: str, path: str = None
 ) -> None:
-    """Update the content of the key `logo` and `src_path` of current repo
+    """Update the content of the key `logo` and `src_path` of current repo.
 
     Update value of keys `logo` and `src_path` of current repo holding the
     documentation.
@@ -753,7 +752,6 @@ def update_logo_src_repo(
         repo_name: Name of the repo,
         path: Absolute path of the location of the current repo.
     """
-
     subpath = ""
     if path:
         subpath = os.path.join(path.replace(env.project_dir, ""), repo_name)
@@ -771,7 +769,7 @@ def update_logo_src_repo(
 
 
 def load_var_file(env: dict) -> None:
-    """Load variables files in `docs/_data/`
+    """Load variables files in `docs/_data/`.
 
     Load every yaml files in `docs/_data/`, if one of the file define the
     current repo, then update keys `logo` and `src_path` for the current repo.
@@ -792,7 +790,7 @@ def load_var_file(env: dict) -> None:
 
 
 def update_version(env: dict) -> None:
-    """Parse every tags of the repo to build a `docs/versions.json`
+    """Parse every tags of the repo to build a `docs/versions.json`.
 
     To emulate mike version support for gitlab, this method will parse every
     tags of the current repo holding the current documentation to create a file
@@ -864,7 +862,8 @@ def update_version(env: dict) -> None:
 def define_env(env: dict) -> None:
     # pylint: disable=C0301
     # - C0301: Line to long
-    """
+    """Hook for mkdocs-macros-plugins defining variables, macros and filters.
+
     This is the hook for defining variables, macros and filters
 
     - variables: the dictionary that contains the environment variables
@@ -879,7 +878,6 @@ def define_env(env: dict) -> None:
     Arguments:
         env: Mkdocs macro plugin environment dictionary.
     """
-
     load_var_file(env)
 
     if "subrepo" in env.variables:
@@ -898,14 +896,28 @@ def define_env(env: dict) -> None:
     # pylint: disable=W0612
     # -  W0612: Unused variable (unused-variable)
     def subs(var: str) -> dict:
-        """Return the content of the dictionary defined by var"""
+        """Return the content of the dictionary defined by var.
+
+        Arguments:
+            var: Key in env.variables to return.
+
+        Returns:
+            The value of `env.variables[var]`.
+        """
         return env.variables[var]
 
     @env.macro
     # pylint: disable=W0612
     # -  W0612: Unused variable (unused-variable)
     def to_html(var: str) -> dict:
-        """Convert the content of the markdown string into HTML"""
+        """Convert the content of the markdown string into HTML.
+
+        Arguments:
+            var: Markdown string which need to be converted to HTML
+
+        Returns:
+            The content of the markdown converted to HTML
+        """
         return markdown.markdown(var)
 
 
diff --git a/pyproject.toml b/pyproject.toml
index cea64ce6be9557abde1308b5325b9f86bd146896..5716a786e6b024a59c039c26da815f1e3e3108d8 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
 # No need for [build-system] as this pyproject.toml per PEP-518 as this file
 # serve to a centralized configuration file for development tools such as
-# black, flake8/flakehell, pylint, pycodestyle, etc.
+# black, flake8/flake9, pylint, pycodestyle, etc.
 [build-system]
 requires = [
   "setuptools",
@@ -45,9 +45,9 @@ commands =
         -not -path "./tmp/*" \
         -not -path "./site**/*"  \\) )'
   # Lint python files using flake8
-  flakehell lint
+  flake8
   # Ensure docstring convention (google is mkdocs rendering documentation)
-  pydocstyle --count --match-dir="(?![^\\.(docs)]).*" --convention=google
+  pydocstyle --count --convention=google --match-dir='[^(\\.|preview)].*'
 
 [testenv:format_shell]
 # Allow external commands
@@ -92,6 +92,8 @@ commands =
 """
 
 
+
+
 ### BEGIN MKDOCS TEMPLATE ###
 ### WARNING, DO NOT UPDATE CONTENT BETWEEN MKDOCS TEMPLATE TAG ! ###
 ### Modified content will be overwritten when updating. ###
@@ -1087,34 +1089,22 @@ overgeneral-exceptions=["BaseException","Exception"]
 
 
 # -----------------------------------------------------------------------------
-# Flake8 wrapper to make it nice, legacy-friendly, configurable.
-# https://flakehell.readthedocs.io/config.html
-[tool.flakehell]
+# Flake8/flake9
+# https://flake8.pycqa.org/en/latest/user/configuration.html
+[tool.flake8]
   # Optionally inherit from remote config (or local if you want)
 #base=https://url.git.com/pyproject.toml
 
   # Specify any flake8 options.
   # Print the total number of errors.
   # Default False
-count=true
+count = true
 
   # Provide a comma-separated list of glob patterns to exclude from checks.
-exclude=[
-  ".git",
-  "__pycache__",
-  ".eggs",
-  ".venv",
-  ".direnv",
-  ".tox",
-  ".sha1",
-  "build",
-  "dist",
-  "docs",
-  "site"
-]
+exclude = ".git,__pycache__,.eggs,.env,.venv,.direnv,.tox,.sha1,build,dist,docs,site"
 
   # Provide a comma-separate list of glob patterns to include for checks.
-filename=[ "*.py" ]
+filename = "*.py"
 
   # Select the formatter used to display errors to the user.
   # This defaults to: default
@@ -1124,12 +1114,12 @@ filename=[ "*.py" ]
   #  - colored
   # The default formatter has a format string of:
   # '%(path)s:%(row)d:%(col)d: %(code)s %(text)s'
-format="grouped"
+#format="colored
 
   # Toggle whether pycodestyle should enforce matching the indentation of the
   # opening bracket’s line. When you specify this, it will prefer that you hang
   # the closing bracket rather than match the indentation.
-hang_closing=false
+hang-closing = false
 
   # Specify a list of codes to ignore. The list is expected to be comma-separated,
   # and does not need to specify an error code exactly. Since Flake8 3.0, this can
@@ -1138,8 +1128,9 @@ hang_closing=false
   # if you want to ignore all codes that start with W23 you need only specify W23
   # to ignore them. This also works for W2 and W (for example).
   # This defaults to: E121,E123,E126,E226,E24,E704
-  # REMARK: Not parsed by flakehell, use plugins
-#ignore=[ "E121", "E123", "E126", "E226", "E24", "E704"]
+ignore = "E121,E123,E126,E226,E24,E704,W503,E501"
+  # W503 : line break before binary operator
+  # E501 : line to long (already handled by black)
 
   # Set the maximum length that any line (with some exceptions) may be.
   # Exceptions include lines that are either strings or comments which are
@@ -1150,20 +1141,20 @@ hang_closing=false
   #   'http://...'
   # )
   # This defaults to: 79
-max_line_length=80
+max-line-length = 80
 
   # Report all errors, even if it is on the same line as a # NOQA comment. # NOQA
   # can be used to silence messages on specific lines. Sometimes, users will want
   # to see what errors are being silenced without editing the file. This option
   # allows you to see all the warnings, errors, etc. reported.
   # This default to : False
-disable_noqa=true
+disable-noqa = true
 
   # Print the source code generating the error/warning in question.
-show_source=true
+show-source = true
 
   # Count the number of occurrences of each error/warning code and print a report.
-statistics=true
+statistics = true
 
   # Enable off-by-default extensions.
   # Plugins to Flake8 have the option of registering themselves as off-by-default.
@@ -1179,13 +1170,10 @@ statistics=true
   # This defaults to: auto
   # The default behaviour will use the number of CPUs on your machine as reported
   # by multiprocessing.cpu_count().
-jobs="auto"
-
-  # Redirect all output to the specified file.
-output-file=".direnv/log/flakehell.log"
+jobs = "auto"
 
   # Also print output to stdout if output-file has been configured.
-tee=true
+tee = true
 
   # Provide a custom list of builtin functions, objects, names, etc.
   # This allows you to let pyflakes know about builtins that it may not
@@ -1199,7 +1187,7 @@ tee=true
 
   # Enable PyFlakes syntax checking of doctests in docstrings.
   # This is registered by the default PyFlakes plugin.
-#doctests=True
+#doctests = True
 
   # Specify which files are checked by PyFlakes for doctest syntax.
   # This is registered by the default PyFlakes plugin.
@@ -1209,20 +1197,13 @@ tee=true
 
   # Specify which files are not to be checked by PyFlakes for doctest syntax.
   # This is registered by the default PyFlakes plugin.
-  # exclude-in-doctest =
+#exclude-in-doctest =
   #  dir/subdir/file.py,
   #  dir/other/file.py
 
-[tool.flakehell.plugins]
-  # Python code style checker
-  # https://pypi.org/project/pycodestyle/
-pycodestyle=["-W503"]
+### END MKDOCS TEMPLATE ###
 
-  # Passive checker of Python programs
-  # https://pypi.org/project/pyflakes/
-pyflakes=["+*"]
 
-### END MKDOCS TEMPLATE ###
 
 
 # *****************************************************************************
diff --git a/requirements.dev.in b/requirements.dev.in
index c3b71b56694340594a902bc9b714e24b6f30f677..f83252396707ead57f1a3d9bf435091f26eae8e4 100644
--- a/requirements.dev.in
+++ b/requirements.dev.in
@@ -1,3 +1,5 @@
+
+
 ### BEGIN MKDOCS TEMPLATE ###
 ### WARNING, DO NOT UPDATE CONTENT BETWEEN MKDOCS TEMPLATE TAG !###
 ### Modified content will be overwritten when updating.###
@@ -24,9 +26,9 @@ isort
 # https://pypi.org/project/pytest/
 pytest
 
-# Flake8 wrapper to make it nice and configurable
-# https://pypi.org/project/flake8/
-flakehell
+# Flake8 with pyproject support
+# https://pypi.org/project/flake9/
+flake9
 
 # python code static checker
 # https://pypi.org/project/pylint/
@@ -44,3 +46,5 @@ shellcheck-py
 # https://pypi.org/project/yamllint/
 yamllint
 ### END MKDOCS TEMPLATE ###
+
+
diff --git a/requirements.dev.txt b/requirements.dev.txt
index 852c98e9950ee2bbe1d29713533a02720ff7aa06..c09aa98667b394e29dd441dedf3d1f772e99279c 100644
--- a/requirements.dev.txt
+++ b/requirements.dev.txt
@@ -1,3 +1,4 @@
+
 ### BEGIN MKDOCS TEMPLATE ###
 ### WARNING, DO NOT UPDATE CONTENT BETWEEN MKDOCS TEMPLATE TAG !###
 ### Modified content will be overwritten when updating.###
@@ -19,19 +20,13 @@ black==20.8b1
     # via -r requirements.dev.in
 click==7.1.2
     # via black
-colorama==0.4.4
-    # via flakehell
 distlib==0.3.1
     # via virtualenv
-entrypoints==0.3
-    # via flakehell
 filelock==3.0.12
     # via
     #   tox
     #   virtualenv
-flake8==3.9.1
-    # via flakehell
-flakehell==0.9.0
+flake9==3.8.3.post2
     # via -r requirements.dev.in
 iniconfig==1.1.1
     # via pytest
@@ -43,7 +38,7 @@ lazy-object-proxy==1.6.0
     # via astroid
 mccabe==0.6.1
     # via
-    #   flake8
+    #   flake9
     #   pylint
 mypy-extensions==0.4.3
     # via black
@@ -63,14 +58,12 @@ py==1.10.0
     # via
     #   pytest
     #   tox
-pycodestyle==2.7.0
-    # via flake8
+pycodestyle==2.6.0
+    # via flake9
 pydocstyle==6.0.0
     # via -r requirements.dev.in
-pyflakes==2.3.1
-    # via flake8
-pygments==2.8.1
-    # via flakehell
+pyflakes==2.2.0
+    # via flake9
 pylint==2.7.4
     # via -r requirements.dev.in
 pyparsing==2.4.7
@@ -81,7 +74,7 @@ pyyaml==5.4.1
     # via yamllint
 regex==2021.4.4
     # via black
-shellcheck-py==0.7.1.1
+shellcheck-py==0.7.2.1
     # via -r requirements.dev.in
 six==1.15.0
     # via
@@ -92,7 +85,6 @@ snowballstemmer==2.1.0
 toml==0.10.2
     # via
     #   black
-    #   flakehell
     #   pylint
     #   pytest
     #   tox
@@ -102,12 +94,11 @@ typed-ast==1.4.3
     # via black
 typing-extensions==3.7.4.3
     # via black
-urllib3==1.26.4
-    # via flakehell
-virtualenv==20.4.3
+virtualenv==20.4.4
     # via tox
 wrapt==1.12.1
     # via astroid
 yamllint==1.26.1
     # via -r requirements.dev.in
 ### END MKDOCS TEMPLATE ###
+
diff --git a/templates/docs/_data/plugins.py b/templates/docs/_data/plugins.py
index c3fae711f0507b49ac8a10d60e89d5c5ad2430f9..dbfe47fb0cd9f568e921b116b7219a648225a210 100644
--- a/templates/docs/_data/plugins.py
+++ b/templates/docs/_data/plugins.py
@@ -1,5 +1,6 @@
 #!/usr/bin/env python3
-"""
+"""Set of methods to manage mkdocs configuration dynamically.
+
 Set of methods for
 [mkdocs-macros-plugin](https://mkdocs-macros-plugin.readthedocs.io/) Set of
 which :
@@ -424,7 +425,6 @@ def set_repo_name(env: dict, repo_slug: str) -> None:
         env: Mkdocs macro plugin environment dictionary.
         repo_slug: Repo slug or name of the repo folder.
     """
-
     if "repo_name" not in env.conf or not env.conf["repo_name"]:
         if "repo_name" in env.variables:
             env.conf["repo_name"] = env.variables["repo_name"]
@@ -533,7 +533,6 @@ def set_config(env: dict) -> None:
     Arguments:
         env: Mkdocs macro plugin environment dictionary.
     """
-
     git_repo = git.Repo(search_parent_directories=True)
     repo_slug = get_repo_slug(env, git_repo)
 
@@ -557,7 +556,7 @@ def set_config(env: dict) -> None:
 
 
 def load_yaml_file(path: str, filename: str) -> None:
-    """Ensure a YAML file is valid again a schema and return its content
+    """Ensure a YAML file is valid again a schema and return its content.
 
     Depending on the name of the YAML file, compare its content to a schema to
     validate its content. If content is not valid, an error will be raised.
@@ -602,7 +601,7 @@ def update_subrepo_logo_src(
     path: str,
     external: bool,
 ) -> None:
-    """Update the content of the key `logo` and `src_path` of subrepo
+    """Update the content of the key `logo` and `src_path` of subrepo.
 
     Update value of keys `logo` and `src_path` of cloned subrepo, i.e. value
     from file `docs/_data/repo.yaml` in the cloned subrepo, relative to the main
@@ -740,7 +739,7 @@ def update_subrepo(
 def update_logo_src_repo(
     env: dict, curr_repo: dict, repo_name: str, path: str = None
 ) -> None:
-    """Update the content of the key `logo` and `src_path` of current repo
+    """Update the content of the key `logo` and `src_path` of current repo.
 
     Update value of keys `logo` and `src_path` of current repo holding the
     documentation.
@@ -753,7 +752,6 @@ def update_logo_src_repo(
         repo_name: Name of the repo,
         path: Absolute path of the location of the current repo.
     """
-
     subpath = ""
     if path:
         subpath = os.path.join(path.replace(env.project_dir, ""), repo_name)
@@ -771,7 +769,7 @@ def update_logo_src_repo(
 
 
 def load_var_file(env: dict) -> None:
-    """Load variables files in `docs/_data/`
+    """Load variables files in `docs/_data/`.
 
     Load every yaml files in `docs/_data/`, if one of the file define the
     current repo, then update keys `logo` and `src_path` for the current repo.
@@ -792,7 +790,7 @@ def load_var_file(env: dict) -> None:
 
 
 def update_version(env: dict) -> None:
-    """Parse every tags of the repo to build a `docs/versions.json`
+    """Parse every tags of the repo to build a `docs/versions.json`.
 
     To emulate mike version support for gitlab, this method will parse every
     tags of the current repo holding the current documentation to create a file
@@ -864,7 +862,8 @@ def update_version(env: dict) -> None:
 def define_env(env: dict) -> None:
     # pylint: disable=C0301
     # - C0301: Line to long
-    """
+    """Hook for mkdocs-macros-plugins defining variables, macros and filters.
+
     This is the hook for defining variables, macros and filters
 
     - variables: the dictionary that contains the environment variables
@@ -879,7 +878,6 @@ def define_env(env: dict) -> None:
     Arguments:
         env: Mkdocs macro plugin environment dictionary.
     """
-
     load_var_file(env)
 
     if "subrepo" in env.variables:
@@ -898,14 +896,28 @@ def define_env(env: dict) -> None:
     # pylint: disable=W0612
     # -  W0612: Unused variable (unused-variable)
     def subs(var: str) -> dict:
-        """Return the content of the dictionary defined by var"""
+        """Return the content of the dictionary defined by var.
+
+        Arguments:
+            var: Key in env.variables to return.
+
+        Returns:
+            The value of `env.variables[var]`.
+        """
         return env.variables[var]
 
     @env.macro
     # pylint: disable=W0612
     # -  W0612: Unused variable (unused-variable)
     def to_html(var: str) -> dict:
-        """Convert the content of the markdown string into HTML"""
+        """Convert the content of the markdown string into HTML.
+
+        Arguments:
+            var: Markdown string which need to be converted to HTML
+
+        Returns:
+            The content of the markdown converted to HTML
+        """
         return markdown.markdown(var)