Import test: improve docs, add more tests (#73600)

This commit is contained in:
Felix Fontein 2021-03-02 01:10:46 +01:00 committed by GitHub
parent ba3f84883f
commit 3cc693b92c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 148 additions and 4 deletions

View file

@ -1,5 +1,68 @@
import import
====== ======
All Python imports in ``lib/ansible/modules/`` and ``lib/ansible/module_utils/`` which are not from the Python standard library 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:
must be imported 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.

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -1,5 +1,6 @@
plugins/modules/bad.py import plugins/modules/bad.py import
plugins/modules/bad.py pylint:ansible-bad-module-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-function
tests/integration/targets/hello/files/bad.py pylint:ansible-bad-import tests/integration/targets/hello/files/bad.py pylint:ansible-bad-import
tests/integration/targets/hello/files/bad.py pylint:ansible-bad-import-from tests/integration/targets/hello/files/bad.py pylint:ansible-bad-import-from

View file

@ -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 # 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]))')" 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 args for all tests
common=(--venv --color --truncate 0 "${@}") common=(--venv --color --truncate 0 "${@}")

View file

@ -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 # 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]))')" 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 args for all tests
# each test will be run in a separate venv to verify that requirements have been properly specified # each test will be run in a separate venv to verify that requirements have been properly specified