# Buggy code
def _download_updates(self):
    updates_filename = "jenkins-plugin-cache.json"
    updates_dir = os.path.expanduser("~/.ansible/tmp")
    updates_file = "%s/%s" % (updates_dir, updates_filename)
    download_updates = True

    # Check if we need to download new updates file
    if os.path.isfile(updates_file):
        # Get timestamp when the file was changed last time
        ts_file = os.stat(updates_file).st_mtime
        ts_now = time.time()

        if ts_now - ts_file < self.params["updates_expiration"]:
            download_updates = False

    updates_file_orig = updates_file

    # Download the updates file if needed
    if download_updates:
        url = "%s/update-center.json" % self.params["updates_url"]

        # Get the data
        r = self._get_url_data(
            url,
            msg_status="Remote updates not found.",
            msg_exception="Updates download failed.",
        )

        # Write the updates file
        update_fd, updates_file = tempfile.mkstemp()
        os.write(update_fd, r.read())

        try:
            os.close(update_fd)
        except IOError as e:
            self.module.fail_json(
                msg="Cannot close the tmp updates file %s." % updates_file,
                details=to_native(e),
            )

    # Open the updates file
    try:
        f = open(updates_file)
    except IOError as e:
        self.module.fail_json(
            msg="Cannot open temporal updates file.", details=to_native(e)
        )

    i = 0
    for line in f:
        # Read only the second line
        if i == 1:
            try:
                data = json.loads(line)
            except Exception as e:
                self.module.fail_json(
                    msg="Cannot load JSON data from the tmp updates file.",
                    details=to_native(e),
                )

            break

        i += 1

    # Move the updates file to the right place if we could read it
    if download_updates:
        # Make sure the destination directory exists
        if not os.path.isdir(updates_dir):
            try:
                os.makedirs(updates_dir, int("0700", 8))
            except OSError as e:
                self.module.fail_json(
                    msg="Cannot create temporal directory.", details=to_native(e)
                )

        self.module.atomic_move(updates_file, updates_file_orig)

    # Check if we have the plugin data available
    if "plugins" not in data or self.params["name"] not in data["plugins"]:
        self.module.fail_json(msg="Cannot find plugin data in the updates file.")

    return data["plugins"][self.params["name"]]


# Traceback (UnicodeDecodeError)
TASK [jenkins : install plugin: ansible]
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position 5126: ordinal not in range(128)
failed: [i_0f827847aaa40f04b] (item=ansible) => {
"ansible_loop_var": "item",
"changed": false,
"item": "ansible",
"rc": 1
}

MSG:

MODULE FAILURE
See stdout/stderr for the exact error


MODULE_STDERR:

Traceback (most recent call last):
File "<stdin>", line 114, in <module>
File "<stdin>", line 106, in _ansiballz_main
File "<stdin>", line 49, in invoke_module
File "/usr/lib/python3.6/imp.py", line 235, in load_module
return load_source(name, filename, file)
File "/usr/lib/python3.6/imp.py", line 170, in load_source
module = _exec(spec, sys.modules[name])
File "<frozen importlib._bootstrap>", line 618, in _exec
File "<frozen importlib._bootstrap_external>", line 678, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "/tmp/ansible_jenkins_plugin_payload_hm9w1r02/__main__.py", line 787, in <module>
File "/tmp/ansible_jenkins_plugin_payload_hm9w1r02/__main__.py", line 770, in main
File "/tmp/ansible_jenkins_plugin_payload_hm9w1r02/__main__.py", line 483, in install
File "/tmp/ansible_jenkins_plugin_payload_hm9w1r02/__main__.py", line 569, in _download_updates
File "/usr/lib/python3.6/encodings/ascii.py", line 26, in decode
return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position 5126: ordinal not in range(128)

<<<REPEATED>>>

# Fixed code
def _download_updates(self):
    updates_filename = "jenkins-plugin-cache.json"
    updates_dir = os.path.expanduser("~/.ansible/tmp")
    updates_file = "%s/%s" % (updates_dir, updates_filename)
    download_updates = True

    # Check if we need to download new updates file
    if os.path.isfile(updates_file):
        # Get timestamp when the file was changed last time
        ts_file = os.stat(updates_file).st_mtime
        ts_now = time.time()

        if ts_now - ts_file < self.params["updates_expiration"]:
            download_updates = False

    updates_file_orig = updates_file

    # Download the updates file if needed
    if download_updates:
        url = "%s/update-center.json" % self.params["updates_url"]

        # Get the data
        r = self._get_url_data(
            url,
            msg_status="Remote updates not found.",
            msg_exception="Updates download failed.",
        )

        # Write the updates file
        update_fd, updates_file = tempfile.mkstemp()
        os.write(update_fd, r.read())

        try:
            os.close(update_fd)
        except IOError as e:
            self.module.fail_json(
                msg="Cannot close the tmp updates file %s." % updates_file,
                details=to_native(e),
            )

    # Open the updates file
    try:
        f = open(updates_file, encoding="utf-8")
    except IOError as e:
        self.module.fail_json(
            msg="Cannot open temporal updates file.", details=to_native(e)
        )

    i = 0
    for line in f:
        # Read only the second line
        if i == 1:
            try:
                data = json.loads(line)
            except Exception as e:
                self.module.fail_json(
                    msg="Cannot load JSON data from the tmp updates file.",
                    details=to_native(e),
                )

            break

        i += 1

    # Move the updates file to the right place if we could read it
    if download_updates:
        # Make sure the destination directory exists
        if not os.path.isdir(updates_dir):
            try:
                os.makedirs(updates_dir, int("0700", 8))
            except OSError as e:
                self.module.fail_json(
                    msg="Cannot create temporal directory.", details=to_native(e)
                )

        self.module.atomic_move(updates_file, updates_file_orig)

    # Check if we have the plugin data available
    if "plugins" not in data or self.params["name"] not in data["plugins"]:
        self.module.fail_json(msg="Cannot find plugin data in the updates file.")

    return data["plugins"][self.params["name"]]