Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions pint/formatting.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ def format_pretty(unit: UnitsContainer, registry: UnitRegistry, **options) -> st
power_fmt="{}{}",
parentheses_fmt="({})",
exp_call=_pretty_fmt_exponent,
registry=registry,
**options,
)

Expand Down Expand Up @@ -228,6 +229,7 @@ def format_latex(unit: UnitsContainer, registry: UnitRegistry, **options) -> str
division_fmt=r"\frac[{}][{}]",
power_fmt="{}^[{}]",
parentheses_fmt=r"\left({}\right)",
registry=registry,
**options,
)
return formatted.replace("[", "{").replace("]", "}")
Expand Down Expand Up @@ -259,6 +261,7 @@ def format_html(unit: UnitsContainer, registry: UnitRegistry, **options) -> str:
division_fmt=r"{}/{}",
power_fmt=r"{}<sup>{}</sup>",
parentheses_fmt=r"({})",
registry=registry,
**options,
)

Expand All @@ -273,6 +276,7 @@ def format_default(unit: UnitsContainer, registry: UnitRegistry, **options) -> s
division_fmt=" / ",
power_fmt="{} ** {}",
parentheses_fmt=r"({})",
registry=registry,
**options,
)

Expand All @@ -287,10 +291,64 @@ def format_compact(unit: UnitsContainer, registry: UnitRegistry, **options) -> s
division_fmt="/",
power_fmt="{}**{}",
parentheses_fmt=r"({})",
registry=registry,
**options,
)


dim_order = [
"[substance]",
"[mass]",
"[current]",
"[luminosity]",
"[length]",
"[time]",
"[temperature]",
]


def dim_sort(units: Iterable[list[str]], registry: UnitRegistry):
"""Sort a list of units by dimensional order.

Parameters
----------
units : list
a list of unit names (without values).
registry : UnitRegistry
the registry to use for looking up the dimensions of each unit.

Returns
-------
list
the list of units sorted by most significant dimension first.

Raises
------
KeyError
If unit cannot be found in the registry.
"""
ret_dict = dict()
len(units) > 1
for name in units:
cname = registry.get_name(name)
if not cname:
continue
dim_types = iter(dim_order)
while True:
try:
dim = next(dim_types)
if dim in registry.get_dimensionality(cname):
if dim not in ret_dict:
ret_dict[dim] = list()
ret_dict[dim].append(cname)
break
except StopIteration:
raise KeyError(f"Unit {cname} has no recognized dimensions")

ret = sum([ret_dict[dim] for dim in dim_order if dim in ret_dict], [])
return ret


def formatter(
items: Iterable[tuple[str, Number]],
as_ratio: bool = True,
Expand All @@ -304,6 +362,8 @@ def formatter(
babel_length: str = "long",
babel_plural_form: str = "one",
sort: bool = True,
sort_dims: bool = False,
registry: Optional[UnitRegistry] = None,
) -> str:
"""Format a list of (name, exponent) pairs.

Expand Down Expand Up @@ -334,6 +394,12 @@ def formatter(
(Default value = lambda x: f"{x:n}")
sort : bool, optional
True to sort the formatted units alphabetically (Default value = True)
sort_dims : bool, optional
True to sort the units dimentionally (Default value = False).
When dimensions have multiple units, sort by "most significant dimension" the unit contains
When both `sort` and `sort_dims` are True, sort alphabetically within sorted dimensions
registry : UnitRegistry, optional
The registry to use if `sort_dims` is True

Returns
-------
Expand Down Expand Up @@ -393,6 +459,12 @@ def formatter(
else:
neg_terms.append(power_fmt.format(key, fun(value)))

if sort_dims:
if len(pos_terms) > 1:
pos_terms = dim_sort(pos_terms, registry)
if len(neg_terms) > 1:
neg_terms = dim_sort(neg_terms, registry)

if not as_ratio:
# Show as Product: positive * negative terms ** -1
return _join(product_fmt, pos_terms + neg_terms)
Expand Down
23 changes: 23 additions & 0 deletions pint/testsuite/test_issues.py
Original file line number Diff line number Diff line change
Expand Up @@ -1150,3 +1150,26 @@ def test_issues_1505():
assert isinstance(
ur.Quantity("m/s").magnitude, decimal.Decimal
) # unexpected fail (magnitude should be a decimal)


def test_issues_1841():
import pint

# sets compact display mode
ur = UnitRegistry()
ur.default_format = "~P"

# creates quantity
q = ur.Quantity("1 kW * 1 h")

assert (
pint.formatting.format_unit(q.u._units, spec="", registry=ur, sort_dims=True)
== "kilowatt * hour"
)
assert (
pint.formatting.format_unit(q.u._units, spec="", registry=ur, sort_dims=False)
== "hour * kilowatt"
)

# this prints "1 h·kW", not "1 kW·h" unless sort_dims is True
# print(q)