from __future__ import annotations import copy import decimal import importlib.util import math import pprint import subprocess import sys import pytest from pint import ( Context, DimensionalityError, UndefinedUnitError, UnitRegistry, get_application_registry, ) from pint.compat import np from pint.delegates.formatter._compound_unit_helpers import sort_by_dimensionality from pint.facets.plain.unit import UnitsContainer from pint.testing import assert_equal from pint.testsuite import QuantityTestCase, helpers from pint.util import ParserHelper from .helpers import internal # TODO: do not subclass from QuantityTestCase class TestIssues(QuantityTestCase): kwargs = dict(autoconvert_offset_to_baseunit=False) @pytest.mark.xfail def test_issue25(self, module_registry): x = ParserHelper.from_string("10 %") assert x == ParserHelper(10, {"%": 1}) x = ParserHelper.from_string("10 ‰") assert x == ParserHelper(10, {"‰": 1}) module_registry.define("percent = [fraction]; offset: 0 = %") module_registry.define("permille = percent / 10 = ‰") x = module_registry.parse_expression("10 %") assert x == module_registry.Quantity(10, {"%": 1}) y = module_registry.parse_expression("10 ‰") assert y == module_registry.Quantity(10, {"‰": 1}) assert x.to("‰") == module_registry.Quantity(1, {"‰": 1}) def test_issue29(self, module_registry): t = 4 * module_registry("mW") assert t.magnitude == 4 assert t._units == UnitsContainer(milliwatt=1) assert t.to("joule / second") == 4e-3 * module_registry("W") @pytest.mark.xfail @helpers.requires_numpy def test_issue37(self, module_registry): x = np.ma.masked_array([1, 2, 3], mask=[True, True, False]) q = module_registry.meter * x assert isinstance(q, module_registry.Quantity) np.testing.assert_array_equal(q.magnitude, x) assert q.units == module_registry.meter.units q = x * module_registry.meter assert isinstance(q, module_registry.Quantity) np.testing.assert_array_equal(q.magnitude, x) assert q.units == module_registry.meter.units m = np.ma.masked_array(2 * np.ones(3, 3)) qq = q * m assert isinstance(qq, module_registry.Quantity) np.testing.assert_array_equal(qq.magnitude, x * m) assert qq.units == module_registry.meter.units qq = m * q assert isinstance(qq, module_registry.Quantity) np.testing.assert_array_equal(qq.magnitude, x * m) assert qq.units == module_registry.meter.units @helpers.requires_numpy def test_issue44(self, module_registry): x = 4.0 * module_registry.dimensionless np.sqrt(x) helpers.assert_quantity_almost_equal( np.sqrt([4.0] * module_registry.dimensionless), [2.0] * module_registry.dimensionless, ) helpers.assert_quantity_almost_equal( np.sqrt(4.0 * module_registry.dimensionless), 2.0 * module_registry.dimensionless, ) def test_issue45(self, module_registry): import math helpers.assert_quantity_almost_equal( math.sqrt(4 * module_registry.m / module_registry.cm), math.sqrt(4 * 100) ) helpers.assert_quantity_almost_equal( float(module_registry.V / module_registry.mV), 1000.0 ) @helpers.requires_numpy def test_issue45b(self, module_registry): helpers.assert_quantity_almost_equal( np.sin([np.pi / 2] * module_registry.m / module_registry.m), np.sin([np.pi / 2] * module_registry.dimensionless), ) helpers.assert_quantity_almost_equal( np.sin([np.pi / 2] * module_registry.cm / module_registry.m), np.sin([np.pi / 2] * module_registry.dimensionless * 0.01), ) def test_issue50(self, module_registry): Q_ = module_registry.Quantity assert Q_(100) == 100 * module_registry.dimensionless assert Q_("100") == 100 * module_registry.dimensionless def test_issue52(self): u1 = UnitRegistry() u2 = UnitRegistry() q1 = 1 * u1.meter q2 = 1 * u2.meter import operator as op for fun in ( op.add, op.iadd, op.sub, op.isub, op.mul, op.imul, op.floordiv, op.ifloordiv, op.truediv, op.itruediv, ): with pytest.raises(ValueError): fun(q1, q2) def test_issue54(self, module_registry): assert (1 * module_registry.km / module_registry.m + 1).magnitude == 1001 def test_issue54_related(self, module_registry): assert module_registry.km / module_registry.m == 1000 assert 1000 == module_registry.km / module_registry.m assert 900 < module_registry.km / module_registry.m assert 1100 > module_registry.km / module_registry.m def test_issue61(self, module_registry): Q_ = module_registry.Quantity for value in ({}, {"a": 3}, None): with pytest.raises(TypeError): Q_(value) with pytest.raises(TypeError): Q_(value, "meter") with pytest.raises(ValueError): Q_("", "meter") with pytest.raises(ValueError): Q_("") @helpers.requires_not_numpy() def test_issue61_notNP(self, module_registry): Q_ = module_registry.Quantity for value in ([1, 2, 3], (1, 2, 3)): with pytest.raises(TypeError): Q_(value) with pytest.raises(TypeError): Q_(value, "meter") def test_issue62(self, module_registry): m = module_registry("m**0.5") assert str(m.units) == "meter ** 0.5" def test_issue66(self, module_registry): assert module_registry.get_dimensionality( UnitsContainer({"[temperature]": 1}) ) == UnitsContainer({"[temperature]": 1}) assert module_registry.get_dimensionality( module_registry.kelvin ) == UnitsContainer({"[temperature]": 1}) assert module_registry.get_dimensionality( module_registry.degC ) == UnitsContainer({"[temperature]": 1}) def test_issue66b(self, module_registry): assert module_registry.get_base_units(module_registry.kelvin) == ( 1.0, module_registry.Unit(UnitsContainer({"kelvin": 1})), ) assert module_registry.get_base_units(module_registry.degC) == ( 1.0, module_registry.Unit(UnitsContainer({"kelvin": 1})), ) def test_issue69(self, module_registry): q = module_registry("m").to(module_registry("in")) assert q == module_registry("m").to("in") @helpers.requires_numpy def test_issue74(self, module_registry): v1 = np.asarray([1.0, 2.0, 3.0]) v2 = np.asarray([3.0, 2.0, 1.0]) q1 = v1 * module_registry.ms q2 = v2 * module_registry.ms np.testing.assert_array_equal(q1 < q2, v1 < v2) np.testing.assert_array_equal(q1 > q2, v1 > v2) np.testing.assert_array_equal(q1 <= q2, v1 <= v2) np.testing.assert_array_equal(q1 >= q2, v1 >= v2) q2s = np.asarray([0.003, 0.002, 0.001]) * module_registry.s v2s = q2s.to("ms").magnitude np.testing.assert_array_equal(q1 < q2s, v1 < v2s) np.testing.assert_array_equal(q1 > q2s, v1 > v2s) np.testing.assert_array_equal(q1 <= q2s, v1 <= v2s) np.testing.assert_array_equal(q1 >= q2s, v1 >= v2s) @helpers.requires_numpy def test_issue75(self, module_registry): v1 = np.asarray([1.0, 2.0, 3.0]) v2 = np.asarray([3.0, 2.0, 1.0]) q1 = v1 * module_registry.ms q2 = v2 * module_registry.ms np.testing.assert_array_equal(q1 == q2, v1 == v2) np.testing.assert_array_equal(q1 != q2, v1 != v2) q2s = np.asarray([0.003, 0.002, 0.001]) * module_registry.s v2s = q2s.to("ms").magnitude np.testing.assert_array_equal(q1 == q2s, v1 == v2s) np.testing.assert_array_equal(q1 != q2s, v1 != v2s) @helpers.requires_uncertainties() def test_issue77(self, module_registry): acc = (5.0 * module_registry("m/s/s")).plus_minus(0.25) tim = (37.0 * module_registry("s")).plus_minus(0.16) dis = acc * tim**2 / 2 assert dis.value == acc.value * tim.value**2 / 2 def test_issue85(self, module_registry): T = 4.0 * module_registry.kelvin m = 1.0 * module_registry.amu va = 2.0 * module_registry.k * T / m va.to_base_units() boltmk = 1.380649e-23 * module_registry.J / module_registry.K vb = 2.0 * boltmk * T / m helpers.assert_quantity_almost_equal(va.to_base_units(), vb.to_base_units()) def test_issue86(self, module_registry): module_registry.autoconvert_offset_to_baseunit = True def parts(q): return q.magnitude, q.units q1 = 10.0 * module_registry.degC q2 = 10.0 * module_registry.kelvin k1 = q1.to_base_units() q3 = 3.0 * module_registry.meter q1m, q1u = parts(q1) q2m, q2u = parts(q2) q3m, q3u = parts(q3) k1m, k1u = parts(k1) assert parts(q2 * q3) == (q2m * q3m, q2u * q3u) assert parts(q2 / q3) == (q2m / q3m, q2u / q3u) assert parts(q3 * q2) == (q3m * q2m, q3u * q2u) assert parts(q3 / q2) == (q3m / q2m, q3u / q2u) assert parts(q2**1) == (q2m**1, q2u**1) assert parts(q2**-1) == (q2m**-1, q2u**-1) assert parts(q2**2) == (q2m**2, q2u**2) assert parts(q2**-2) == (q2m**-2, q2u**-2) assert parts(q1 * q3) == (k1m * q3m, k1u * q3u) assert parts(q1 / q3) == (k1m / q3m, k1u / q3u) assert parts(q3 * q1) == (q3m * k1m, q3u * k1u) assert parts(q3 / q1) == (q3m / k1m, q3u / k1u) assert parts(q1**-1) == (k1m**-1, k1u**-1) assert parts(q1**2) == (k1m**2, k1u**2) assert parts(q1**-2) == (k1m**-2, k1u**-2) def test_issues86b(self, module_registry): T1 = module_registry.Quantity(200, module_registry.degC) # T1 = 200.0 * module_registry.degC T2 = T1.to(module_registry.kelvin) m = 132.9054519 * module_registry.amu v1 = 2 * module_registry.k * T1 / m v2 = 2 * module_registry.k * T2 / m helpers.assert_quantity_almost_equal(v1, v2) helpers.assert_quantity_almost_equal(v1, v2.to_base_units()) helpers.assert_quantity_almost_equal(v1.to_base_units(), v2) helpers.assert_quantity_almost_equal(v1.to_base_units(), v2.to_base_units()) @pytest.mark.xfail def test_issue86c(self, module_registry): module_registry.autoconvert_offset_to_baseunit = True T = module_registry.degC T = 100.0 * T helpers.assert_quantity_almost_equal( module_registry.k * 2 * T, module_registry.k * (2 * T) ) def test_issue93(self, module_registry): x = 5 * module_registry.meter assert isinstance(x.magnitude, int) y = 0.1 * module_registry.meter assert isinstance(y.magnitude, float) z = 5 * module_registry.meter assert isinstance(z.magnitude, int) z += y assert isinstance(z.magnitude, float) helpers.assert_quantity_almost_equal(x + y, 5.1 * module_registry.meter) helpers.assert_quantity_almost_equal(z, 5.1 * module_registry.meter) def test_issue104(self, module_registry): x = [ module_registry("1 meter"), module_registry("1 meter"), module_registry("1 meter"), ] y = [module_registry("1 meter")] * 3 def summer(values): if not values: return 0 total = values[0] for v in values[1:]: total += v return total helpers.assert_quantity_almost_equal( summer(x), module_registry.Quantity(3, "meter") ) helpers.assert_quantity_almost_equal(x[0], module_registry.Quantity(1, "meter")) helpers.assert_quantity_almost_equal( summer(y), module_registry.Quantity(3, "meter") ) helpers.assert_quantity_almost_equal(y[0], module_registry.Quantity(1, "meter")) def test_issue105(self, module_registry): func = module_registry.parse_unit_name val = list(func("meter")) assert list(func("METER")) == [] assert val == list(func("METER", False)) for func in (module_registry.get_name, module_registry.parse_expression): val = func("meter") with pytest.raises(AttributeError): func("METER") assert val == func("METER", False) @helpers.requires_numpy def test_issue127(self, module_registry): q = [1.0, 2.0, 3.0, 4.0] * module_registry.meter q[0] = np.nan assert q[0] != 1.0 assert math.isnan(q[0].magnitude) q[1] = float("NaN") assert q[1] != 2.0 assert math.isnan(q[1].magnitude) def test_issue170(self): Q_ = UnitRegistry().Quantity q = Q_("1 kHz") / Q_("100 Hz") iq = int(q) assert iq == 10 assert isinstance(iq, int) def test_angstrom_creation(self, module_registry): module_registry.Quantity(2, "Å") def test_alternative_angstrom_definition(self, module_registry): module_registry.Quantity(2, "\u212b") def test_micro_creation_U03bc(self, module_registry): module_registry.Quantity(2, "μm") def test_micro_creation_U00b5(self, module_registry): module_registry.Quantity(2, "µm") def test_micro_creation_mu(self, module_registry): module_registry.Quantity(2, "mug") def test_micro_creation_mc(self, module_registry): module_registry.Quantity(2, "mcg") def test_liter_creation_U2113(self, module_registry): module_registry.Quantity(2, "ℓ") @helpers.requires_numpy def test_issue171_real_imag(self, module_registry): qr = [1.0, 2.0, 3.0, 4.0] * module_registry.meter qi = [4.0, 3.0, 2.0, 1.0] * module_registry.meter q = qr + 1j * qi helpers.assert_quantity_equal(q.real, qr) helpers.assert_quantity_equal(q.imag, qi) @helpers.requires_numpy def test_issue171_T(self, module_registry): a = np.asarray([[1.0, 2.0, 3.0, 4.0], [4.0, 3.0, 2.0, 1.0]]) q1 = a * module_registry.meter q2 = a.T * module_registry.meter helpers.assert_quantity_equal(q1.T, q2) @helpers.requires_numpy def test_issue250(self, module_registry): a = module_registry.V b = module_registry.mV assert np.float16(a / b) == 1000.0 assert np.float32(a / b) == 1000.0 assert np.float64(a / b) == 1000.0 if "float128" in dir(np): assert np.float128(a / b) == 1000.0 def test_issue252(self): ur = UnitRegistry() q = ur("3 F") t = copy.deepcopy(q) u = t.to(ur.mF) helpers.assert_quantity_equal(q.to(ur.mF), u) def test_issue323(self, module_registry): from fractions import Fraction as F assert (self.Q_(F(2, 3), "s")).to("ms") == self.Q_(F(2000, 3), "ms") assert (self.Q_(F(2, 3), "m")).to("km") == self.Q_(F(1, 1500), "km") def test_issue339(self, module_registry): q1 = module_registry("") assert q1.magnitude == 1 assert q1.units == module_registry.dimensionless q2 = module_registry("1 dimensionless") assert q1 == q2 def test_issue354_356_370(self, module_registry): assert ( f"{1 * module_registry.second / module_registry.millisecond:~}" == "1.0 s / ms" ) assert f"{1 * module_registry.count:~}" == "1 count" assert "{:~}".format(1 * module_registry("MiB")) == "1 MiB" def test_issue468(self, module_registry): @module_registry.wraps("kg", "meter") def f(x): return x x = module_registry.Quantity(1.0, "meter") y = f(x) z = x * y assert z == module_registry.Quantity(1.0, "meter * kilogram") @helpers.requires_numpy def test_issue482(self, module_registry): q = module_registry.Quantity(1, module_registry.dimensionless) qe = np.exp(q) assert isinstance(qe, module_registry.Quantity) @helpers.requires_numpy def test_issue483(self, module_registry): a = np.asarray([1, 2, 3]) q = [1, 2, 3] * module_registry.dimensionless p = (q**q).m np.testing.assert_array_equal(p, a**a) def test_issue507(self, module_registry): # leading underscore in unit works with numbers module_registry.define("_100km = 100 * kilometer") battery_ec = 16 * module_registry.kWh / module_registry._100km # noqa: F841 # ... but not with text module_registry.define("_home = 4700 * kWh / year") with pytest.raises(AttributeError): home_elec_power = 1 * module_registry._home # noqa: F841 # ... or with *only* underscores module_registry.define("_ = 45 * km") with pytest.raises(AttributeError): one_blank = 1 * module_registry._ # noqa: F841 def test_issue523(self, module_registry): src, dst = UnitsContainer({"meter": 1}), UnitsContainer({"degF": 1}) value = 10.0 convert = module_registry.convert with pytest.raises(DimensionalityError): convert(value, src, dst) with pytest.raises(DimensionalityError): convert(value, dst, src) def test_issue532(self, module_registry): @module_registry.check(module_registry("")) def f(x): return 2 * x assert f(module_registry.Quantity(1, "")) == 2 with pytest.raises(DimensionalityError): f(module_registry.Quantity(1, "m")) def test_issue625a(self, module_registry): Q_ = module_registry.Quantity from math import sqrt @module_registry.wraps( module_registry.second, ( module_registry.meters, module_registry.meters / module_registry.second**2, ), ) def calculate_time_to_fall(height, gravity=Q_(9.8, "m/s^2")): """Calculate time to fall from a height h with a default gravity. By default, the gravity is assumed to be earth gravity, but it can be modified. d = .5 * g * t**2 t = sqrt(2 * d / g) Parameters ---------- height : gravity : (Default value = Q_(9.8) "m/s^2") : Returns ------- """ return sqrt(2 * height / gravity) lunar_module_height = Q_(10, "m") t1 = calculate_time_to_fall(lunar_module_height) # print(t1) assert round(abs(t1 - Q_(1.4285714285714286, "s")), 7) == 0 moon_gravity = Q_(1.625, "m/s^2") t2 = calculate_time_to_fall(lunar_module_height, moon_gravity) assert round(abs(t2 - Q_(3.508232077228117, "s")), 7) == 0 def test_issue625b(self, module_registry): Q_ = module_registry.Quantity @module_registry.wraps("=A*B", ("=A", "=B")) def get_displacement(time, rate=Q_(1, "m/s")): """Calculates displacement from a duration and default rate. Parameters ---------- time : rate : (Default value = Q_(1) "m/s") : Returns ------- """ return time * rate d1 = get_displacement(Q_(2, "s")) assert round(abs(d1 - Q_(2, "m")), 7) == 0 d2 = get_displacement(Q_(2, "s"), Q_(1, "deg/s")) assert round(abs(d2 - Q_(2, " deg")), 7) == 0 def test_issue625c(self): u = UnitRegistry() @u.wraps("=A*B*C", ("=A", "=B", "=C")) def get_product(a=2 * u.m, b=3 * u.m, c=5 * u.m): return a * b * c assert get_product(a=3 * u.m) == 45 * u.m**3 assert get_product(b=2 * u.m) == 20 * u.m**3 assert get_product(c=1 * u.dimensionless) == 6 * u.m**2 def test_issue655a(self, module_registry): distance = 1 * module_registry.m time = 1 * module_registry.s velocity = distance / time assert distance.check("[length]") assert not distance.check("[time]") assert velocity.check("[length] / [time]") assert velocity.check("1 / [time] * [length]") def test_issue655b(self, module_registry): Q_ = module_registry.Quantity @module_registry.check("[length]", "[length]/[time]^2") def pendulum_period(length, G=Q_(1, "standard_gravity")): # print(length) return (2 * math.pi * (length / G) ** 0.5).to("s") length = Q_(1, module_registry.m) # Assume earth gravity t = pendulum_period(length) assert round(abs(t - Q_("2.0064092925890407 second")), 7) == 0 # Use moon gravity moon_gravity = Q_(1.625, "m/s^2") t = pendulum_period(length, moon_gravity) assert round(abs(t - Q_("4.928936075204336 second")), 7) == 0 def test_issue783(self, module_registry): assert not module_registry("g") == [] def test_issue856(self, module_registry): ph1 = ParserHelper(scale=123) ph2 = copy.deepcopy(ph1) assert ph2.scale == ph1.scale module_registry1 = UnitRegistry() module_registry2 = copy.deepcopy(module_registry1) # Very basic functionality test assert module_registry2("1 t").to("kg").magnitude == 1000 def test_issue856b(self): # Test that, after a deepcopy(), the two UnitRegistries are # independent from each other ureg1 = UnitRegistry() ureg2 = copy.deepcopy(ureg1) ureg1.define("test123 = 123 kg") ureg2.define("test123 = 456 kg") assert ureg1("1 test123").to("kg").magnitude == 123 assert ureg2("1 test123").to("kg").magnitude == 456 def test_issue876(self): # Same hash must not imply equality. # As an implementation detail of CPython, hash(-1) == hash(-2). # This test is useless in potential alternative Python implementations where # hash(-1) != hash(-2); one would need to find hash collisions specific for each # implementation a = UnitsContainer({"[mass]": -1}) b = UnitsContainer({"[mass]": -2}) c = UnitsContainer({"[mass]": -3}) # Guarantee working on alternative Python implementations assert (hash(-1) == hash(-2)) == (hash(a) == hash(b)) assert (hash(-1) == hash(-3)) == (hash(a) == hash(c)) assert a != b assert a != c def test_issue902(self): module_registry = UnitRegistry(auto_reduce_dimensions=True) velocity = 1 * module_registry.m / module_registry.s cross_section = 1 * module_registry.um**2 result = cross_section / velocity assert result == 1e-12 * module_registry.m * module_registry.s def test_issue912(self, module_registry): """pprint.pformat() invokes sorted() on large sets and frozensets and graciously handles TypeError, but not generic Exceptions. This test will fail if pint.DimensionalityError stops being a subclass of TypeError. Parameters ---------- Returns ------- """ meter_units = module_registry.get_compatible_units(module_registry.meter) hertz_units = module_registry.get_compatible_units(module_registry.hertz) pprint.pformat(meter_units | hertz_units) def test_issue932(self, module_registry): q = module_registry.Quantity("1 kg") with pytest.raises(DimensionalityError): q.to("joule") module_registry.enable_contexts("energy", *(Context() for _ in range(20))) q.to("joule") module_registry.disable_contexts() with pytest.raises(DimensionalityError): q.to("joule") def test_issue960(self, module_registry): q = (1 * module_registry.nanometer).to_compact("micrometer") assert q.units == module_registry.nanometer assert q.magnitude == 1 def test_issue1032(self, module_registry): class MultiplicativeDictionary(dict): def __rmul__(self, other): return self.__class__( {key: value * other for key, value in self.items()} ) q = 3 * module_registry.s d = MultiplicativeDictionary({4: 5, 6: 7}) assert q * d == MultiplicativeDictionary( {4: 15 * module_registry.s, 6: 21 * module_registry.s} ) with pytest.raises(TypeError): d * q @helpers.requires_numpy def test_issue973(self, module_registry): """Verify that an empty array Quantity can be created through multiplication.""" q0 = np.array([]) * module_registry.m # by Unit q1 = np.array([]) * module_registry("m") # by Quantity assert isinstance(q0, module_registry.Quantity) assert isinstance(q1, module_registry.Quantity) assert len(q0) == len(q1) == 0 def test_issue1058(self, module_registry): """verify that auto-reducing quantities with three or more units of same plain type succeeds""" q = 1 * module_registry.mg / module_registry.g / module_registry.kg q.ito_reduced_units() assert isinstance(q, module_registry.Quantity) def test_issue1062_issue1097(self): # Must not be used by any other tests ureg = UnitRegistry() assert "nanometer" not in internal(ureg)._units for i in range(5): ctx = Context.from_lines(["@context _", "cal = 4 J"]) with ureg.context("sp", ctx): q = ureg.Quantity(1, "nm") q.to("J") def test_issue1066(self): """Verify calculations for offset units of higher dimension""" ureg = UnitRegistry() ureg.define("barga = 1e5 * Pa; offset: 1e5") ureg.define("bargb = 1 * bar; offset: 1") q_4barg_a = ureg.Quantity(4, ureg.barga) q_4barg_b = ureg.Quantity(4, ureg.bargb) q_5bar = ureg.Quantity(5, ureg.bar) helpers.assert_quantity_equal(q_4barg_a, q_5bar) helpers.assert_quantity_equal(q_4barg_b, q_5bar) def test_issue1086(self, module_registry): # units with prefixes should correctly test as 'in' the registry assert "bits" in module_registry assert "gigabits" in module_registry assert "meters" in module_registry assert "kilometers" in module_registry # unknown or incorrect units should test as 'not in' the registry assert "magicbits" not in module_registry assert "unknownmeters" not in module_registry assert "gigatrees" not in module_registry def test_issue1112(self): ureg = UnitRegistry( """ m = [length] g = [mass] s = [time] ft = 0.305 m lb = 454 g @context c1 [time]->[length] : value * 10 m/s @end @context c2 ft = 0.3 m @end @context c3 lb = 500 g @end """.splitlines() ) ureg.enable_contexts("c1") ureg.enable_contexts("c2") ureg.enable_contexts("c3") @helpers.requires_numpy def test_issue1144_1102(self, module_registry): # Performing operations shouldn't modify the original objects # Issue 1144 ddc = "delta_degree_Celsius" q1 = module_registry.Quantity([-287.78, -32.24, -1.94], ddc) q2 = module_registry.Quantity(70.0, "degree_Fahrenheit") q1 - q2 assert all(q1 == module_registry.Quantity([-287.78, -32.24, -1.94], ddc)) assert q2 == module_registry.Quantity(70.0, "degree_Fahrenheit") q2 - q1 assert all(q1 == module_registry.Quantity([-287.78, -32.24, -1.94], ddc)) assert q2 == module_registry.Quantity(70.0, "degree_Fahrenheit") # Issue 1102 val = [30.0, 45.0, 60.0] * module_registry.degree val == 1 1 == val assert all(val == module_registry.Quantity([30.0, 45.0, 60.0], "degree")) # Test for another bug identified by searching on "_convert_magnitude" q2 = module_registry.Quantity(3, "degree_Kelvin") q1 - q2 assert all(q1 == module_registry.Quantity([-287.78, -32.24, -1.94], ddc)) @helpers.requires_numpy def test_issue_1136(self, module_registry): assert ( 2 ** module_registry.Quantity([2, 3], "") == 2 ** np.array([2, 3]) ).all() with pytest.raises(DimensionalityError): 2 ** module_registry.Quantity([2, 3], "m") def test_issue1175(self): import pickle foo1 = get_application_registry().Quantity(1, "s") foo2 = pickle.loads(pickle.dumps(foo1)) assert isinstance(foo1, foo2.__class__) assert isinstance(foo2, foo1.__class__) @helpers.requires_numpy def test_issue1174(self, module_registry): q = [1.0, -2.0, 3.0, -4.0] * module_registry.meter assert np.sign(q[0].magnitude) assert np.sign(q[1].magnitude) @helpers.requires_numpy() def test_issue_1185(self, module_registry): # Test __pow__ foo = module_registry.Quantity((3, 3), "mm / cm") assert np.allclose( foo ** module_registry.Quantity([2, 3], ""), 0.3 ** np.array([2, 3]) ) assert np.allclose(foo ** np.array([2, 3]), 0.3 ** np.array([2, 3])) assert np.allclose(np.array([2, 3]) ** foo, np.array([2, 3]) ** 0.3) # Test __ipow__ foo **= np.array([2, 3]) assert np.allclose(foo, 0.3 ** np.array([2, 3])) # Test __rpow__ assert np.allclose( np.array((1, 1)).__rpow__(module_registry.Quantity((2, 3), "mm / cm")), np.array((0.2, 0.3)), ) assert np.allclose( module_registry.Quantity((20, 20), "mm / cm").__rpow__( np.array((0.2, 0.3)) ), np.array((0.04, 0.09)), ) def test_issue1277(self, module_registry): ureg = module_registry assert ureg("%") == ureg("percent") assert ureg("%") == ureg.percent assert ureg("ppm") == ureg.ppm a = ureg.Quantity("10 %") b = ureg.Quantity("100 ppm") c = ureg.Quantity("0.5") assert f"{a}" == "10 percent" assert f"{a:~}" == "10 %" assert f"{b}" == "100 ppm" assert f"{b:~}" == "100 ppm" assert_equal(a, 0.1) assert_equal(1000 * b, a) assert_equal(c, 5 * a) assert_equal((1 * ureg.meter) / (1 * ureg.kilometer), 0.1 * ureg.percent) assert c.to("percent").m == 50 # assert c.to("%").m == 50 # TODO: fails. def test_issue1963(self, module_registry): ureg = module_registry assert ureg("‰") == ureg("permille") assert ureg("‰") == ureg.permille a = ureg.Quantity("10 ‰") b = ureg.Quantity("100 ppm") c = ureg.Quantity("0.5") assert f"{a}" == "10 permille" assert f"{a:~}" == "10 ‰" assert_equal(a, 0.01) assert_equal(1e2 * b, a) assert_equal(c, 50 * a) assert_equal((1 * ureg.milligram) / (1 * ureg.gram), 1 * ureg.permille) @pytest.mark.xfail @helpers.requires_uncertainties() def test_issue_1300(self): # TODO: THIS is not longer necessary after moving to formatter module_registry = UnitRegistry() module_registry.default_format = "~P" m = module_registry.Measurement(1, 0.1, "meter") assert m.default_format == "~P" @helpers.requires_numpy() def test_issue1674(self, module_registry): Q_ = module_registry.Quantity arr_of_q = np.array([Q_(2, "m"), Q_(4, "m")], dtype="object") q_arr = Q_(np.array([1, 2]), "m") helpers.assert_quantity_equal( arr_of_q * q_arr, np.array([Q_(2, "m^2"), Q_(8, "m^2")], dtype="object") ) helpers.assert_quantity_equal( arr_of_q / q_arr, np.array([Q_(2, ""), Q_(2, "")], dtype="object") ) arr_of_q = np.array([Q_(2, "m"), Q_(4, "s")], dtype="object") q_arr = Q_(np.array([1, 2]), "m") helpers.assert_quantity_equal( arr_of_q * q_arr, np.array([Q_(2, "m^2"), Q_(8, "m s")], dtype="object") ) @helpers.requires_babel(["es_ES"]) def test_issue_1400(self, sess_registry): q1 = 3.1 * sess_registry.W q2 = 3.1 * sess_registry.W / sess_registry.cm assert q1.format_babel("~", locale="es_ES") == "3,1 W" assert q1.format_babel("", locale="es_ES") == "3,1 vatios" assert q2.format_babel("~", locale="es_ES") == "3,1 W/cm" assert q2.format_babel("", locale="es_ES") == "3,1 vatios por centímetro" @helpers.requires_numpy() @helpers.requires_uncertainties() def test_issue1611(self, module_registry): from numpy.testing import assert_almost_equal from uncertainties import ufloat from pint import pint_eval pint_eval.tokenizer = pint_eval.uncertainty_tokenizer u1 = ufloat(1.2, 0.34) u2 = ufloat(5.6, 0.78) q1_u = module_registry.Quantity(u2 - u1, "m") q1_str = str(q1_u) q1_str = f"{q1_u:.4uS}" q1_m = q1_u.magnitude q2_u = module_registry.Quantity(q1_str) # Not equal because the uncertainties are differently random! assert q1_u != q2_u q2_m = q2_u.magnitude assert_almost_equal(q2_m.nominal_value, q1_m.nominal_value, decimal=9) assert_almost_equal(q2_m.std_dev, q1_m.std_dev, decimal=4) q3_str = "12.34(5678)e-066 m" q3_u = module_registry.Quantity(q3_str) q3_m = q3_u.magnitude assert q3_m < 1 @helpers.requires_uncertainties def test_issue1614(self, module_registry): from uncertainties import UFloat, ufloat q = module_registry.Quantity(1.0, "m") assert isinstance(q, module_registry.Quantity) m = module_registry.Measurement(2.0, 0.3, "m") assert isinstance(m, module_registry.Measurement) u1 = ufloat(1.2, 3.4) u2 = ufloat(5.6, 7.8) q1_u = module_registry.Quantity(u1, "m") m1 = module_registry.Measurement(q1_u) assert m1.value.magnitude == u1.nominal_value assert m1.error.magnitude == u1.std_dev m2 = module_registry.Measurement(5.6, 7.8) # dimensionless q2_u = module_registry.Quantity(m2) assert isinstance(q2_u.magnitude, UFloat) assert q2_u.magnitude.nominal_value == m2.value assert q2_u.magnitude.nominal_value == u2.nominal_value assert q2_u.magnitude.std_dev == m2.error assert q2_u.magnitude.std_dev == u2.std_dev if np is not None: @pytest.mark.filterwarnings("ignore::pint.UnitStrippedWarning") @pytest.mark.parametrize( "callable", [ lambda x: np.sin(x / x.units), # Issue 399 lambda x: np.cos(x / x.units), # Issue 399 np.isfinite, # Issue 481 np.shape, # Issue 509 np.size, # Issue 509 np.sqrt, # Issue 622 lambda x: x.mean(), # Issue 678 lambda x: x.copy(), # Issue 678 np.array, lambda x: x.conjugate, ], ) @pytest.mark.parametrize( "q_params", [ pytest.param((1, "m"), id="python scalar int"), pytest.param(([1, 2, 3, 4], "m"), id="array int"), pytest.param(([1], "m", 0), id="numpy scalar int"), pytest.param((1.0, "m"), id="python scalar float"), pytest.param(([1.0, 2.0, 3.0, 4.0], "m"), id="array float"), pytest.param(([1.0], "m", 0), id="numpy scalar float"), ], ) def test_issue925(module_registry, callable, q_params): # Test for immutability of type if len(q_params) == 3: q_params, el = q_params[:2], q_params[2] else: el = None q = module_registry.Quantity(*q_params) if el is not None: q = q[el] type_before = type(q._magnitude) callable(q) assert isinstance(q._magnitude, type_before) @helpers.requires_numpy def test_issue1498(tmp_path): def0 = tmp_path / "def0.txt" def1 = tmp_path / "def1.txt" def2 = tmp_path / "def2.txt" # A file that defines a new plain unit and uses it in a context def0.write_text( """ foo = [FOO] @context BAR [FOO] -> [mass]: value / foo * 10.0 kg @end """ ) # A file that defines a new plain unit, then imports another file… def1.write_text( f""" foo = [FOO] @import {def2.name} """ ) # …that, in turn, uses it in a context def2.write_text( """ @context BAR [FOO] -> [mass]: value / foo * 10.0 kg @end """ ) ureg1 = UnitRegistry() ureg1.load_definitions(def1) assert 12.0 == ureg1("1.2 foo").to("kg", "BAR").magnitude @helpers.requires_numpy def test_issue1498b(tmp_path): def0 = tmp_path / "def0.txt" def1 = tmp_path / "dir_a" / "def1.txt" def1_1 = tmp_path / "dir_a" / "def1_1.txt" def1_2 = tmp_path / "dir_a" / "def1_2.txt" def2 = tmp_path / "def2.txt" # A file that defines a new plain unit and uses it in a context def0.write_text( """ foo = [FOO] @context BAR [FOO] -> [mass]: value / foo * 10.0 kg @end @import dir_a/def1.txt @import def2.txt """ ) # A file that defines a new plain unit, then imports another file… def1.parent.mkdir() def1.write_text( """ @import def1_1.txt @import def1_2.txt """ ) def1_1.write_text( """ @context BAR1_1 [FOO] -> [mass]: value / foo * 10.0 kg @end """ ) def1_2.write_text( """ @context BAR1_2 [FOO] -> [mass]: value / foo * 10.0 kg @end """ ) # …that, in turn, uses it in a context def2.write_text( """ @context BAR2 [FOO] -> [mass]: value / foo * 10.0 kg @end """ ) # Succeeds with pint 0.18; fails with pint 0.19 ureg1 = UnitRegistry() ureg1.load_definitions(def0) # ← FAILS assert 12.0 == ureg1("1.2 foo").to("kg", "BAR").magnitude def test_backcompat_speed_velocity(func_registry): get = func_registry.get_dimensionality assert get("[velocity]") == UnitsContainer({"[length]": 1, "[time]": -1}) assert get("[speed]") == UnitsContainer({"[length]": 1, "[time]": -1}) def test_issue1433(func_registry): assert func_registry.Quantity("1 micron") == func_registry.Quantity("1 micrometer") def test_issue1527(): ureg = UnitRegistry(non_int_type=decimal.Decimal) x = ureg.parse_expression("2 microliter milligram/liter") assert x.magnitude.as_tuple()[1] == (2,) assert x.to_compact().as_tuple()[1] == (2,) assert x.to_base_units().as_tuple()[1] == (2,) assert x.to("ng").as_tuple()[1] == (2,) def test_issue1621(): ureg = UnitRegistry(non_int_type=decimal.Decimal) digits = ureg.Quantity("5.0 mV/m").to_base_units().magnitude.as_tuple()[1] assert digits == (5, 0) def test_issue1631(): import pint # Test registry subclassing class MyRegistry(pint.UnitRegistry): pass assert MyRegistry.Quantity is pint.UnitRegistry.Quantity assert MyRegistry.Unit is pint.UnitRegistry.Unit ureg = MyRegistry() u = ureg.meter assert isinstance(u, ureg.Unit) assert isinstance(u, pint.Unit) q = 2 * ureg.meter assert isinstance(q, ureg.Quantity) assert isinstance(q, pint.Quantity) def test_issue1725(registry_empty): registry_empty.define("dollar = [currency]") assert registry_empty.get_compatible_units("dollar") == set() def test_issue1505(): ur = UnitRegistry(non_int_type=decimal.Decimal) assert isinstance(ur.Quantity("1m/s").magnitude, decimal.Decimal) assert not isinstance( ur.Quantity("m/s").magnitude, float ) # unexpected success (magnitude should not be a float) assert isinstance( ur.Quantity("m/s").magnitude, decimal.Decimal ) # unexpected fail (magnitude should be a decimal) def test_issue_1845(): ur = UnitRegistry(auto_reduce_dimensions=True, non_int_type=decimal.Decimal) # before issue 1845 these inputs would have resulted in a TypeError assert ur("km / h * m").units == ur.Quantity("meter ** 2 / hour") assert ur("kW / min * W").units == ur.Quantity("watts ** 2 / minute") @pytest.mark.parametrize( "units,spec,expected", [ # (dict(hour=1, watt=1), "P~", "W·h"), (dict(ampere=1, volt=1), "P~", "V·A"), # (dict(meter=1, newton=1), "P~", "N·m"), ], ) def test_issues_1841(func_registry, units, spec, expected): ur = func_registry ur.formatter.default_sort_func = sort_by_dimensionality ur.formatter.default_format = spec value = ur.Unit(UnitsContainer(**units)) assert f"{value}" == expected @pytest.mark.xfail def test_issues_1841_xfail(): from pint import formatting as fmt from pint.delegates.formatter._compound_unit_helpers import sort_by_dimensionality # sets compact display mode by default ur = UnitRegistry() ur.formatter.default_format = "~P" ur.formatter.default_sort_func = sort_by_dimensionality q = ur.Quantity("2*pi radian * hour") # Note that `radian` (and `bit` and `count`) are treated as dimensionless. # And note that dimensionless quantities are stripped by this process, # leading to errorneous output. Suggestions? assert ( fmt.format_unit(q.u._units, spec="", registry=ur, sort_dims=True) == "radian * hour" ) assert ( fmt.format_unit(q.u._units, spec="", registry=ur, sort_dims=False) == "hour * radian" ) # this prints "2*pi hour * radian", not "2*pi radian * hour" unless sort_dims is True # print(q) def test_issue1949(registry_empty): ureg = UnitRegistry() ureg.define( "in_Hg_gauge = 3386389 * gram / metre / second ** 2; offset:101325000 = inHg_g = in_Hg_g = inHg_gauge" ) q = ureg.Quantity("1 atm").to("inHg_gauge") assert q.units == ureg.in_Hg_gauge assert_equal(q.magnitude, 0.0) @pytest.mark.parametrize( "given,expected", [ ( "8.989e9 newton * meter^2 / coulomb^2", r"\SI[]{8.989E+9}{\meter\squared\newton\per\coulomb\squared}", ), ("5 * meter / second", r"\SI[]{5}{\meter\per\second}"), ("2.2 * meter^4", r"\SI[]{2.2}{\meter\tothe{4}}"), ("2.2 * meter^-4", r"\SI[]{2.2}{\per\meter\tothe{4}}"), ], ) def test_issue1772(given, expected): ureg = UnitRegistry(non_int_type=decimal.Decimal) assert f"{ureg(given):Lx}" == expected def test_issue2017(): ureg = UnitRegistry() from pint import formatting as fmt @fmt.register_unit_format("test") def _test_format(unit, registry, **options): proc = {u.replace("µ", "u"): e for u, e in unit.items()} return fmt.formatter( proc.items(), as_ratio=True, single_denominator=False, product_fmt="*", division_fmt="/", power_fmt="{}{}", parentheses_fmt="({})", **options, ) base_unit = ureg.microsecond assert f"{base_unit:~test}" == "us" assert f"{base_unit:test}" == "microsecond" def test_issue2007(): ureg = UnitRegistry() q = ureg.Quantity(1, "") assert f"{q:P}" == "1 dimensionless" assert f"{q:C}" == "1 dimensionless" assert f"{q:D}" == "1 dimensionless" assert f"{q:H}" == "1 dimensionless" assert f"{q:L}" == "1\\ \\mathrm{dimensionless}" # L returned '1\\ dimensionless' in pint 0.23 assert f"{q:Lx}" == "\\SI[]{1}{}" assert f"{q:~P}" == "1" assert f"{q:~C}" == "1" assert f"{q:~D}" == "1" assert f"{q:~H}" == "1" @helpers.requires_uncertainties() @helpers.requires_numpy() def test_issue2044(): from numpy.testing import assert_almost_equal from uncertainties import ufloat ureg = UnitRegistry() # First make sure this doesn't fail completely (A Measurement) q = ureg.Quantity(10_000, "m").plus_minus(0.01).to_compact() assert_almost_equal(q.m.n, 10.0) assert q.u == "kilometer" # Similarly, for a Ufloat with units q = (ufloat(10_000, 0.01) * ureg.m).to_compact() assert_almost_equal(q.m.n, 10.0) assert q.u == "kilometer" def test_issue2107(): # Use decimal ureg = UnitRegistry(non_int_type=decimal.Decimal) # 2 L/h is equal to 48 L/day flow = decimal.Decimal("2") * ureg.L / ureg.h assert flow.to(ureg.L / ureg.day).magnitude == 48.0 # 1 inch is equal to 1000 thou distance = ureg.Quantity(decimal.Decimal("1.0"), ureg.inch) assert distance.to(ureg.thou).magnitude == 1000.0 # Perform the same conversions without decimal ureg = UnitRegistry() # 2 L/h is equal to 48 L/day flow = 2 * ureg.L / ureg.h assert flow.to(ureg.L / ureg.day).magnitude == 48.0 # 1 inch is equal to 1000 thou distance = ureg.Quantity(1, ureg.inch) assert distance.to(ureg.thou).magnitude == 1000.0 def test_issue2172(): ureg = UnitRegistry() def mass_to_volume(u, value, *, density=None): """Convert mass to volume using density.""" density = density or 1000 * u.kilogram / u.meter**3 # 5 C return value / density context = Context("Water") context.add_transformation("[mass]", "[volume]", mass_to_volume) ureg.add_context(context) ureg.enable_contexts(context.name) mass = ureg.Quantity(1000, "kg") assert mass.to("m**3").m == pytest.approx(1.0) assert mass.to( "m**3", density=958.05 * ureg.kilogram / ureg.meter**3 ).m == pytest.approx(1.0437868587234487) # 100 C mass.ito("m**3", density=958.05 * ureg.kilogram / ureg.meter**3) assert mass.m == pytest.approx(1.0437868587234487) # 100 C def test_issue2199(func_registry): msg = "is not defined in the unit registry" with pytest.raises(UndefinedUnitError, match=msg): func_registry.Quantity.from_tuple((1, (("wrong", 1),))) def test_issue2228(func_registry): func_registry.define("test2228A = nan meter") func_registry.define("test2228B = nan meter") # Behaviour before 2228 was fixed nan_factor, _ = func_registry._get_root_units( UnitsContainer({"test2228A": 1, "test2228B": -1}) ) assert nan_factor != 1 # Expected behaviour - return nan assert math.isnan(nan_factor) ok_factor, _ = func_registry._get_root_units( UnitsContainer({"meter": 1, "centimeter": -1}) ) assert ok_factor == 100.0 def test_issue2261(func_registry): func_registry.define("truckload = nan kg") # Converting to a prefixed form of a NaN unit should give a numeric result q = func_registry.Quantity("1000 truckloads") result = q.to("kilotruckload") assert result.magnitude == 1.0 # Reverse direction should also work q2 = func_registry.Quantity("1 kilotruckload") result2 = q2.to("truckload") assert result2.magnitude == 1000.0 # NaN should still propagate when converting to a non-NaN unit q3 = func_registry.Quantity("2 truckloads") result3 = q3.to("kg") assert math.isnan(result3.magnitude) # Compound units containing a NaN unit should also convert correctly q4 = func_registry.Quantity("1000 truckload/day") result4 = q4.to("kilotruckload/day") assert result4.magnitude == 1.0 def test_issue2265(): """Check that dask.array is not imported with pint.""" if importlib.util.find_spec("dask") is None: pytest.skip("dask is not available") command = [ sys.executable, "-c", "import pint, sys; print('dask.array' in sys.modules)", ] result = subprocess.run(command, check=True, capture_output=True, text=True) assert result.stdout.strip() == "False" def test_issue2265_2(): """Verify that lazy-loaded dask_array.Array works when accessed.""" if importlib.util.find_spec("dask") is None: pytest.skip("dask is not available") from pint.compat import HAS_DASK, dask_array if not HAS_DASK: pytest.skip("dask is not available") # Access dask_array.Array to trigger lazy import dask_array_class = dask_array.Array assert dask_array_class is not None # Verify it's the actual dask Array class by checking module assert dask_array_class.__module__ == "dask.array.core" def test_issue2256(): ureg = UnitRegistry() from pint import formatting as fmt from pint.delegates.formatter.plain import PrettyFormatter @fmt.register_unit_format("test2256") def _test_format(unit, registry, **options): pf = PrettyFormatter(registry) return pf.format_unit(unit, "~", as_ratio=False) q = 2.3e-6 * ureg.m**3 / (ureg.s**2 * ureg.kg) assert f"{q:test2256}" == "2.3e-06 kg⁻¹·m³·s⁻²" assert f"{q:~P}" == "2.3×10⁻⁶ m³/kg/s²" def test_issue2256_2(): ureg = UnitRegistry() q = 2.3e-6 * ureg.m**3 / (ureg.s**2 * ureg.kg) assert f"{q:~P}" == "2.3×10⁻⁶ m³/kg/s²" assert f"{q:~^P}" == "2.3×10⁻⁶ kg⁻¹·m³·s⁻²" assert f"{q:^}" == "2.3e-06 kilogram ** -1 * meter ** 3 * second ** -2"