Import test: improve docs, add more tests (#73600)
This commit is contained in:
parent
ba3f84883f
commit
3cc693b92c
7 changed files with 148 additions and 4 deletions
docs/docsite/rst/dev_guide/testing/sanity
test/integration/targets/ansible-test
ansible_collections/ns/col
collection-tests
|
@ -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.
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -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]))')"
|
||||||
|
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"
|
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 "${@}")
|
||||||
|
|
|
@ -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]))')"
|
||||||
|
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"
|
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
|
||||||
|
|
Loading…
Reference in a new issue