Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support 'oxford comma' format and non-string types in listing #690

Merged
merged 8 commits into from
Jan 17, 2025
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[report]
exclude_lines =
pragma: no cover
if TYPE_CHECKING:
20 changes: 16 additions & 4 deletions src/human_readable/lists.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,20 @@

from __future__ import annotations

from typing import TYPE_CHECKING


if TYPE_CHECKING:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it is much simpler to just remove this if statement and always import this. It is the standard approach.

from collections.abc import Sequence
from typing import Any


__all__ = ["listing"]


def listing(items: list[str], separator: str, conjunction: str = "") -> str:
def listing(
items: Sequence[Any], separator: Any, conjunction: Any = None, oxford: bool = False
) -> str:
"""Return human readable list separated by separator.

Optional argument is conjuntion that substitutes the last separator.
Expand All @@ -15,6 +24,7 @@ def listing(items: list[str], separator: str, conjunction: str = "") -> str:
items: list of items.
separator: separator of items.
conjunction: word/string as last separator. Defaults to None.
oxford: apply separators in the same manner as an oxford comma

Returns:
str: list in natural language.
Expand All @@ -23,11 +33,13 @@ def listing(items: list[str], separator: str, conjunction: str = "") -> str:
if len_items == 0:
return ""
if len_items == 1:
return items[0]
phrase = items[0]
if conjunction:
return str(items[0])
phrase = str(items[0])
if conjunction is not None:
for i in range(1, len_items - 1):
phrase += f"{separator} {items[i]}"
if oxford and len_items > 2:
phrase += str(separator)
phrase += f" {conjunction} {items[len_items - 1]}"
else:
for i in range(1, len_items):
Expand Down
19 changes: 19 additions & 0 deletions tests/unit/test_lists.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,22 @@ def test_listing_with_conjunction(
) -> None:
"""Listing with separator and conjunction."""
assert lists.listing(*params) == expected


@pytest.mark.parametrize(
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would also be great to explain this in our examples documentation.

"params, expected",
[
(([], ";", "or"), ""), # empty list
((["jorbas"], ";", "or"), "jorbas"), # one element
((["jorbas", "maria"], ";", "or"), "jorbas or maria"), # two elements
(
(["jorbas", "maria", "gustavo"], ";", "or"),
"jorbas; maria; or gustavo",
), # three elements
],
)
def test_listing_with_conjunction_oxford(
params: tuple[list[str], str, str], expected: str
) -> None:
"""Listing with separator and conjunction."""
assert lists.listing(*params, oxford=True) == expected
Loading