Merge pull request #2941 from InspectorCaracal/iter-to-str

Fix and catch edge cases in `iter_to_str`
This commit is contained in:
Griatch 2022-10-19 22:37:24 +02:00 committed by GitHub
commit f2f0ec3c55
2 changed files with 19 additions and 7 deletions

View file

@ -66,8 +66,12 @@ class TestListToString(TestCase):
[1,2,3] -> '1, 2, 3'
with sep==';' and endsep==';':
[1,2,3] -> '1; 2; 3'
with sep=='or':
[1,2,3] -> '1 or 2, and 3'
with endsep=='and':
[1,2,3] -> '1, 2 and 3'
with endsep=='; and':
[1,2,3] -> '1, 2; and 3'
with endsep=='':
[1,2,3] -> '1, 2 3'
with addquote and endsep="and"
@ -80,6 +84,8 @@ class TestListToString(TestCase):
self.assertEqual("1, 2 and 3", utils.list_to_string([1, 2, 3], endsep="and"))
self.assertEqual("1, 2 3", utils.list_to_string([1, 2, 3], endsep=""))
self.assertEqual("1; 2; 3", utils.list_to_string([1, 2, 3], sep=";", endsep=";"))
self.assertEqual("1 or 2, and 3", utils.list_to_string([1, 2, 3], sep="or"))
self.assertEqual("1, 2; and 3", utils.list_to_string([1, 2, 3], endsep="; and"))
self.assertEqual(
'"1", "2", "3"', utils.list_to_string([1, 2, 3], endsep=",", addquote=True)
)

View file

@ -25,6 +25,7 @@ from collections import OrderedDict, defaultdict
from inspect import getmembers, getmodule, getmro, ismodule, trace
from os.path import join as osjoin
from unicodedata import east_asian_width
from string import punctuation
from django.apps import apps
from django.conf import settings
@ -403,18 +404,23 @@ def iter_to_str(iterable, sep=",", endsep=", and", addquote=False):
if not iterable:
return ""
len_iter = len(iterable)
if addquote:
iterable = tuple(f'"{val}"' for val in iterable)
else:
iterable = tuple(str(val) for val in iterable)
if endsep.startswith(sep):
# oxford comma alternative
endsep = endsep[1:] if len_iter < 3 else endsep
elif endsep:
# normal space-separated end separator
endsep = " " + str(endsep).strip()
if endsep:
if endsep.startswith(sep):
# oxford comma alternative
endsep = endsep[1:] if len_iter < 3 else endsep
elif endsep[0] not in punctuation:
# add a leading space if endsep is a word
endsep = " " + str(endsep).strip()
# also add a leading space if separator is a word
if sep not in punctuation:
sep = " "+sep
if len_iter == 1:
return str(iterable[0])