"""Text utilities."""
from quantiphy import Quantity as _Quantity
[docs]def ngettext(n, fsingle, fplural, sub=True):
"""Get the singular or plural form of the specified messages based on n.
Simplified version of the Python standard library function :func:`gettext.ngettext`.
Parameters
----------
n : int
The number to use to decide which form to return.
fsingle, fplural : str
Single and plural templates.
sub : bool, optional
Substitute `n` into the templates. Defaults to `True`.
Examples
--------
>>> ngettext(1, "{n} item", "{n} items")
'1 item'
>>> ngettext(5, "{n} item", "{n} items")
'5 items'
The template doesn't have to contain `{n}`:
>>> ngettext(5, "item", "items")
'items'
Setting `sub=False` turns off substitution:
>>> ngettext(5, "{n} item", "{n} items", sub=False)
'{n} items'
"""
if n == 1:
return fsingle.format(n=n) if sub else fsingle
return fplural.format(n=n) if sub else fplural
[docs]def option_list(sequence, final_sep="or", quotechar=None):
"""Build a list from `sequence` with commas and a final "or".
As in Python's error messages (e.g. "'func' missing 3 requied positional arguments:
'a', 'b', and 'c'"), this function adds an Oxford comma for sequences of length > 2.
Parameters
----------
sequence : sequence
The options to create a list with.
final_sep : str, optional
The final separator when `sequence` has more than one item. Defaults to `or`.
quotechar : str, optional
Quote the items in `sequence` with this character. Defaults to no quotes.
"""
sequence = list(sequence)
if quotechar:
sequence = [f"{quotechar}{item}{quotechar}" for item in sequence]
if len(sequence) <= 1:
return "".join(sequence)
elif len(sequence) == 2:
return f"{sequence[0]} {final_sep} {sequence[1]}"
sequence[-1] = f"{final_sep} {sequence[-1]}"
return ", ".join(sequence)
[docs]def add_linenos(linenos, lines):
"""Add line numbers to the start of lines.
Parameters
----------
linenos : sequence of int
The line numbers, in the same order as `lines`.
lines : sequence of str
The lines.
Returns
-------
sequence of str
The lines with prepended line numbers.
"""
# Use as many columns as required to fit the largest line number.
wlinenocol = max([len(str(lineno)) for lineno in linenos])
return [f"{lineno:>{wlinenocol}}: {line}" for lineno, line in zip(linenos, lines)]
[docs]def stringify(item):
"""Recursively stringify `item`.
This is useful for when it doesn't make sense or isn't possible to override the
__repr__ method of an object to get a compact string representation.
"""
if isinstance(item, (list, tuple)):
return f"[{', '.join(stringify(i) for i in item)}]"
return str(item)
[docs]def stringify_graph_gml(graph):
"""Convert the specified NetworkX graph to string representation using GML
markup."""
from io import BytesIO
import networkx as nx
graphbytes = BytesIO()
nx.write_gml(graph, graphbytes, stringify)
graphbytes.seek(0)
return graphbytes.read().decode("utf-8")
[docs]def scale_si(number, units=None):
"""Convert `number` to an SI-scaled string representation, with optional unit.
Examples
--------
>>> scale_si(123.45e-6)
'123.45u'
>>> scale_si(370e-6, units="m")
'370 um'
"""
return str(_Quantity(number, units=units))