# Buggy code
def _find_snippet_imports(
    module_name, module_data, module_path, module_args, task_vars, module_compression
):
    """
    Given the source of the module, convert it to a Jinja2 template to insert
    module code and return whether it's a new or old style module.
    """

    module_substyle = module_style = "old"

    # module_style is something important to calling code (ActionBase).  It
    # determines how arguments are formatted (json vs k=v) and whether
    # a separate arguments file needs to be sent over the wire.
    # module_substyle is extra information that's useful internally.  It tells
    # us what we have to look to substitute in the module files and whether
    # we're using module replacer or ziploader to format the module itself.
    if REPLACER in module_data:
        # Do REPLACER before from ansible.module_utils because we need make sure
        # we substitute "from ansible.module_utils basic" for REPLACER
        module_style = "new"
        module_substyle = "python"
        module_data = module_data.replace(
            REPLACER, b"from ansible.module_utils.basic import *"
        )
    elif b"from ansible.module_utils." in module_data:
        module_style = "new"
        module_substyle = "python"
    elif REPLACER_WINDOWS in module_data:
        module_style = "new"
        module_substyle = "powershell"
    elif REPLACER_JSONARGS in module_data:
        module_style = "new"
        module_substyle = "jsonargs"
    elif b"WANT_JSON" in module_data:
        module_substyle = module_style = "non_native_want_json"

    shebang = None
    # Neither old-style nor non_native_want_json modules should be modified
    # except for the shebang line (Done by modify_module)
    if module_style in ("old", "non_native_want_json"):
        return module_data, module_style, shebang

    output = BytesIO()
    py_module_names = set()

    if module_substyle == "python":
        # ziploader for new-style python classes
        constants = dict(
            SELINUX_SPECIAL_FS=C.DEFAULT_SELINUX_SPECIAL_FS,
            SYSLOG_FACILITY=_get_facility(task_vars),
        )
        params = dict(
            ANSIBLE_MODULE_ARGS=module_args,
            ANSIBLE_MODULE_CONSTANTS=constants,
        )
        python_repred_params = to_bytes(repr(json.dumps(params)), errors="strict")

        try:
            compression_method = getattr(zipfile, module_compression)
        except AttributeError:
            display.warning(
                "Bad module compression string specified: %s.  Using ZIP_STORED (no compression)"
                % module_compression
            )
            compression_method = zipfile.ZIP_STORED

        lookup_path = os.path.join(C.DEFAULT_LOCAL_TMP, "ziploader_cache")
        cached_module_filename = os.path.join(
            lookup_path, "%s-%s" % (module_name, module_compression)
        )

        zipdata = None
        # Optimization -- don't lock if the module has already been cached
        if os.path.exists(cached_module_filename):
            zipdata = open(cached_module_filename, "rb").read()
            # Fool the check later... I think we should just remove the check
            py_module_names.add(("basic",))
        else:
            with action_write_locks[module_name]:
                # Check that no other process has created this while we were
                # waiting for the lock
                if not os.path.exists(cached_module_filename):
                    # Create the module zip data
                    zipoutput = BytesIO()
                    zf = zipfile.ZipFile(
                        zipoutput, mode="w", compression=compression_method
                    )
                    zf.writestr(
                        "ansible/__init__.py",
                        b"".join((b"__version__ = '", to_bytes(__version__), b"'\n")),
                    )
                    zf.writestr("ansible/module_utils/__init__.py", b"")

                    zf.writestr("ansible_module_%s.py" % module_name, module_data)

                    py_module_cache = {("__init__",): b""}
                    recursive_finder(
                        module_name, module_data, py_module_names, py_module_cache, zf
                    )
                    zf.close()
                    zipdata = base64.b64encode(zipoutput.getvalue())

                    # Write the assembled module to a temp file (write to temp
                    # so that no one looking for the file reads a partially
                    # written file)
                    if not os.path.exists(lookup_path):
                        # Note -- if we have a global function to setup, that would
                        # be a better place to run this
                        os.mkdir(lookup_path)
                    with open(cached_module_filename + "-part", "w") as f:
                        f.write(zipdata)

                    # Rename the file into its final position in the cache so
                    # future users of this module can read it off the
                    # filesystem instead of constructing from scratch.
                    os.rename(cached_module_filename + "-part", cached_module_filename)

            if zipdata is None:
                # Another process wrote the file while we were waiting for
                # the write lock.  Go ahead and read the data from disk
                # instead of re-creating it.
                try:
                    zipdata = open(cached_module_filename, "rb").read()
                except IOError:
                    raise AnsibleError(
                        "A different worker process failed to create module file.  Look at traceback for that process for debugging information."
                    )
                # Fool the check later... I think we should just remove the check
                py_module_names.add(("basic",))

        shebang, interpreter = _get_shebang("/usr/bin/python", task_vars)
        if shebang is None:
            shebang = "#!/usr/bin/python"
        output.write(
            to_bytes(
                ACTIVE_ZIPLOADER_TEMPLATE
                % dict(
                    zipdata=zipdata,
                    ansible_module=module_name,
                    params=python_repred_params,
                    shebang=shebang,
                    interpreter=interpreter,
                    coding=ENCODING_STRING,
                )
            )
        )
        module_data = output.getvalue()

        # Sanity check from 1.x days.  Maybe too strict.  Some custom python
        # modules that use ziploader may implement their own helpers and not
        # need basic.py.  All the constants that we substituted into basic.py
        # for module_replacer are now available in other, better ways.
        if ("basic",) not in py_module_names:
            raise AnsibleError(
                "missing required import in %s: Did not import ansible.module_utils.basic for boilerplate helper code"
                % module_path
            )

    elif module_substyle == "powershell":
        # Module replacer for jsonargs and windows
        lines = module_data.split(b"\n")
        for line in lines:
            if REPLACER_WINDOWS in line:
                ps_data = _slurp(os.path.join(_SNIPPET_PATH, "powershell.ps1"))
                output.write(ps_data)
                py_module_names.add((b"powershell",))
                continue
            output.write(line + b"\n")
        module_data = output.getvalue()

        module_args_json = to_bytes(json.dumps(module_args))
        module_data = module_data.replace(REPLACER_JSONARGS, module_args_json)

        # Sanity check from 1.x days.  This is currently useless as we only
        # get here if we are going to substitute powershell.ps1 into the
        # module anyway.  Leaving it for when/if we add other powershell
        # module_utils files.
        if (b"powershell",) not in py_module_names:
            raise AnsibleError(
                "missing required import in %s: # POWERSHELL_COMMON" % module_path
            )

    elif module_substyle == "jsonargs":
        module_args_json = to_bytes(json.dumps(module_args))

        # these strings could be included in a third-party module but
        # officially they were included in the 'basic' snippet for new-style
        # python modules (which has been replaced with something else in
        # ziploader) If we remove them from jsonargs-style module replacer
        # then we can remove them everywhere.
        python_repred_args = to_bytes(repr(module_args_json))
        module_data = module_data.replace(REPLACER_VERSION, to_bytes(repr(__version__)))
        module_data = module_data.replace(REPLACER_COMPLEX, python_repred_args)
        module_data = module_data.replace(
            REPLACER_SELINUX, to_bytes(",".join(C.DEFAULT_SELINUX_SPECIAL_FS))
        )

        # The main event -- substitute the JSON args string into the module
        module_data = module_data.replace(REPLACER_JSONARGS, module_args_json)

        facility = b"syslog." + to_bytes(_get_facility(task_vars), errors="strict")
        module_data = module_data.replace(b"syslog.LOG_USER", facility)

    return (module_data, module_style, shebang)


# Traceback (OSError)
% ansible-playbook -vvvv -i inventory playbook.yml
Using /Users/jladd/.ansible.cfg as config file
Loaded callback default of type stdout, v2.0

PLAYBOOK: playbook.yml *********************************************************
1 plays in playbook.yml

PLAY [all] *********************************************************************

TASK [setup] *******************************************************************
<127.0.0.1> ESTABLISH LOCAL CONNECTION FOR USER: jladd
<127.0.0.1> EXEC /bin/sh -c '( umask 77 &amp;&amp; mkdir -p "` echo $HOME/.ansible/tmp/ansible-tmp-1461804617.07-35816113603270 `" &amp;&amp; echo "` echo $HOME/.ansible/tmp/ansible-tmp-1461804617.07-35816113603270 `" )'
<127.0.0.1> PUT /var/folders/9f/lfcc9zd96fngv4bpptdg86700000gn/T/tmp7VbvKW TO /Users/jladd/.ansible/tmp/ansible-tmp-1461804617.07-35816113603270/setup
<127.0.0.1> EXEC /bin/sh -c 'LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8 /usr/bin/env python /Users/jladd/.ansible/tmp/ansible-tmp-1461804617.07-35816113603270/setup; rm -rf "/Users/jladd/.ansible/tmp/ansible-tmp-1461804617.07-35816113603270/" > /dev/null 2>&amp;1'
An exception occurred during task execution. The full traceback is:
Traceback (most recent call last):
File "/Users/jladd/.ansible/tmp/ansible-tmp-1461804617.07-35816113603270/setup", line 114, in <module>
exitcode = invoke_module(module, zipped_mod, ZIPLOADER_PARAMS)
File "/Users/jladd/.ansible/tmp/ansible-tmp-1461804617.07-35816113603270/setup", line 28, in invoke_module
p = subprocess.Popen(['/usr/bin/env python', module], env=os.environ, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
File "/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 710, in __init__
errread, errwrite)
File "/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 1335, in _execute_child
raise child_exception
OSError: [Errno 2] No such file or directory

fatal: [127.0.0.1]: FAILED! => {"changed": false, "failed": true, "invocation": {"module_name": "setup"}, "module_stderr": "Traceback (most recent call last):\n  File \"/Users/jladd/.ansible/tmp/ansible-tmp-1461804617.07-35816113603270/setup\", line 114, in <module>\n    exitcode = invoke_module(module, zipped_mod, ZIPLOADER_PARAMS)\n  File \"/Users/jladd/.ansible/tmp/ansible-tmp-1461804617.07-35816113603270/setup\", line 28, in invoke_module\n    p = subprocess.Popen(['/usr/bin/env python', module], env=os.environ, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)\n  File \"/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py\", line 710, in __init__\n    errread, errwrite)\n  File \"/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py\", line 1335, in _execute_child\n    raise child_exception\nOSError: [Errno 2] No such file or directory\n", "module_stdout": "", "msg": "MODULE FAILURE", "parsed": false}

NO MORE HOSTS LEFT *************************************************************
to retry, use: --limit @playbook.retry

PLAY RECAP *********************************************************************
127.0.0.1                  : ok=0    changed=0    unreachable=0    failed=1

# Fixed code
def _find_snippet_imports(
    module_name, module_data, module_path, module_args, task_vars, module_compression
):
    """
    Given the source of the module, convert it to a Jinja2 template to insert
    module code and return whether it's a new or old style module.
    """

    module_substyle = module_style = "old"

    # module_style is something important to calling code (ActionBase).  It
    # determines how arguments are formatted (json vs k=v) and whether
    # a separate arguments file needs to be sent over the wire.
    # module_substyle is extra information that's useful internally.  It tells
    # us what we have to look to substitute in the module files and whether
    # we're using module replacer or ziploader to format the module itself.
    if REPLACER in module_data:
        # Do REPLACER before from ansible.module_utils because we need make sure
        # we substitute "from ansible.module_utils basic" for REPLACER
        module_style = "new"
        module_substyle = "python"
        module_data = module_data.replace(
            REPLACER, b"from ansible.module_utils.basic import *"
        )
    elif b"from ansible.module_utils." in module_data:
        module_style = "new"
        module_substyle = "python"
    elif REPLACER_WINDOWS in module_data:
        module_style = "new"
        module_substyle = "powershell"
    elif REPLACER_JSONARGS in module_data:
        module_style = "new"
        module_substyle = "jsonargs"
    elif b"WANT_JSON" in module_data:
        module_substyle = module_style = "non_native_want_json"

    shebang = None
    # Neither old-style nor non_native_want_json modules should be modified
    # except for the shebang line (Done by modify_module)
    if module_style in ("old", "non_native_want_json"):
        return module_data, module_style, shebang

    output = BytesIO()
    py_module_names = set()

    if module_substyle == "python":
        # ziploader for new-style python classes
        constants = dict(
            SELINUX_SPECIAL_FS=C.DEFAULT_SELINUX_SPECIAL_FS,
            SYSLOG_FACILITY=_get_facility(task_vars),
        )
        params = dict(
            ANSIBLE_MODULE_ARGS=module_args,
            ANSIBLE_MODULE_CONSTANTS=constants,
        )
        python_repred_params = to_bytes(repr(json.dumps(params)), errors="strict")

        try:
            compression_method = getattr(zipfile, module_compression)
        except AttributeError:
            display.warning(
                "Bad module compression string specified: %s.  Using ZIP_STORED (no compression)"
                % module_compression
            )
            compression_method = zipfile.ZIP_STORED

        lookup_path = os.path.join(C.DEFAULT_LOCAL_TMP, "ziploader_cache")
        cached_module_filename = os.path.join(
            lookup_path, "%s-%s" % (module_name, module_compression)
        )

        zipdata = None
        # Optimization -- don't lock if the module has already been cached
        if os.path.exists(cached_module_filename):
            zipdata = open(cached_module_filename, "rb").read()
            # Fool the check later... I think we should just remove the check
            py_module_names.add(("basic",))
        else:
            with action_write_locks[module_name]:
                # Check that no other process has created this while we were
                # waiting for the lock
                if not os.path.exists(cached_module_filename):
                    # Create the module zip data
                    zipoutput = BytesIO()
                    zf = zipfile.ZipFile(
                        zipoutput, mode="w", compression=compression_method
                    )
                    zf.writestr(
                        "ansible/__init__.py",
                        b"".join((b"__version__ = '", to_bytes(__version__), b"'\n")),
                    )
                    zf.writestr("ansible/module_utils/__init__.py", b"")

                    zf.writestr("ansible_module_%s.py" % module_name, module_data)

                    py_module_cache = {("__init__",): b""}
                    recursive_finder(
                        module_name, module_data, py_module_names, py_module_cache, zf
                    )
                    zf.close()
                    zipdata = base64.b64encode(zipoutput.getvalue())

                    # Write the assembled module to a temp file (write to temp
                    # so that no one looking for the file reads a partially
                    # written file)
                    if not os.path.exists(lookup_path):
                        # Note -- if we have a global function to setup, that would
                        # be a better place to run this
                        os.mkdir(lookup_path)
                    with open(cached_module_filename + "-part", "w") as f:
                        f.write(zipdata)

                    # Rename the file into its final position in the cache so
                    # future users of this module can read it off the
                    # filesystem instead of constructing from scratch.
                    os.rename(cached_module_filename + "-part", cached_module_filename)

            if zipdata is None:
                # Another process wrote the file while we were waiting for
                # the write lock.  Go ahead and read the data from disk
                # instead of re-creating it.
                try:
                    zipdata = open(cached_module_filename, "rb").read()
                except IOError:
                    raise AnsibleError(
                        "A different worker process failed to create module file.  Look at traceback for that process for debugging information."
                    )
                # Fool the check later... I think we should just remove the check
                py_module_names.add(("basic",))

        shebang, interpreter = _get_shebang("/usr/bin/python", task_vars)
        if shebang is None:
            shebang = "#!/usr/bin/python"

        executable = interpreter.split(" ", 1)
        if len(executable) == 2 and executable[0].endswith("env"):
            # Handle /usr/bin/env python style interpreter settings
            interpreter = "'{0}', '{1}'".format(*executable)
        else:
            # Still have to enclose the parts of the interpreter in quotes
            # because we're substituting it into the template as a python
            # string
            interpreter = "'{0}'".format(interpreter)

        output.write(
            to_bytes(
                ACTIVE_ZIPLOADER_TEMPLATE
                % dict(
                    zipdata=zipdata,
                    ansible_module=module_name,
                    params=python_repred_params,
                    shebang=shebang,
                    interpreter=interpreter,
                    coding=ENCODING_STRING,
                )
            )
        )
        module_data = output.getvalue()

        # Sanity check from 1.x days.  Maybe too strict.  Some custom python
        # modules that use ziploader may implement their own helpers and not
        # need basic.py.  All the constants that we substituted into basic.py
        # for module_replacer are now available in other, better ways.
        if ("basic",) not in py_module_names:
            raise AnsibleError(
                "missing required import in %s: Did not import ansible.module_utils.basic for boilerplate helper code"
                % module_path
            )

    elif module_substyle == "powershell":
        # Module replacer for jsonargs and windows
        lines = module_data.split(b"\n")
        for line in lines:
            if REPLACER_WINDOWS in line:
                ps_data = _slurp(os.path.join(_SNIPPET_PATH, "powershell.ps1"))
                output.write(ps_data)
                py_module_names.add((b"powershell",))
                continue
            output.write(line + b"\n")
        module_data = output.getvalue()

        module_args_json = to_bytes(json.dumps(module_args))
        module_data = module_data.replace(REPLACER_JSONARGS, module_args_json)

        # Sanity check from 1.x days.  This is currently useless as we only
        # get here if we are going to substitute powershell.ps1 into the
        # module anyway.  Leaving it for when/if we add other powershell
        # module_utils files.
        if (b"powershell",) not in py_module_names:
            raise AnsibleError(
                "missing required import in %s: # POWERSHELL_COMMON" % module_path
            )

    elif module_substyle == "jsonargs":
        module_args_json = to_bytes(json.dumps(module_args))

        # these strings could be included in a third-party module but
        # officially they were included in the 'basic' snippet for new-style
        # python modules (which has been replaced with something else in
        # ziploader) If we remove them from jsonargs-style module replacer
        # then we can remove them everywhere.
        python_repred_args = to_bytes(repr(module_args_json))
        module_data = module_data.replace(REPLACER_VERSION, to_bytes(repr(__version__)))
        module_data = module_data.replace(REPLACER_COMPLEX, python_repred_args)
        module_data = module_data.replace(
            REPLACER_SELINUX, to_bytes(",".join(C.DEFAULT_SELINUX_SPECIAL_FS))
        )

        # The main event -- substitute the JSON args string into the module
        module_data = module_data.replace(REPLACER_JSONARGS, module_args_json)

        facility = b"syslog." + to_bytes(_get_facility(task_vars), errors="strict")
        module_data = module_data.replace(b"syslog.LOG_USER", facility)

    return (module_data, module_style, shebang)