Skip to content

Commit 5821f19

Browse files
committed
fix(lists): support general iterables and update typing in natural_list
1 parent ce4147b commit 5821f19

2 files changed

Lines changed: 21 additions & 10 deletions

File tree

src/humanize/lists.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,16 @@
44

55
TYPE_CHECKING = False
66
if TYPE_CHECKING:
7+
from collections.abc import Iterable
78
from typing import Any
89

910
__all__ = ["natural_list"]
1011

1112

12-
def natural_list(items: list[Any]) -> str:
13+
def natural_list(items: Iterable[Any]) -> str:
1314
"""Natural list.
1415
15-
Convert a list of items into a human-readable string with commas and 'and'.
16+
Convert an iterable of items into a human-readable string with commas and 'and'.
1617
1718
Examples:
1819
>>> natural_list(["one", "two", "three"])
@@ -23,16 +24,17 @@ def natural_list(items: list[Any]) -> str:
2324
'one'
2425
2526
Args:
26-
items (list): An iterable of items.
27+
items (Iterable): An iterable of items.
2728
2829
Returns:
2930
str: A string with commas and 'and' in the right places.
3031
"""
31-
if not items:
32+
item_list = [str(item) for item in items]
33+
if not item_list:
3234
return ""
33-
if len(items) == 1:
34-
return str(items[0])
35-
elif len(items) == 2:
36-
return f"{str(items[0])} and {str(items[1])}"
35+
if len(item_list) == 1:
36+
return item_list[0]
37+
elif len(item_list) == 2:
38+
return f"{item_list[0]} and {item_list[1]}"
3739
else:
38-
return ", ".join([str(item) for item in items[:-1]]) + f" and {str(items[-1])}"
40+
return ", ".join(item_list[:-1]) + f" and {item_list[-1]}"

tests/test_lists.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
from __future__ import annotations
22

3+
from collections.abc import Iterable
4+
from typing import Any
5+
36
import pytest
47

58
import humanize
@@ -16,9 +19,15 @@
1619
([[""]], ""),
1720
([[1, 2, 3]], "1, 2 and 3"),
1821
([[1, "two"]], "1 and two"),
22+
([("one", "two", "three")], "one, two and three"),
23+
([("one", "two")], "one and two"),
24+
([("one",)], "one"),
25+
([{"one": 1, "two": 2}.keys()], "one and two"),
26+
([(x for x in ["one", "two", "three"])], "one, two and three"),
27+
([range(1, 4)], "1, 2 and 3"),
1928
],
2029
)
2130
def test_natural_list(
22-
test_args: list[str] | list[int] | list[str | int], expected: str
31+
test_args: Iterable[Any], expected: str
2332
) -> None:
2433
assert humanize.natural_list(*test_args) == expected

0 commit comments

Comments
 (0)