Source code for pint.delegates.formatter._to_register
"""
pint.delegates.formatter.base_formatter
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Common class and function for all formatters.
:copyright: 2022 by Pint Authors, see AUTHORS for more details.
:license: BSD, see LICENSE for more details.
"""
from __future__ import annotations
from collections.abc import Callable
from typing import TYPE_CHECKING, Any, Iterable
from ..._typing import Magnitude
from ...compat import Unpack, ndarray, np
from ...util import UnitsContainer
from ._compound_unit_helpers import BabelKwds, prepare_compount_unit
from ._format_helpers import join_mu, override_locale
from ._spec_helpers import REGISTERED_FORMATTERS, split_format
from .plain import BaseFormatter
if TYPE_CHECKING:
from ...facets.plain import MagnitudeT, PlainQuantity, PlainUnit
from ...registry import UnitRegistry
[docs]
def register_unit_format(name: str):
"""register a function as a new format for units
The registered function must have a signature of:
.. code:: python
def new_format(unit, registry, **options):
pass
Parameters
----------
name : str
The name of the new format (to be used in the format mini-language). A error is
raised if the new format would overwrite a existing format.
Examples
--------
.. code:: python
@pint.register_unit_format("custom")
def format_custom(unit, registry, **options):
result = "<formatted unit>" # do the formatting
return result
ureg = pint.UnitRegistry()
u = ureg.m / ureg.s ** 2
f"{u:custom}"
"""
# TODO: kwargs missing in typing
def wrapper(func: Callable[[PlainUnit, UnitRegistry], str]):
if name in REGISTERED_FORMATTERS:
raise ValueError(f"format {name!r} already exists") # or warn instead
class NewFormatter(BaseFormatter):
def format_magnitude(
self,
magnitude: Magnitude,
mspec: str = "",
**babel_kwds: Unpack[BabelKwds],
) -> str:
with override_locale(
mspec, babel_kwds.get("locale", None)
) as format_number:
if isinstance(magnitude, ndarray) and magnitude.ndim > 0:
# Use custom ndarray text formatting--need to handle scalars differently
# since they don't respond to printoptions
with np.printoptions(formatter={"float_kind": format_number}):
mstr = format(magnitude).replace("\n", "")
else:
mstr = format_number(magnitude)
return mstr
def format_unit(
self,
unit: PlainUnit | Iterable[tuple[str, Any]],
uspec: str = "",
**babel_kwds: Unpack[BabelKwds],
) -> str:
numerator, _denominator = prepare_compount_unit(
unit,
uspec,
**babel_kwds,
as_ratio=False,
registry=self._registry,
)
if self._registry is None:
units = UnitsContainer(numerator)
else:
units = self._registry.UnitsContainer(numerator)
return func(units, registry=self._registry)
def format_quantity(
self,
quantity: PlainQuantity[MagnitudeT],
qspec: str = "",
**babel_kwds: Unpack[BabelKwds],
) -> str:
registry = self._registry
if registry is None:
mspec, uspec = split_format(qspec, "", True)
else:
mspec, uspec = split_format(
qspec,
registry.formatter.default_format,
registry.separate_format_defaults,
)
joint_fstring = "{} {}"
return join_mu(
joint_fstring,
self.format_magnitude(quantity.magnitude, mspec, **babel_kwds),
self.format_unit(quantity.unit_items(), uspec, **babel_kwds),
)
REGISTERED_FORMATTERS[name] = NewFormatter()
return wrapper