diff --git a/docs/docsite/rst/dev_guide/developing_modules_best_practices.rst b/docs/docsite/rst/dev_guide/developing_modules_best_practices.rst index 20526dd184e..8e084b3f4f6 100644 --- a/docs/docsite/rst/dev_guide/developing_modules_best_practices.rst +++ b/docs/docsite/rst/dev_guide/developing_modules_best_practices.rst @@ -59,22 +59,29 @@ Importing and using shared code * Use shared code whenever possible - don't reinvent the wheel. Ansible offers the ``AnsibleModule`` common Python code, plus :ref:`utilities ` for many common use cases and patterns. * Import ``ansible.module_utils`` code in the same place as you import other libraries. * Do NOT use wildcards (*) for importing other python modules; instead, list the function(s) you are importing (for example, ``from some.other_python_module.basic import otherFunction``). -* Import custom packages in ``try``/``except`` and handle them with ``fail_json()`` in ``main()``. For example: +* Import custom packages in ``try``/``except``, capture any import errors, and handle them with ``fail_json()`` in ``main()``. For example: .. code-block:: python + import traceback + + from ansible.basic import missing_required_lib + + LIB_IMP_ERR = None try: import foo - HAS_LIB=True + HAS_LIB = True except: - HAS_LIB=False + HAS_LIB = False + LIB_IMP_ERR = traceback.format_exc() - Then in main(), just after the argspec, do + Then in ``main()``, just after the argspec, do .. code-block:: python if not HAS_LIB: - module.fail_json(msg='The foo Python module is required') + module.fail_json(msg=missing_required_lib("foo"), + exception=LIB_IMP_ERR) And document the dependency in the ``requirements`` section of your module's :ref:`documentation_block`. diff --git a/lib/ansible/module_utils/basic.py b/lib/ansible/module_utils/basic.py index d673c0f69b9..63a20ea9b82 100644 --- a/lib/ansible/module_utils/basic.py +++ b/lib/ansible/module_utils/basic.py @@ -785,6 +785,12 @@ def jsonify(data, **kwargs): raise UnicodeError('Invalid unicode encoding encountered') +def missing_required_lib(library): + hostname = platform.node() + return "Failed to import the required Python library (%s) on %s's Python %s. Please read module documentation " \ + "and install in the appropriate location." % (library, hostname, sys.executable) + + class AnsibleFallbackNotFound(Exception): pass diff --git a/lib/ansible/modules/commands/psexec.py b/lib/ansible/modules/commands/psexec.py index 4a534c63a81..6b1af39aa80 100644 --- a/lib/ansible/modules/commands/psexec.py +++ b/lib/ansible/modules/commands/psexec.py @@ -321,10 +321,9 @@ rc: sample: 0 ''' -import sys import traceback -from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible.module_utils._text import to_bytes, to_text PYPSEXEC_IMP_ERR = None @@ -407,9 +406,7 @@ def main(): 'running as System: process_username, ' 'process_password') if not HAS_PYPSEXEC: - module.fail_json(msg="The pypsexec Python module is required to be " - "installed for the Python environment at '%s'" - % sys.executable, + module.fail_json(msg=missing_required_lib("pypsexec"), exception=PYPSEXEC_IMP_ERR) hostname = module.params['hostname'] @@ -443,11 +440,8 @@ def main(): if connection_username is None or connection_password is None and \ not HAS_KERBEROS: - module.fail_json(msg="The gssapi Python module with the GGF extension " - "used for kerberos auth is required to be " - "installed for the Python environment at '%s'" - % sys.executable, - exception=KERBEROS_IMP_ERR) + module.fail_json(msg=missing_required_lib("gssapi"), + execption=KERBEROS_IMP_ERR) win_client = client.Client(server=hostname, username=connection_username, password=connection_password, port=port,