diff options
author | Felix Fontein <felix@fontein.de> | 2021-03-02 01:10:46 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-03-02 01:10:46 +0100 |
commit | 3cc693b92c0cbaec6af133e6f73427f1c4f1b28f (patch) | |
tree | d97547f5e6389514a36fec8bd758ba5679fe7d42 | |
parent | Reduce complexity of Templar._lookup slightly (#73277) (diff) | |
download | ansible-3cc693b92c0cbaec6af133e6f73427f1c4f1b28f.tar.xz ansible-3cc693b92c0cbaec6af133e6f73427f1c4f1b28f.zip |
Import test: improve docs, add more tests (#73600)
7 files changed, 148 insertions, 4 deletions
diff --git a/docs/docsite/rst/dev_guide/testing/sanity/import.rst b/docs/docsite/rst/dev_guide/testing/sanity/import.rst index 4b29636a54..045afee718 100644 --- a/docs/docsite/rst/dev_guide/testing/sanity/import.rst +++ b/docs/docsite/rst/dev_guide/testing/sanity/import.rst @@ -1,5 +1,68 @@ import ====== -All Python imports in ``lib/ansible/modules/`` and ``lib/ansible/module_utils/`` which are not from the Python standard library -must be imported in a try/except ImportError block. +Ansible allows unchecked imports of some libraries from specific directories, listed at the bottom of this section. Import all other Python libraries in a try/except ImportError block to support sanity tests such as ``validate-modules`` and to allow Ansible to give better error messages to the user. To import a library in a try/except ImportError block: + +1. In modules: + + .. code-block:: python + + # Instead of 'import another_library', do: + + import traceback + + try: + import another_library + except ImportError: + HAS_ANOTHER_LIBRARY = False + ANOTHER_LIBRARY_IMPORT_ERROR = traceback.format_exc() + else: + HAS_ANOTHER_LIBRARY = True + + + # Later in module code: + + module = AnsibleModule(...) + + if not HAS_ANOTHER_LIBRARY: + # Needs: from ansible.module_utils.basic import missing_required_lib + module.fail_json( + msg=missing_required_lib('another_library'), + exception=ANOTHER_LIBRARY_IMPORT_ERROR) + +2. In plugins: + + .. code-block:: python + + # Instead of 'import another_library', do: + + from ansible.module_utils.six import raise_from + + try: + import another_library + except ImportError as imp_exc: + ANOTHER_LIBRARY_IMPORT_ERROR = imp_exc + else: + ANOTHER_LIBRARY_IMPORT_ERROR = None + + + # Later in plugin code, for example in __init__ of the plugin: + + if ANOTHER_LIBRARY_IMPORT_ERROR: + raise_from( + AnsibleError('another_library must be installed to use this plugin'), + ANOTHER_LIBRARY_IMPORT_ERROR) + # If you target only newer Python 3 versions, you can also use the + # 'raise ... from ...' syntax. + +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 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 <https://github.com/ansible-collections/overview/blob/main/collection_requirements.rst#modules-plugins>`_ for a list), unchecked imports are only allowed from the Python standard library, from dependencies of ansible-core, and from ansible-core itself. diff --git a/test/integration/targets/ansible-test/ansible_collections/ns/col/plugins/lookup/bad.py b/test/integration/targets/ansible-test/ansible_collections/ns/col/plugins/lookup/bad.py new file mode 100644 index 0000000000..580f9d87b7 --- /dev/null +++ b/test/integration/targets/ansible-test/ansible_collections/ns/col/plugins/lookup/bad.py @@ -0,0 +1,31 @@ +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +DOCUMENTATION = ''' +name: bad +short_description: Bad lookup +description: A bad lookup. +author: + - Ansible Core Team +''' + +EXAMPLES = ''' +- debug: + msg: "{{ lookup('ns.col.bad') }}" +''' + +RETURN = ''' # ''' + +from ansible.plugins.lookup import LookupBase +from ansible import constants + +import lxml + + +class LookupModule(LookupBase): + def run(self, terms, variables, **kwargs): + self.set_options(var_options=variables, direct=kwargs) + + return terms diff --git a/test/integration/targets/ansible-test/ansible_collections/ns/col/plugins/lookup/world.py b/test/integration/targets/ansible-test/ansible_collections/ns/col/plugins/lookup/world.py new file mode 100644 index 0000000000..dbb479a726 --- /dev/null +++ b/test/integration/targets/ansible-test/ansible_collections/ns/col/plugins/lookup/world.py @@ -0,0 +1,29 @@ +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +DOCUMENTATION = ''' +name: world +short_description: World lookup +description: A world lookup. +author: + - Ansible Core Team +''' + +EXAMPLES = ''' +- debug: + msg: "{{ lookup('ns.col.world') }}" +''' + +RETURN = ''' # ''' + +from ansible.plugins.lookup import LookupBase +from ansible import constants + + +class LookupModule(LookupBase): + def run(self, terms, variables, **kwargs): + self.set_options(var_options=variables, direct=kwargs) + + return terms diff --git a/test/integration/targets/ansible-test/ansible_collections/ns/col/plugins/random_directory/bad.py b/test/integration/targets/ansible-test/ansible_collections/ns/col/plugins/random_directory/bad.py new file mode 100644 index 0000000000..2e35cf85cd --- /dev/null +++ b/test/integration/targets/ansible-test/ansible_collections/ns/col/plugins/random_directory/bad.py @@ -0,0 +1,8 @@ +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +# This is not an allowed import, but since this file is in a plugins/ subdirectory that is not checked, +# the import sanity test will not complain. +import lxml diff --git a/test/integration/targets/ansible-test/ansible_collections/ns/col/tests/sanity/ignore.txt b/test/integration/targets/ansible-test/ansible_collections/ns/col/tests/sanity/ignore.txt index 6d7877ba1e..e1b3f4ca09 100644 --- a/test/integration/targets/ansible-test/ansible_collections/ns/col/tests/sanity/ignore.txt +++ b/test/integration/targets/ansible-test/ansible_collections/ns/col/tests/sanity/ignore.txt @@ -1,5 +1,6 @@ plugins/modules/bad.py import plugins/modules/bad.py pylint:ansible-bad-module-import +plugins/lookup/bad.py import tests/integration/targets/hello/files/bad.py pylint:ansible-bad-function tests/integration/targets/hello/files/bad.py pylint:ansible-bad-import tests/integration/targets/hello/files/bad.py pylint:ansible-bad-import-from diff --git a/test/integration/targets/ansible-test/collection-tests/coverage.sh b/test/integration/targets/ansible-test/collection-tests/coverage.sh index 3d01dd4bc1..033a9836ea 100755 --- a/test/integration/targets/ansible-test/collection-tests/coverage.sh +++ b/test/integration/targets/ansible-test/collection-tests/coverage.sh @@ -7,7 +7,13 @@ cd "${WORK_DIR}/ansible_collections/ns/col" # rename the sanity ignore file to match the current ansible version and update import ignores with the python version ansible_version="$(python -c 'import ansible.release; print(".".join(ansible.release.__version__.split(".")[:2]))')" -sed "s/ import$/ import-${ANSIBLE_TEST_PYTHON_VERSION}/;" < "tests/sanity/ignore.txt" > "tests/sanity/ignore-${ansible_version}.txt" +if [ "${ANSIBLE_TEST_PYTHON_VERSION}" == "2.6" ]; then + # Non-module/module_utils plugins are not checked on this remote-only Python versions + sed "s/ import$/ import-${ANSIBLE_TEST_PYTHON_VERSION}/;" < "tests/sanity/ignore.txt" | grep -v 'plugins/[^m].* import' > "tests/sanity/ignore-${ansible_version}.txt" +else + sed "s/ import$/ import-${ANSIBLE_TEST_PYTHON_VERSION}/;" < "tests/sanity/ignore.txt" > "tests/sanity/ignore-${ansible_version}.txt" +fi +cat "tests/sanity/ignore-${ansible_version}.txt" # common args for all tests common=(--venv --color --truncate 0 "${@}") diff --git a/test/integration/targets/ansible-test/collection-tests/venv.sh b/test/integration/targets/ansible-test/collection-tests/venv.sh index 862c8ad989..ba0d2628d6 100755 --- a/test/integration/targets/ansible-test/collection-tests/venv.sh +++ b/test/integration/targets/ansible-test/collection-tests/venv.sh @@ -7,7 +7,13 @@ cd "${WORK_DIR}/ansible_collections/ns/col" # rename the sanity ignore file to match the current ansible version and update import ignores with the python version ansible_version="$(python -c 'import ansible.release; print(".".join(ansible.release.__version__.split(".")[:2]))')" -sed "s/ import$/ import-${ANSIBLE_TEST_PYTHON_VERSION}/;" < "tests/sanity/ignore.txt" > "tests/sanity/ignore-${ansible_version}.txt" +if [ "${ANSIBLE_TEST_PYTHON_VERSION}" == "2.6" ]; then + # Non-module/module_utils plugins are not checked on this remote-only Python versions + sed "s/ import$/ import-${ANSIBLE_TEST_PYTHON_VERSION}/;" < "tests/sanity/ignore.txt" | grep -v 'plugins/[^m].* import' > "tests/sanity/ignore-${ansible_version}.txt" +else + sed "s/ import$/ import-${ANSIBLE_TEST_PYTHON_VERSION}/;" < "tests/sanity/ignore.txt" > "tests/sanity/ignore-${ansible_version}.txt" +fi +cat "tests/sanity/ignore-${ansible_version}.txt" # common args for all tests # each test will be run in a separate venv to verify that requirements have been properly specified |