123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113 |
- """ FlexMeasures way of handling inflection """
- from __future__ import annotations
- import re
- from typing import Any
- import inflect
- import inflection
- p = inflect.engine()
- # Give the inflection module some help for our domain
- inflection.UNCOUNTABLES.add("solar")
- inflection.UNCOUNTABLES.add("wind")
- inflection.UNCOUNTABLES.add("evse")
- ACRONYMS = ["EVSE"]
- def capitalize(x: str, lower_case_remainder: bool = False) -> str:
- """Capitalize string with control over whether to lower case the remainder."""
- if lower_case_remainder:
- return x.capitalize()
- return x[0].upper() + x[1:]
- def humanize(word):
- return inflection.humanize(word)
- def parameterize(word):
- """Parameterize the word, so it can be used as a Python or JavaScript variable name.
- For example:
- >>> parameterize("Acme® EV-Charger™")
- 'acme_ev_chargertm'
- """
- return inflection.parameterize(word).replace("-", "_")
- def pluralize(word, count: str | int | None = None):
- if word.lower().split()[-1] in inflection.UNCOUNTABLES:
- return word
- return p.plural(word, count)
- def titleize(word):
- """Acronym exceptions are not yet supported by the inflection package,
- even though Ruby on Rails, of which the package is a port, does.
- In most cases it's probably better to use our capitalize function instead of titleize,
- because it has less unintended side effects. For example:
- >>> word = "two PV panels"
- >>> titleize(word)
- 'Two Pv Panels'
- >>> capitalize(word)
- 'Two PV panels'
- """
- word = inflection.titleize(word)
- for ac in ACRONYMS:
- word = re.sub(inflection.titleize(ac), ac, word)
- return word
- def join_words_into_a_list(words: list[str]) -> str:
- return p.join(words, final_sep="")
- def atoi(text):
- """Utility method for the `natural_keys` method."""
- return int(text) if text.isdigit() else text
- def natural_keys(text: str):
- """Support for human sorting.
- `alist.sort(key=natural_keys)` sorts in human order.
- https://stackoverflow.com/a/5967539/13775459
- """
- return [atoi(c) for c in re.split(r"(\d+)", text)]
- def human_sorted(alist: list, attr: Any | None = None, reverse: bool = False):
- """Human sort a list (for example, a list of strings or dictionaries).
- :param alist: List to be sorted.
- :param attr: Optionally, pass a dictionary key or attribute name to sort by
- :param reverse: If True, sorts descending.
- Example:
- >>> alist = ["PV 10", "CP1", "PV 2", "PV 1", "CP 2"]
- >>> sorted(alist)
- ['CP 2', 'CP1', 'PV 1', 'PV 10', 'PV 2']
- >>> human_sorted(alist)
- ['CP1', 'CP 2', 'PV 1', 'PV 2', 'PV 10']
- """
- if attr is None:
- # List of strings, to be sorted
- sorted_list = sorted(alist, key=lambda k: natural_keys(str(k)), reverse=reverse)
- else:
- try:
- # List of dictionaries, to be sorted by key
- sorted_list = sorted(
- alist, key=lambda k: natural_keys(k[attr]), reverse=reverse
- )
- except TypeError:
- # List of objects, to be sorted by attribute
- sorted_list = sorted(
- alist,
- key=lambda k: natural_keys(str(getattr(k, str(attr)))),
- reverse=reverse,
- )
- return sorted_list
|