diff --git a/src/humanize/lists.py b/src/humanize/lists.py index 525f0e33..9b56dee1 100644 --- a/src/humanize/lists.py +++ b/src/humanize/lists.py @@ -4,35 +4,41 @@ 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], conjunction: str = "and") -> 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 + a conjunction. Examples: >>> natural_list(["one", "two", "three"]) 'one, two and three' >>> natural_list(["one", "two"]) 'one and two' + >>> natural_list(["one", "two", "three"], conjunction="or") + 'one, two or three' >>> natural_list(["one"]) 'one' Args: - items (list): An iterable of items. + items (Iterable): An iterable of items. + conjunction (str): The word or phrase joining the final two items. Returns: - str: A string with commas and 'and' in the right places. + str: A string with commas and the conjunction 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]} {conjunction} {item_list[1]}" else: - return ", ".join([str(item) for item in items[:-1]]) + f" and {str(items[-1])}" + return ", ".join(item_list[:-1]) + f" {conjunction} {item_list[-1]}" diff --git a/tests/test_lists.py b/tests/test_lists.py index cc514f32..e1754c81 100644 --- a/tests/test_lists.py +++ b/tests/test_lists.py @@ -22,3 +22,19 @@ def test_natural_list( test_args: list[str] | list[int] | list[str | int], expected: str ) -> None: assert humanize.natural_list(*test_args) == expected + + +@pytest.mark.parametrize( + "items, conjunction, expected", + [ + (["one", "two"], "or", "one or two"), + (["one", "two", "three"], "or", "one, two or three"), + (["one", "two", "three"], "and also", "one, two and also three"), + ([], "or", ""), + (["one"], "or", "one"), + ], +) +def test_natural_list_conjunction( + items: list[str], conjunction: str, expected: str +) -> None: + assert humanize.natural_list(items, conjunction=conjunction) == expected