# Buggy code
def main():
    module = AnsibleModule(
        argument_spec=dict(
            path=dict(type="path", required=True, aliases=["filename"]),
            dialect=dict(type="str", default="excel"),
            key=dict(type="str"),
            fieldnames=dict(type="list"),
            unique=dict(type="bool", default=True),
            delimiter=dict(type="str"),
            skipinitialspace=dict(type="bool"),
            strict=dict(type="bool"),
        ),
        supports_check_mode=True,
    )

    path = module.params["path"]
    dialect = module.params["dialect"]
    key = module.params["key"]
    fieldnames = module.params["fieldnames"]
    unique = module.params["unique"]

    if dialect not in csv.list_dialects():
        module.fail_json(
            msg="Dialect '%s' is not supported by your version of python." % dialect
        )

    dialect_options = dict(
        delimiter=module.params["delimiter"],
        skipinitialspace=module.params["skipinitialspace"],
        strict=module.params["strict"],
    )

    # Create a dictionary from only set options
    dialect_params = dict((k, v) for k, v in dialect_options.items() if v is not None)
    if dialect_params:
        try:
            csv.register_dialect("custom", dialect, **dialect_params)
        except TypeError as e:
            module.fail_json(msg="Unable to create custom dialect: %s" % to_text(e))
        dialect = "custom"

    try:
        f = open(path, "r")
    except (IOError, OSError) as e:
        module.fail_json(msg="Unable to open file: %s" % to_text(e))

    reader = csv.DictReader(f, fieldnames=fieldnames, dialect=dialect)

    if key and key not in reader.fieldnames:
        module.fail_json(
            msg="Key '%s' was not found in the CSV header fields: %s"
            % (key, ", ".join(reader.fieldnames))
        )

    data_dict = dict()
    data_list = list()

    if key is None:
        try:
            for row in reader:
                data_list.append(row)
        except csv.Error as e:
            module.fail_json(msg="Unable to process file: %s" % to_text(e))
    else:
        try:
            for row in reader:
                if unique and row[key] in data_dict:
                    module.fail_json(
                        msg="Key '%s' is not unique for value '%s'" % (key, row[key])
                    )
                data_dict[row[key]] = row
        except csv.Error as e:
            module.fail_json(msg="Unable to process file: %s" % to_text(e))

    module.exit_json(dict=data_dict, list=data_list)


# Traceback (nUnicodeDecodeError)
TASK [read_csv : Read users from CSV file and return a dictionary] ******************************************************************************************************
fatal: [testhost]: FAILED! => {"changed": false, "module_stderr": "Shared connection to localhost closed.\r\n", "module_stdout": "Traceback (most recent call last):\r\n  File \"/root/.ansible/tmp/ansible-tmp-1561575641.134005-97732254058242/AnsiballZ_read_csv.py\", line 139, in <module>\r\n    _ansiballz_main()\r\n  File \"/root/.ansible/tmp/ansible-tmp-1561575641.134005-97732254058242/AnsiballZ_read_csv.py\", line 131, in _ansiballz_main\r\n    invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)\r\n  File \"/root/.ansible/tmp/ansible-tmp-1561575641.134005-97732254058242/AnsiballZ_read_csv.py\", line 65, in invoke_module\r\n    spec.loader.exec_module(module)\r\n  File \"<frozen importlib._bootstrap_external>\", line 678, in exec_module\r\n  File \"<frozen importlib._bootstrap>\", line 219, in _call_with_frames_removed\r\n  File \"/tmp/ansible_read_csv_payload_dllmyumq/__main__.py\", line 235, in <module>\r\n  File \"/tmp/ansible_read_csv_payload_dllmyumq/__main__.py\", line 210, in main\r\n  File \"/usr/local/lib/python3.6/csv.py\", line 98, in fieldnames\r\n    self._fieldnames = next(self.reader)\r\n  File \"/usr/local/lib/python3.6/encodings/ascii.py\", line 26, in decode\r\n    return codecs.ascii_decode(input, self.errors)[0]\r\nUnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 38: ordinal not in range(128)\r\n", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 1}

# Fixed code
def main():
    module = AnsibleModule(
        argument_spec=dict(
            path=dict(type="path", required=True, aliases=["filename"]),
            dialect=dict(type="str", default="excel"),
            key=dict(type="str"),
            fieldnames=dict(type="list"),
            unique=dict(type="bool", default=True),
            delimiter=dict(type="str"),
            skipinitialspace=dict(type="bool"),
            strict=dict(type="bool"),
        ),
        supports_check_mode=True,
    )

    path = module.params["path"]
    dialect = module.params["dialect"]
    key = module.params["key"]
    fieldnames = module.params["fieldnames"]
    unique = module.params["unique"]

    if dialect not in csv.list_dialects():
        module.fail_json(
            msg="Dialect '%s' is not supported by your version of python." % dialect
        )

    dialect_options = dict(
        delimiter=module.params["delimiter"],
        skipinitialspace=module.params["skipinitialspace"],
        strict=module.params["strict"],
    )

    # Create a dictionary from only set options
    dialect_params = dict((k, v) for k, v in dialect_options.items() if v is not None)
    if dialect_params:
        try:
            csv.register_dialect("custom", dialect, **dialect_params)
        except TypeError as e:
            module.fail_json(msg="Unable to create custom dialect: %s" % to_text(e))
        dialect = "custom"

    try:
        with open(path, "rb") as f:
            data = f.read()
    except (IOError, OSError) as e:
        module.fail_json(msg="Unable to open file: %s" % to_text(e))

    if PY3:
        # Manually decode on Python3 so that we can use the surrogateescape error handler
        data = to_text(data, errors="surrogate_or_strict")
        fake_fh = StringIO(data)
    else:
        fake_fh = BytesIO(data)

    reader = csv.DictReader(fake_fh, fieldnames=fieldnames, dialect=dialect)

    if key and key not in reader.fieldnames:
        module.fail_json(
            msg="Key '%s' was not found in the CSV header fields: %s"
            % (key, ", ".join(reader.fieldnames))
        )

    data_dict = dict()
    data_list = list()

    if key is None:
        try:
            for row in reader:
                data_list.append(row)
        except csv.Error as e:
            module.fail_json(msg="Unable to process file: %s" % to_text(e))
    else:
        try:
            for row in reader:
                if unique and row[key] in data_dict:
                    module.fail_json(
                        msg="Key '%s' is not unique for value '%s'" % (key, row[key])
                    )
                data_dict[row[key]] = row
        except csv.Error as e:
            module.fail_json(msg="Unable to process file: %s" % to_text(e))

    module.exit_json(dict=data_dict, list=data_list)