xref: /aosp_15_r20/external/pigweed/pw_cli/py/pw_cli/plural.py (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1# Copyright 2024 The Pigweed Authors
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may not
4# use this file except in compliance with the License. You may obtain a copy of
5# the License at
6#
7#     https://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations under
13# the License.
14"""Utilities for handling singular/plural forms in logs and tooling."""
15
16
17def plural(
18    items_or_count,
19    singular: str,
20    count_format='',
21    these: bool = False,
22    number: bool = True,
23    are: bool = False,
24    exist: bool = False,
25) -> str:
26    """Returns the singular or plural form of a word based on a count.
27
28    Args:
29        items_or_count: Number of items or a collection of items
30        singular: Singular form of the name of the item
31        count_format: .format()-style specification for items_or_count
32        these: Prefix the string with "this" or "these", depending on number
33        number: Include the number in the return string (e.g., "3 things" vs.
34            "things")
35        are: Suffix the string with "is" or "are", depending on number
36        exist: Suffix the string with "exists" or "exist", depending on number
37    """
38
39    try:
40        count = len(items_or_count)
41    except TypeError:
42        count = items_or_count
43
44    prefix = ('this ' if count == 1 else 'these ') if these else ''
45    num = f'{count:{count_format}} ' if number else ''
46
47    suffix = ''
48    if are and exist:
49        raise ValueError(f'cannot combine are ({are}) and exist ({exist})')
50    if are:
51        suffix = ' is' if count == 1 else ' are'
52    if exist:
53        suffix = ' exists' if count == 1 else ' exist'
54
55    if singular.endswith('y'):
56        result = f'{singular[:-1]}{"y" if count == 1 else "ies"}'
57    elif singular.endswith('s'):
58        result = f'{singular}{"" if count == 1 else "es"}'
59    else:
60        result = f'{singular}{"" if count == 1 else "s"}'
61
62    return f'{prefix}{num}{result}{suffix}'
63