From 8a754e0858d922e955e71b253c139e071ecec432 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 28 Apr 2024 18:04:21 +0200 Subject: Adding upstream version 2.14.3. Signed-off-by: Daniel Baumann --- .../rst/dev_guide/testing/sanity/import.rst | 126 +++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 docs/docsite/rst/dev_guide/testing/sanity/import.rst (limited to 'docs/docsite/rst/dev_guide/testing/sanity/import.rst') diff --git a/docs/docsite/rst/dev_guide/testing/sanity/import.rst b/docs/docsite/rst/dev_guide/testing/sanity/import.rst new file mode 100644 index 0000000..6a5d329 --- /dev/null +++ b/docs/docsite/rst/dev_guide/testing/sanity/import.rst @@ -0,0 +1,126 @@ +import +====== + +Ansible :ref:`allows unchecked imports` of some libraries from specific directories. +Importing any other Python library requires :ref:`handling import errors`. +This enables support for sanity tests such as :ref:`testing_validate-modules` and provides better error messages to the user. + +.. _handling_import_errors: + +Handling import errors +---------------------- + +In modules +^^^^^^^^^^ + +Instead of using ``import another_library``: + +.. code-block:: python + + import traceback + + from ansible.module_utils.basic import missing_required_lib + + try: + import another_library + except ImportError: + HAS_ANOTHER_LIBRARY = False + ANOTHER_LIBRARY_IMPORT_ERROR = traceback.format_exc() + else: + HAS_ANOTHER_LIBRARY = True + ANOTHER_LIBRARY_IMPORT_ERROR = None + +.. note:: + + The ``missing_required_lib`` import above will be used below. + +Then in the module code: + +.. code-block:: python + + module = AnsibleModule(...) + + if not HAS_ANOTHER_LIBRARY: + module.fail_json( + msg=missing_required_lib('another_library'), + exception=ANOTHER_LIBRARY_IMPORT_ERROR) + +In plugins +^^^^^^^^^^ + +Instead of using ``import another_library``: + +.. code-block:: python + + try: + import another_library + except ImportError as imp_exc: + ANOTHER_LIBRARY_IMPORT_ERROR = imp_exc + else: + ANOTHER_LIBRARY_IMPORT_ERROR = None + +Then in the plugin code, for example in ``__init__`` of the plugin: + +.. code-block:: python + + if ANOTHER_LIBRARY_IMPORT_ERROR: + raise AnsibleError('another_library must be installed to use this plugin') from ANOTHER_LIBRARY_IMPORT_ERROR + +When used as base classes +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. important:: + + This solution builds on the previous two examples. + Make sure to pick the appropriate one before continuing with this solution. + +Sometimes an import is used in a base class, for example: + +.. code-block:: python + + from another_library import UsefulThing + + class CustomThing(UsefulThing): + pass + +One option is make the entire class definition conditional: + +.. code-block:: python + + if not ANOTHER_LIBRARY_IMPORT_ERROR: + class CustomThing(UsefulThing): + pass + +Another option is to define a substitute base class by modifying the exception handler: + +.. code-block:: python + + try: + from another_library import UsefulThing + except ImportError: + class UsefulThing: + pass + ... + +.. _allowed_unchecked_imports: + +Allowed unchecked imports +------------------------- + +Ansible allows the following unchecked imports from these specific directories: + +* ansible-core: + + * For ``lib/ansible/modules/`` and ``lib/ansible/module_utils/``, unchecked imports are only allowed from the Python standard library; + * For ``lib/ansible/plugins/``, unchecked imports are only allowed from the Python standard library, from public dependencies of ansible-core, and from ansible-core itself; + +* collections: + + * For ``plugins/modules/`` and ``plugins/module_utils/``, unchecked imports are only allowed from the Python standard library; + * For other directories in ``plugins/`` (see `the community collection requirements `_ for a list), unchecked imports are only allowed from the Python standard library, from public dependencies of ansible-core, and from ansible-core itself. + +Public dependencies of ansible-core are: + + * Jinja2 + * PyYAML + * MarkupSafe (as a dependency of Jinja2) -- cgit v1.2.3