-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Added from_csv filter and integration tests * Cleaning up whitespace * Adding changelog fragment * Updated changelog fragment name * Removed temp fragment * Refactoring csv functions Part 1 * Syncing refactored csv modules/filters * Adding unit tests for csv Module_Util * Updating changelog fragment * Correcting whitespace in unit test * Improving changelog fragment Co-authored-by: Felix Fontein <felix@fontein.de> * Update changelogs/fragments/2037-add-from-csv-filter.yml Co-authored-by: Felix Fontein <felix@fontein.de>
- Loading branch information
1 parent
c147d2f
commit 6529390
Showing
8 changed files
with
383 additions
and
47 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
--- | ||
add plugin.filter: | ||
- name: from_csv | ||
description: Converts CSV text input into list of dicts | ||
minor_changes: | ||
- csv module utils - new module_utils for shared functions between ``from_csv`` filter and ``read_csv`` module (https://github.com/ansible-collections/community.general/pull/2037). | ||
- read_csv - refactored read_csv module to use shared csv functions from csv module_utils (https://github.com/ansible-collections/community.general/pull/2037). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
# -*- coding: utf-8 -*- | ||
|
||
# Copyright: (c) 2021, Andrew Pantuso (@ajpantuso) <ajpantuso@gmail.com> | ||
# Copyright: (c) 2018, Dag Wieers (@dagwieers) <dag@wieers.com> | ||
# 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 | ||
|
||
from ansible.errors import AnsibleFilterError | ||
from ansible.module_utils._text import to_native | ||
|
||
from ansible_collections.community.general.plugins.module_utils.csv import (initialize_dialect, read_csv, CSVError, | ||
DialectNotAvailableError, | ||
CustomDialectFailureError) | ||
|
||
|
||
def from_csv(data, dialect='excel', fieldnames=None, delimiter=None, skipinitialspace=None, strict=None): | ||
|
||
dialect_params = { | ||
"delimiter": delimiter, | ||
"skipinitialspace": skipinitialspace, | ||
"strict": strict, | ||
} | ||
|
||
try: | ||
dialect = initialize_dialect(dialect, **dialect_params) | ||
except (CustomDialectFailureError, DialectNotAvailableError) as e: | ||
raise AnsibleFilterError(to_native(e)) | ||
|
||
reader = read_csv(data, dialect, fieldnames) | ||
|
||
data_list = [] | ||
|
||
try: | ||
for row in reader: | ||
data_list.append(row) | ||
except CSVError as e: | ||
raise AnsibleFilterError("Unable to process file: %s" % to_native(e)) | ||
|
||
return data_list | ||
|
||
|
||
class FilterModule(object): | ||
|
||
def filters(self): | ||
return { | ||
'from_csv': from_csv | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
# -*- coding: utf-8 -*- | ||
|
||
# Copyright: (c) 2021, Andrew Pantuso (@ajpantuso) <ajpantuso@gmail.com> | ||
# Copyright: (c) 2018, Dag Wieers (@dagwieers) <dag@wieers.com> | ||
# 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 | ||
|
||
import csv | ||
from io import BytesIO, StringIO | ||
|
||
from ansible.module_utils._text import to_native | ||
from ansible.module_utils.six import PY3 | ||
|
||
|
||
class CustomDialectFailureError(Exception): | ||
pass | ||
|
||
|
||
class DialectNotAvailableError(Exception): | ||
pass | ||
|
||
|
||
CSVError = csv.Error | ||
|
||
|
||
def initialize_dialect(dialect, **kwargs): | ||
# Add Unix dialect from Python 3 | ||
class unix_dialect(csv.Dialect): | ||
"""Describe the usual properties of Unix-generated CSV files.""" | ||
delimiter = ',' | ||
quotechar = '"' | ||
doublequote = True | ||
skipinitialspace = False | ||
lineterminator = '\n' | ||
quoting = csv.QUOTE_ALL | ||
|
||
csv.register_dialect("unix", unix_dialect) | ||
|
||
if dialect not in csv.list_dialects(): | ||
raise DialectNotAvailableError("Dialect '%s' is not supported by your version of python." % dialect) | ||
|
||
# Create a dictionary from only set options | ||
dialect_params = dict((k, v) for k, v in kwargs.items() if v is not None) | ||
if dialect_params: | ||
try: | ||
csv.register_dialect('custom', dialect, **dialect_params) | ||
except TypeError as e: | ||
raise CustomDialectFailureError("Unable to create custom dialect: %s" % to_native(e)) | ||
dialect = 'custom' | ||
|
||
return dialect | ||
|
||
|
||
def read_csv(data, dialect, fieldnames=None): | ||
|
||
data = to_native(data, errors='surrogate_or_strict') | ||
|
||
if PY3: | ||
fake_fh = StringIO(data) | ||
else: | ||
fake_fh = BytesIO(data) | ||
|
||
reader = csv.DictReader(fake_fh, fieldnames=fieldnames, dialect=dialect) | ||
|
||
return reader |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
shippable/posix/group2 | ||
skip/python2.6 # filters are controller only, and we no longer support Python 2.6 on the controller |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
#################################################################### | ||
# WARNING: These are designed specifically for Ansible tests # | ||
# and should not be used as examples of how to write Ansible roles # | ||
#################################################################### | ||
|
||
- name: Parse valid csv input | ||
assert: | ||
that: | ||
- "valid_comma_separated | community.general.from_csv == expected_result" | ||
|
||
- name: Parse valid csv input containing spaces with/without skipinitialspace=True | ||
assert: | ||
that: | ||
- "valid_comma_separated_spaces | community.general.from_csv(skipinitialspace=True) == expected_result" | ||
- "valid_comma_separated_spaces | community.general.from_csv != expected_result" | ||
|
||
- name: Parse valid csv input with no headers with/without specifiying fieldnames | ||
assert: | ||
that: | ||
- "valid_comma_separated_no_headers | community.general.from_csv(fieldnames=['id','name','role']) == expected_result" | ||
- "valid_comma_separated_no_headers | community.general.from_csv != expected_result" | ||
|
||
- name: Parse valid pipe-delimited csv input with/without delimiter=| | ||
assert: | ||
that: | ||
- "valid_pipe_separated | community.general.from_csv(delimiter='|') == expected_result" | ||
- "valid_pipe_separated | community.general.from_csv != expected_result" | ||
|
||
- name: Register result of invalid csv input when strict=False | ||
debug: | ||
var: "invalid_comma_separated | community.general.from_csv" | ||
register: _invalid_csv_strict_false | ||
|
||
- name: Test invalid csv input when strict=False is successful | ||
assert: | ||
that: | ||
- _invalid_csv_strict_false is success | ||
|
||
- name: Register result of invalid csv input when strict=True | ||
debug: | ||
var: "invalid_comma_separated | community.general.from_csv(strict=True)" | ||
register: _invalid_csv_strict_true | ||
ignore_errors: True | ||
|
||
- name: Test invalid csv input when strict=True is failed | ||
assert: | ||
that: | ||
- _invalid_csv_strict_true is failed | ||
- _invalid_csv_strict_true.msg is match('Unable to process file:.*') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
valid_comma_separated: | | ||
id,name,role | ||
1,foo,bar | ||
2,bar,baz | ||
valid_comma_separated_spaces: | | ||
id,name,role | ||
1, foo, bar | ||
2, bar, baz | ||
valid_comma_separated_no_headers: | | ||
1,foo,bar | ||
2,bar,baz | ||
valid_pipe_separated: | | ||
id|name|role | ||
1|foo|bar | ||
2|bar|baz | ||
invalid_comma_separated: | | ||
id,name,role | ||
1,foo,bar | ||
2,"b"ar",baz | ||
expected_result: | ||
- id: '1' | ||
name: foo | ||
role: bar | ||
- id: '2' | ||
name: bar | ||
role: baz |
Oops, something went wrong.