From 3734f471c12784ef0deae77e8199ce7298c14f09 Mon Sep 17 00:00:00 2001 From: Alexei Znamensky <103110+russoz@users.noreply.github.com> Date: Sat, 11 Oct 2025 22:59:28 +1300 Subject: [PATCH] use f-strings (#10899) * use f-strings * add changelog frag * Apply suggestions from code review Co-authored-by: Felix Fontein --------- Co-authored-by: Felix Fontein --- changelogs/fragments/10899-use-f-strings.yml | 14 ++++++++++++++ plugins/connection/wsl.py | 10 +++------- plugins/filter/accumulate.py | 3 +-- plugins/filter/counter.py | 5 ++--- plugins/filter/crc32.py | 5 ++--- plugins/filter/groupby_as_dict.py | 6 +++--- plugins/filter/hashids.py | 4 +--- plugins/filter/json_query.py | 4 ++-- plugins/filter/lists.py | 16 ++++------------ plugins/filter/random_mac.py | 12 +++++------- plugins/filter/time.py | 14 +++++++------- plugins/filter/unicode_normalize.py | 4 ++-- plugins/lookup/passwordstore.py | 3 ++- plugins/plugin_utils/ansible_type.py | 4 ++-- 14 files changed, 50 insertions(+), 54 deletions(-) create mode 100644 changelogs/fragments/10899-use-f-strings.yml diff --git a/changelogs/fragments/10899-use-f-strings.yml b/changelogs/fragments/10899-use-f-strings.yml new file mode 100644 index 0000000000..9752e5ebf2 --- /dev/null +++ b/changelogs/fragments/10899-use-f-strings.yml @@ -0,0 +1,14 @@ +minor_changes: + - wsl connection plugin - use f-strings for string templating (https://github.com/ansible-collections/community.general/pull/10899). + - accumulate filter plugin - use f-strings for string templating (https://github.com/ansible-collections/community.general/pull/10899). + - counter filter plugin - use f-strings for string templating (https://github.com/ansible-collections/community.general/pull/10899). + - crc32 filter plugin - use f-strings for string templating (https://github.com/ansible-collections/community.general/pull/10899). + - groupby_as_dict filter plugin - use f-strings for string templating (https://github.com/ansible-collections/community.general/pull/10899). + - hashids filter plugin - use f-strings for string templating (https://github.com/ansible-collections/community.general/pull/10899). + - json_query filter plugin - use f-strings for string templating (https://github.com/ansible-collections/community.general/pull/10899). + - lists filter plugin - use f-strings for string templating (https://github.com/ansible-collections/community.general/pull/10899). + - random_mac filter plugin - use f-strings for string templating (https://github.com/ansible-collections/community.general/pull/10899). + - time filter plugin - use f-strings for string templating (https://github.com/ansible-collections/community.general/pull/10899). + - unicode_normalize filter plugin - use f-strings for string templating (https://github.com/ansible-collections/community.general/pull/10899). + - passwordstore lookup plugin - use f-strings for string templating (https://github.com/ansible-collections/community.general/pull/10899). + - ansible_type plugin_utils plugin - use f-strings for string templating (https://github.com/ansible-collections/community.general/pull/10899). diff --git a/plugins/connection/wsl.py b/plugins/connection/wsl.py index 7604ca52cc..9e7bb26eeb 100644 --- a/plugins/connection/wsl.py +++ b/plugins/connection/wsl.py @@ -649,7 +649,7 @@ class Connection(ConnectionBase): if password_prompt: if self.become: become_pass = self.become.get_option('become_pass') - chan.sendall(to_bytes(become_pass + '\n', errors='surrogate_or_strict')) + chan.sendall(to_bytes(f"{become_pass}\n", errors='surrogate_or_strict')) else: raise AnsibleError('A password is required but none was supplied') else: @@ -687,9 +687,7 @@ class Connection(ConnectionBase): with open(in_path, 'rb') as f: data = f.read() returncode, stdout, stderr = self.exec_command( - ' '.join([ - self._shell.executable, '-c', - self._shell.quote(f'cat > {out_path}')]), + f"{self._shell.executable} -c {self._shell.quote(f'cat > {out_path}')}", in_data=data, sudoable=False) if returncode != 0: @@ -708,9 +706,7 @@ class Connection(ConnectionBase): display.vvv(f'FETCH {in_path} TO {out_path}', host=self.get_option('remote_addr')) try: returncode, stdout, stderr = self.exec_command( - ' '.join([ - self._shell.executable, '-c', - self._shell.quote(f'cat {in_path}')]), + f"{self._shell.executable} -c {self._shell.quote(f'cat {in_path}')}", sudoable=False) if returncode != 0: if 'cat: not found' in stderr.decode('utf-8'): diff --git a/plugins/filter/accumulate.py b/plugins/filter/accumulate.py index c48afa0467..da784ab12b 100644 --- a/plugins/filter/accumulate.py +++ b/plugins/filter/accumulate.py @@ -49,8 +49,7 @@ from ansible.errors import AnsibleFilterError def list_accumulate(sequence): if not isinstance(sequence, Sequence): - raise AnsibleFilterError('Invalid value type (%s) for accumulate (%r)' % - (type(sequence), sequence)) + raise AnsibleFilterError(f'Invalid value type ({type(sequence)}) for accumulate ({sequence!r})') return accumulate(sequence) diff --git a/plugins/filter/counter.py b/plugins/filter/counter.py index acb04ec76b..f89bfd6d1a 100644 --- a/plugins/filter/counter.py +++ b/plugins/filter/counter.py @@ -42,14 +42,13 @@ from collections import Counter def counter(sequence): ''' Count elements in a sequence. Returns dict with count result. ''' if not isinstance(sequence, Sequence): - raise AnsibleFilterError('Argument for community.general.counter must be a sequence (string or list). %s is %s' % - (sequence, type(sequence))) + raise AnsibleFilterError(f'Argument for community.general.counter must be a sequence (string or list). {sequence} is {type(sequence)}') try: result = dict(Counter(sequence)) except TypeError as e: raise AnsibleFilterError( - "community.general.counter needs a sequence with hashable elements (int, float or str) - %s" % (e) + f"community.general.counter needs a sequence with hashable elements (int, float or str) - {e}" ) return result diff --git a/plugins/filter/crc32.py b/plugins/filter/crc32.py index 444524c4e9..11a6e77495 100644 --- a/plugins/filter/crc32.py +++ b/plugins/filter/crc32.py @@ -45,14 +45,13 @@ _value: def crc32s(value): if not is_string(value): - raise AnsibleFilterError('Invalid value type (%s) for crc32 (%r)' % - (type(value), value)) + raise AnsibleFilterError(f'Invalid value type ({type(value)}) for crc32 ({value!r})') if not HAS_ZLIB: raise AnsibleFilterError('Failed to import zlib module') data = to_bytes(value, errors='surrogate_or_strict') - return "{0:x}".format(crc32(data) & 0xffffffff) + return f"{crc32(data) & 0xffffffff:x}" class FilterModule: diff --git a/plugins/filter/groupby_as_dict.py b/plugins/filter/groupby_as_dict.py index cd8ccc4148..766d365575 100644 --- a/plugins/filter/groupby_as_dict.py +++ b/plugins/filter/groupby_as_dict.py @@ -70,12 +70,12 @@ def groupby_as_dict(sequence, attribute): result = dict() for list_index, element in enumerate(sequence): if not isinstance(element, Mapping): - raise AnsibleFilterError('Sequence element #{0} is not a mapping'.format(list_index)) + raise AnsibleFilterError(f'Sequence element #{list_index} is not a mapping') if attribute not in element: - raise AnsibleFilterError('Attribute not contained in element #{0} of sequence'.format(list_index)) + raise AnsibleFilterError(f'Attribute not contained in element #{list_index} of sequence') result_index = element[attribute] if result_index in result: - raise AnsibleFilterError('Multiple sequence entries have attribute value {0!r}'.format(result_index)) + raise AnsibleFilterError(f'Multiple sequence entries have attribute value {result_index!r}') result[result_index] = element return result diff --git a/plugins/filter/hashids.py b/plugins/filter/hashids.py index 6ae83aed85..c58ae4d70b 100644 --- a/plugins/filter/hashids.py +++ b/plugins/filter/hashids.py @@ -66,9 +66,7 @@ def hashids_encode(nums, salt=None, alphabet=None, min_length=None): try: hashid = hashids.encode(*nums) except TypeError as e: - raise AnsibleTypeError( - "Data to encode must by a tuple or list of ints: %s" % to_native(e) - ) + raise AnsibleTypeError(f"Data to encode must by a tuple or list of ints: {e}") return hashid diff --git a/plugins/filter/json_query.py b/plugins/filter/json_query.py index fb9eedc155..e040a4aca2 100644 --- a/plugins/filter/json_query.py +++ b/plugins/filter/json_query.py @@ -137,10 +137,10 @@ def json_query(data, expr): try: return jmespath.search(expr, data) except jmespath.exceptions.JMESPathError as e: - raise AnsibleFilterError('JMESPathError in json_query filter plugin:\n%s' % e) + raise AnsibleFilterError(f'JMESPathError in json_query filter plugin:\n{e}') except Exception as e: # For older jmespath, we can get ValueError and TypeError without much info. - raise AnsibleFilterError('Error in jmespath.search in json_query filter plugin:\n%s' % e) + raise AnsibleFilterError(f'Error in jmespath.search in json_query filter plugin:\n{e}') class FilterModule(object): diff --git a/plugins/filter/lists.py b/plugins/filter/lists.py index 0faa6fcea6..0bae08f24c 100644 --- a/plugins/filter/lists.py +++ b/plugins/filter/lists.py @@ -50,9 +50,7 @@ def lists_union(*args, **kwargs): if kwargs: # Some unused kwargs remain raise AnsibleFilterError( - "lists_union() got unexpected keywords arguments: {0}".format( - ", ".join(kwargs.keys()) - ) + f"lists_union() got unexpected keywords arguments: {', '.join(kwargs.keys())}" ) if flatten: @@ -81,9 +79,7 @@ def lists_intersect(*args, **kwargs): if kwargs: # Some unused kwargs remain raise AnsibleFilterError( - "lists_intersect() got unexpected keywords arguments: {0}".format( - ", ".join(kwargs.keys()) - ) + f"lists_intersect() got unexpected keywords arguments: {', '.join(kwargs.keys())}" ) if flatten: @@ -121,9 +117,7 @@ def lists_difference(*args, **kwargs): if kwargs: # Some unused kwargs remain raise AnsibleFilterError( - "lists_difference() got unexpected keywords arguments: {0}".format( - ", ".join(kwargs.keys()) - ) + f"lists_difference() got unexpected keywords arguments: {', '.join(kwargs.keys())}" ) if flatten: @@ -161,9 +155,7 @@ def lists_symmetric_difference(*args, **kwargs): if kwargs: # Some unused kwargs remain raise AnsibleFilterError( - "lists_difference() got unexpected keywords arguments: {0}".format( - ", ".join(kwargs.keys()) - ) + f"lists_difference() got unexpected keywords arguments: {', '.join(kwargs.keys())}" ) if flatten: diff --git a/plugins/filter/random_mac.py b/plugins/filter/random_mac.py index fe8eb51b28..e5e6201f1c 100644 --- a/plugins/filter/random_mac.py +++ b/plugins/filter/random_mac.py @@ -51,15 +51,13 @@ def random_mac(value, seed=None): to get a complete 6 bytes MAC address ''' if not isinstance(value, str): - raise AnsibleFilterError('Invalid value type (%s) for random_mac (%s)' % - (type(value), value)) + raise AnsibleFilterError(f'Invalid value type ({type(value)}) for random_mac ({value})') value = value.lower() mac_items = value.split(':') if len(mac_items) > 5: - raise AnsibleFilterError('Invalid value (%s) for random_mac: 5 colon(:) separated' - ' items max' % value) + raise AnsibleFilterError(f'Invalid value ({value}) for random_mac: 5 colon(:) separated items max') err = "" for mac in mac_items: @@ -67,11 +65,11 @@ def random_mac(value, seed=None): err += ",empty item" continue if not re.match('[a-f0-9]{2}', mac): - err += ",%s not hexa byte" % mac + err += f",{mac} not hexa byte" err = err.strip(',') if err: - raise AnsibleFilterError('Invalid value (%s) for random_mac: %s' % (value, err)) + raise AnsibleFilterError(f'Invalid value ({value}) for random_mac: {err}') if seed is None: r = SystemRandom() @@ -81,7 +79,7 @@ def random_mac(value, seed=None): v = r.randint(68719476736, 1099511627775) # Select first n chars to complement input prefix remain = 2 * (6 - len(mac_items)) - rnd = ('%x' % v)[:remain] + rnd = f'{v:x}'[:remain] return value + re.sub(r'(..)', r':\1', rnd) diff --git a/plugins/filter/time.py b/plugins/filter/time.py index dcd598cd3b..e48e24216a 100644 --- a/plugins/filter/time.py +++ b/plugins/filter/time.py @@ -55,10 +55,10 @@ def to_time_unit(human_time, unit='ms', **kwargs): unit = unit_to_short_form.get(unit.rstrip('s'), unit) if unit not in unit_factors: - raise AnsibleFilterError("to_time_unit() can not convert to the following unit: %s. " - "Available units (singular or plural): %s. " - "Available short units: %s" - % (unit, ', '.join(unit_to_short_form.keys()), ', '.join(unit_factors.keys()))) + raise AnsibleFilterError(( + f"to_time_unit() can not convert to the following unit: {unit}. Available units (singular or plural):" + f"{', '.join(unit_to_short_form.keys())}. Available short units: {', '.join(unit_factors.keys())}" + )) if 'year' in kwargs: unit_factors['y'] = unit_factors['y'][:-1] + [kwargs.pop('year')] @@ -66,14 +66,14 @@ def to_time_unit(human_time, unit='ms', **kwargs): unit_factors['mo'] = unit_factors['mo'][:-1] + [kwargs.pop('month')] if kwargs: - raise AnsibleFilterError('to_time_unit() got unknown keyword arguments: %s' % ', '.join(kwargs.keys())) + raise AnsibleFilterError(f"to_time_unit() got unknown keyword arguments: {', '.join(kwargs.keys())}") result = 0 for h_time_string in human_time.split(): res = re.match(r'(-?\d+)(\w+)', h_time_string) if not res: raise AnsibleFilterError( - "to_time_unit() can not interpret following string: %s" % human_time) + f"to_time_unit() can not interpret following string: {human_time}") h_time_int = int(res.group(1)) h_time_unit = res.group(2) @@ -81,7 +81,7 @@ def to_time_unit(human_time, unit='ms', **kwargs): h_time_unit = unit_to_short_form.get(h_time_unit.rstrip('s'), h_time_unit) if h_time_unit not in unit_factors: raise AnsibleFilterError( - "to_time_unit() can not interpret following string: %s" % human_time) + f"to_time_unit() can not interpret following string: {human_time}") time_in_milliseconds = h_time_int * multiply(unit_factors[h_time_unit]) result += time_in_milliseconds diff --git a/plugins/filter/unicode_normalize.py b/plugins/filter/unicode_normalize.py index ef3ba194dd..f1fe18402b 100644 --- a/plugins/filter/unicode_normalize.py +++ b/plugins/filter/unicode_normalize.py @@ -68,10 +68,10 @@ def unicode_normalize(data, form='NFC'): """ if not isinstance(data, str): - raise AnsibleTypeError("%s is not a valid input type" % type(data)) + raise AnsibleTypeError(f"{type(data)} is not a valid input type") if form not in ('NFC', 'NFD', 'NFKC', 'NFKD'): - raise AnsibleFilterError("%s is not a valid form" % form) + raise AnsibleFilterError(f"{form!r} is not a valid form") return normalize(form, data) diff --git a/plugins/lookup/passwordstore.py b/plugins/lookup/passwordstore.py index ec4348221c..31305d81bb 100644 --- a/plugins/lookup/passwordstore.py +++ b/plugins/lookup/passwordstore.py @@ -459,7 +459,8 @@ class LookupModule(LookupBase): if self.paramvals['preserve'] or self.paramvals['timestamp']: msg += '\n' if self.paramvals['preserve'] and self.passoutput[1:]: - msg += '\n'.join(self.passoutput[1:]) + '\n' + msg += '\n'.join(self.passoutput[1:]) + msg += '\n' if self.paramvals['timestamp'] and self.paramvals['backup']: msg += f"lookup_pass: old password was {self.password} (Updated on {datetime})\n" diff --git a/plugins/plugin_utils/ansible_type.py b/plugins/plugin_utils/ansible_type.py index 3de3488e80..d9481b4c9a 100644 --- a/plugins/plugin_utils/ansible_type.py +++ b/plugins/plugin_utils/ansible_type.py @@ -48,13 +48,13 @@ def _ansible_type(data, alias, *, use_native_type: bool = False): if data_type == 'list' and len(data) > 0: items = [_atype(i, alias, use_native_type=use_native_type) for i in data] items_type = '|'.join(sorted(set(items))) - return ''.join((data_type, '[', items_type, ']')) + return f"{data_type}[{items_type}]" if data_type == 'dict' and len(data) > 0: keys = [_atype(i, alias, use_native_type=use_native_type) for i in data.keys()] vals = [_atype(i, alias, use_native_type=use_native_type) for i in data.values()] keys_type = '|'.join(sorted(set(keys))) vals_type = '|'.join(sorted(set(vals))) - return ''.join((data_type, '[', keys_type, ', ', vals_type, ']')) + return f"{data_type}[{keys_type}, {vals_type}]" return data_type