diff --git a/src/humanize/lists.py b/src/humanize/lists.py index 525f0e33..36e8ab73 100644 --- a/src/humanize/lists.py +++ b/src/humanize/lists.py @@ -4,15 +4,16 @@ TYPE_CHECKING = False if TYPE_CHECKING: + from collections.abc import Iterable from typing import Any __all__ = ["natural_list"] -def natural_list(items: list[Any]) -> str: +def natural_list(items: Iterable[Any]) -> str: """Natural list. - Convert a list of items into a human-readable string with commas and 'and'. + Convert an iterable of items into a human-readable string with commas and 'and'. Examples: >>> natural_list(["one", "two", "three"]) @@ -23,16 +24,17 @@ def natural_list(items: list[Any]) -> str: 'one' Args: - items (list): An iterable of items. + items (Iterable): An iterable of items. Returns: str: A string with commas and 'and' in the right places. """ - if not items: + item_list = [str(item) for item in items] + if not item_list: return "" - if len(items) == 1: - return str(items[0]) - elif len(items) == 2: - return f"{str(items[0])} and {str(items[1])}" + if len(item_list) == 1: + return item_list[0] + elif len(item_list) == 2: + return f"{item_list[0]} and {item_list[1]}" else: - return ", ".join([str(item) for item in items[:-1]]) + f" and {str(items[-1])}" + return ", ".join(item_list[:-1]) + f" and {item_list[-1]}" diff --git a/tests/test_lists.py b/tests/test_lists.py index cc514f32..9b3c1b77 100644 --- a/tests/test_lists.py +++ b/tests/test_lists.py @@ -1,5 +1,8 @@ from __future__ import annotations +from collections.abc import Iterable +from typing import Any + import pytest import humanize @@ -16,9 +19,13 @@ ([[""]], ""), ([[1, 2, 3]], "1, 2 and 3"), ([[1, "two"]], "1 and two"), + ([("one", "two", "three")], "one, two and three"), + ([("one", "two")], "one and two"), + ([("one",)], "one"), + ([{"one": 1, "two": 2}.keys()], "one and two"), + ([(x for x in ["one", "two", "three"])], "one, two and three"), + ([range(1, 4)], "1, 2 and 3"), ], ) -def test_natural_list( - test_args: list[str] | list[int] | list[str | int], expected: str -) -> None: +def test_natural_list(test_args: Iterable[Any], expected: str) -> None: assert humanize.natural_list(*test_args) == expected