Source code for fairdm.contrib.contributors.profiles

"""Pure helpers behind the person and organization overview pages.

Nothing here touches the database or a request, so each function can be tested with plain values.
"""

from collections.abc import Callable, Iterable, Mapping, Sequence
from typing import Any
from urllib.parse import urlparse

from django.conf.locale import LANG_INFO
from django.utils.translation import gettext






[docs] def language_names(codes: Iterable[str] | None) -> list[str]: """Name each ISO 639-1 code in the active language. Args: codes: The language codes. Returns: One name per code, in the order given. A code Django does not know is kept as written. """ names = [] for code in codes or []: info = LANG_INFO.get(code) names.append(gettext(info["name"]) if info and "name" in info else code) return names
[docs] def ranked_shares(counts: Mapping[str, int]) -> list[dict[str, Any]]: """Rank counts, largest first, each with its share of the largest. Args: counts: A count for each label. Returns: One ``{"label", "count", "percent"}`` entry per label, where the largest count is 100. """ if not counts: return [] largest = max(counts.values()) ranked = sorted(counts.items(), key=lambda item: item[1], reverse=True) return [ {"label": label, "count": count, "percent": round(100 * count / largest)} for label, count in ranked ]
[docs] def fill_slots( items: Sequence[Any], slots: int, reserve: bool = False ) -> dict[str, Any]: """Fit a list into a fixed number of slots. Args: items: Everything there is to show, in order. slots: How many slots there are. reserve: Keep the last slot for a "+n more" entry when the items do not all fit, so the list never takes more than ``slots`` places. Returns: ``shown`` (the items that fit), ``more`` (how many do not) and ``total``. """ shown = items if len(items) > slots: shown = items[: slots - 1] if reserve else items[:slots] return {"shown": list(shown), "more": len(items) - len(shown), "total": len(items)}
[docs] def active_then_recent( items: Iterable[Any], modified: Callable[[Any], Any], active: Callable[[Any], bool] | None = None, ) -> list[Any]: """Order items with the active ones first, each group most recently updated first. Args: items: The items to order. modified: Returns when an item was last updated. active: Says whether an item is active, or None when the items have no such state. Returns: The items in order. """ ordered = sorted(items, key=modified, reverse=True) if active is not None: ordered.sort(key=lambda item: not active(item)) return ordered
[docs] def checklist(items: Sequence[Mapping[str, Any]]) -> dict[str, Any]: """Sum up a checklist. Args: items: The checklist's items, each with a ``done`` flag. Returns: The ``items``, how many are ``done``, the ``total``, and whether all of them are (``ready``). """ done = sum(1 for item in items if item["done"]) return { "items": list(items), "done": done, "total": len(items), "ready": done == len(items), }