1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00

Adding a new filter: to_ini, which allows conversion of a dictionary to an INI formatted string (#7744)

* Adding a new filter: to_ini, which allows conversion of a dictionary to an INI formatted string

* Adding to_ini maintainers into BOTMETA

* Correcting filter suffix

* Moving filter to correct path

* Adding error handling; Removing quotes from examples; Fixing RETURN documentation

* Removing the last newline char; Adding error handling for an empty dict

* Adding integration tests for to_ini

* Fixing F-String usage

* Fixing formatting

* Fixing whitespace

* Moving import statements below documentation; Adding a more generic Exception handling; Removing unused imports

* Removing not needed set_fact and replacing it with using vars:

* Replacing MutableMapping with Mapping
This commit is contained in:
Steffen Scheib 2023-12-28 08:32:57 +01:00 committed by GitHub
parent f79940c415
commit ec12422fae
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 173 additions and 0 deletions

2
.github/BOTMETA.yml vendored
View file

@ -158,6 +158,8 @@ files:
maintainers: resmo maintainers: resmo
$filters/to_hours.yml: $filters/to_hours.yml:
maintainers: resmo maintainers: resmo
$filters/to_ini.py:
maintainers: sscheib
$filters/to_milliseconds.yml: $filters/to_milliseconds.yml:
maintainers: resmo maintainers: resmo
$filters/to_minutes.yml: $filters/to_minutes.yml:

105
plugins/filter/to_ini.py Normal file
View file

@ -0,0 +1,105 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2023, Steffen Scheib <steffen@scheib.me>
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
from __future__ import absolute_import, division, print_function
DOCUMENTATION = r'''
name: to_ini
short_description: Converts a dictionary to the INI file format
version_added: 8.2.0
author: Steffen Scheib (@sscheib)
description:
- Converts a dictionary to the INI file format.
options:
_input:
description: The dictionary that should be converted to the INI format.
type: dictionary
required: true
'''
EXAMPLES = r'''
- name: Define a dictionary
ansible.builtin.set_fact:
my_dict:
section_name:
key_name: 'key value'
another_section:
connection: 'ssh'
- name: Write dictionary to INI file
ansible.builtin.copy:
dest: /tmp/test.ini
content: '{{ my_dict | community.general.to_ini }}'
# /tmp/test.ini will look like this:
# [section_name]
# key_name = key value
#
# [another_section]
# connection = ssh
'''
RETURN = r'''
_value:
description: A string formatted as INI file.
type: string
'''
__metaclass__ = type
from ansible.errors import AnsibleFilterError
from ansible.module_utils.common._collections_compat import Mapping
from ansible.module_utils.six.moves import StringIO
from ansible.module_utils.six.moves.configparser import ConfigParser
from ansible.module_utils.common.text.converters import to_native
class IniParser(ConfigParser):
''' Implements a configparser which sets the correct optionxform '''
def __init__(self):
super().__init__()
self.optionxform = str
def to_ini(obj):
''' Read the given dict and return an INI formatted string '''
if not isinstance(obj, Mapping):
raise AnsibleFilterError(f'to_ini requires a dict, got {type(obj)}')
ini_parser = IniParser()
try:
ini_parser.read_dict(obj)
except Exception as ex:
raise AnsibleFilterError('to_ini failed to parse given dict:'
f'{to_native(ex)}', orig_exc=ex)
# catching empty dicts
if obj == dict():
raise AnsibleFilterError('to_ini received an empty dict. '
'An empty dict cannot be converted.')
config = StringIO()
ini_parser.write(config)
# config.getvalue() returns two \n at the end
# with the below insanity, we remove the very last character of
# the resulting string
return ''.join(config.getvalue().rsplit(config.getvalue()[-1], 1))
class FilterModule(object):
''' Query filter '''
def filters(self):
return {
'to_ini': to_ini
}

View file

@ -0,0 +1,58 @@
---
# Copyright (c) 2023, Steffen Scheib <steffen@scheib.me>
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- name: >-
Write INI file that reflects using to_ini to {{ ini_test_file_filter }}
ansible.builtin.copy:
dest: '{{ ini_test_file_filter }}'
content: '{{ ini_test_dict | community.general.to_ini }}'
vars:
ini_test_dict:
section_name:
key_name: 'key value'
another_section:
connection: 'ssh'
- name: 'Write INI file manually to {{ ini_test_file }}'
ansible.builtin.copy:
dest: '{{ ini_test_file }}'
content: |
[section_name]
key_name = key value
[another_section]
connection = ssh
- name: 'Slurp the manually created test file: {{ ini_test_file }}'
ansible.builtin.slurp:
src: '{{ ini_test_file }}'
register: 'ini_file_content'
- name: 'Slurp the test file created with to_ini: {{ ini_test_file_filter }}'
ansible.builtin.slurp:
src: '{{ ini_test_file_filter }}'
register: 'ini_file_filter_content'
- name: >-
Ensure the manually created test file and the test file created with
to_ini are identical
ansible.builtin.assert:
that:
- 'ini_file_content.content | b64decode ==
ini_file_filter_content.content | b64decode'
- name: 'Try to convert an empty dictionary with to_ini'
ansible.builtin.debug:
msg: '{{ {} | community.general.to_ini }}'
register: 'ini_empty_dict'
ignore_errors: true
- name: 'Ensure the correct exception was raised'
ansible.builtin.assert:
that:
- "'to_ini received an empty dict. An empty dict cannot be converted.' in
ini_empty_dict.msg"
...

View file

@ -0,0 +1,8 @@
---
# Copyright (c) 2023, Steffen Scheib <steffen@scheib.me>
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
ini_test_file: '/tmp/test.ini'
ini_test_file_filter: '/tmp/test_filter.ini'
...