diff --git a/pint/facets/plain/qto.py b/pint/facets/plain/qto.py index 22176491d..b4a1eb6cb 100644 --- a/pint/facets/plain/qto.py +++ b/pint/facets/plain/qto.py @@ -16,6 +16,7 @@ ) from ...errors import UndefinedBehavior from ...util import infer_base_unit +import itertools if TYPE_CHECKING: from ..._typing import UnitLike @@ -84,7 +85,7 @@ def to_reduced_units( def to_compact( quantity: PlainQuantity, unit: UnitsContainer | None = None ) -> PlainQuantity: - """ "Return PlainQuantity rescaled to compact, human-readable units. + """ "Return PlainQuantity in compact, human-readable units by adding or modifying the SI prefix. To get output in terms of a different unit, use the unit parameter. @@ -170,6 +171,50 @@ def to_compact( return quantity.to(new_unit_container) +def to_human( + quantity: PlainQuantity, human_units: list[UnitLike] | None = None +) -> PlainQuantity: + """Return Quantity converted to the smallest human_unit with a magnitude greater than 1, + or the largest magnitude if all conversions give magnitudes less than 1. + + Examples + -------- + + >>> import pint + >>> ureg = pint.UnitRegistry() + >>> time_units = [ureg.s, ureg.min, ureg.hr, ureg.day, ureg.year] + >>> (1000*ureg.s).to_human(time_units) + + >>> (100000*ureg.s).to_human(time_units) + + >>> (100000000*ureg.s).to_human(time_units) + + >>> ureg.Quantity(100000,"m**3/hr").to_human([ureg.Unit("m**3/s"), ureg.Unit("liter/s")]) + + >>> ureg.Quantity(1000,"m**3/hr").to_human([ureg.Unit("m**3/s"), ureg.Unit("liter/s")]) + + + """ + if human_units is None: + human_units = quantity._REGISTRY.default_human_units + + candidate_units = [] + if human_units: + for unit in human_units: + if unit.dimensionality == quantity.dimensionality: + candidate_units.append(unit) + if candidate_units == []: + return quantity + + results = [quantity.to(cu) for cu in candidate_units] + results = sorted(results, key=lambda x:x.m) + + for result in results: + if result.m > 1: + return result + return results[-1] + + def to_preferred( quantity: PlainQuantity, preferred_units: list[UnitLike] | None = None diff --git a/pint/facets/plain/quantity.py b/pint/facets/plain/quantity.py index a18919273..0adccedcc 100644 --- a/pint/facets/plain/quantity.py +++ b/pint/facets/plain/quantity.py @@ -579,6 +579,7 @@ def to_base_units(self) -> PlainQuantity[MagnitudeT]: # convenient that they live in PlainQuantity. # They are implemented elsewhere to keep Quantity class clean. to_compact = qto.to_compact + to_human = qto.to_human to_preferred = qto.to_preferred ito_preferred = qto.ito_preferred to_reduced_units = qto.to_reduced_units diff --git a/pint/testsuite/test_quantity.py b/pint/testsuite/test_quantity.py index 26a5ee05d..7866afe05 100644 --- a/pint/testsuite/test_quantity.py +++ b/pint/testsuite/test_quantity.py @@ -377,6 +377,56 @@ def test_convert(self): round(abs(self.Q_("2 second").to("millisecond").magnitude - 2000), 7) == 0 ) + def test_to_human(self): + ureg = self.ureg + Q_ = self.Q_ + time_units = [ureg.s, ureg.min, ureg.hr, ureg.day, ureg.year] + + temp = (1000*ureg.s).to_human(time_units) + helpers.assert_quantity_almost_equal(temp, Q_(16.6666667, 'minute')) + assert temp.units == ureg.minute + + temp = (100000*ureg.s).to_human(time_units) + helpers.assert_quantity_almost_equal(temp, Q_(1.15740741, 'day')) + assert temp.units == ureg.day + + temp = (100000000*ureg.s).to_human(time_units) + helpers.assert_quantity_almost_equal(temp, Q_(3.16880878, 'year')) + assert temp.units == ureg.year + + temp = ureg.Quantity(100000,"m**3/hr").to_human([ureg.Unit("m**3/s"), ureg.Unit("liter/s")]) + helpers.assert_quantity_almost_equal(temp, Q_(27.7777778, 'meter ** 3 / second')) + assert temp.units == ureg.Unit("m**3/s") + + temp = ureg.Quantity(1000,"m**3/hr").to_human([ureg.Unit("m**3/s"), ureg.Unit("liter/s")]) + helpers.assert_quantity_almost_equal(temp, Q_(277.777778, 'liter / second')) + assert temp.units == ureg.Unit("liter/s") + + def test_to_human_registry(self): + ureg = self.ureg + Q_ = self.Q_ + ureg.default_human_units = [ureg.s, ureg.min, ureg.hr, ureg.day, ureg.year, ureg.Unit("m**3/s"), ureg.Unit("liter/s")] + + temp = (1000*ureg.s).to_human() + helpers.assert_quantity_almost_equal(temp, Q_(16.6666667, 'minute')) + assert temp.units == ureg.minute + + temp = (100000*ureg.s).to_human() + helpers.assert_quantity_almost_equal(temp, Q_(1.15740741, 'day')) + assert temp.units == ureg.day + + temp = (100000000*ureg.s).to_human() + helpers.assert_quantity_almost_equal(temp, Q_(3.16880878, 'year')) + assert temp.units == ureg.year + + temp = ureg.Quantity(100000,"m**3/hr").to_human() + helpers.assert_quantity_almost_equal(temp, Q_(27.7777778, 'meter ** 3 / second')) + assert temp.units == ureg.Unit("m**3/s") + + temp = ureg.Quantity(1000,"m**3/hr").to_human() + helpers.assert_quantity_almost_equal(temp, Q_(277.777778, 'liter / second')) + assert temp.units == ureg.Unit("liter/s") + @helpers.requires_mip def test_to_preferred(self): ureg = self.ureg