import copy import functools import logging import math import re import pytest from pint import ( DefinitionSyntaxError, DimensionalityError, RedefinitionError, UndefinedUnitError, ) from pint.compat import np from pint.registry import LazyRegistry, UnitRegistry from pint.testsuite import QuantityTestCase, helpers from pint.util import ParserHelper, UnitsContainer class TestUnit(QuantityTestCase): def test_creation(self): for arg in ("meter", UnitsContainer(meter=1), self.U_("m")): assert self.U_(arg)._units == UnitsContainer(meter=1) with pytest.raises(TypeError): self.U_(1) def test_deepcopy(self): x = self.U_(UnitsContainer(meter=1)) assert x == copy.deepcopy(x) def test_unit_repr(self): x = self.U_(UnitsContainer(meter=1)) assert str(x) == "meter" assert repr(x) == "" def test_unit_formatting(self, subtests): x = self.U_(UnitsContainer(meter=2, kilogram=1, second=-1)) for spec, result in ( ("{}", str(x)), ("{!s}", str(x)), ("{!r}", repr(x)), ( "{:L}", r"\frac{\mathrm{kilogram} \cdot \mathrm{meter}^{2}}{\mathrm{second}}", ), ("{:P}", "kilogram·meter²/second"), ("{:H}", "kilogram meter2/second"), ("{:C}", "kilogram*meter**2/second"), ("{:Lx}", r"\si[]{\kilo\gram\meter\squared\per\second}"), ("{:~}", "kg * m ** 2 / s"), ("{:L~}", r"\frac{\mathrm{kg} \cdot \mathrm{m}^{2}}{\mathrm{s}}"), ("{:P~}", "kg·m²/s"), ("{:H~}", "kg m2/s"), ("{:C~}", "kg*m**2/s"), ): with subtests.test(spec): assert spec.format(x) == result def test_unit_default_formatting(self, subtests): ureg = UnitRegistry() x = ureg.Unit(UnitsContainer(meter=2, kilogram=1, second=-1)) for spec, result in ( ( "L", r"\frac{\mathrm{kilogram} \cdot \mathrm{meter}^{2}}{\mathrm{second}}", ), ("P", "kilogram·meter²/second"), ("H", "kilogram meter2/second"), ("C", "kilogram*meter**2/second"), ("~", "kg * m ** 2 / s"), ("L~", r"\frac{\mathrm{kg} \cdot \mathrm{m}^{2}}{\mathrm{s}}"), ("P~", "kg·m²/s"), ("H~", "kg m2/s"), ("C~", "kg*m**2/s"), ): with subtests.test(spec): ureg.default_format = spec assert f"{x}" == result, f"Failed for {spec}, {result}" def test_unit_formatting_snake_case(self, subtests): # Test that snake_case units are escaped where appropriate ureg = UnitRegistry() x = ureg.Unit(UnitsContainer(oil_barrel=1)) for spec, result in ( ("L", r"\mathrm{oil\_barrel}"), ("P", "oil_barrel"), ("H", "oil_barrel"), ("C", "oil_barrel"), ("~", "oil_bbl"), ("L~", r"\mathrm{oil\_bbl}"), ("P~", "oil_bbl"), ("H~", "oil_bbl"), ("C~", "oil_bbl"), ): with subtests.test(spec): ureg.default_format = spec assert f"{x}" == result, f"Failed for {spec}, {result}" def test_unit_formatting_custom(self, monkeypatch): from pint import formatting, register_unit_format monkeypatch.setattr(formatting, "_FORMATTERS", formatting._FORMATTERS.copy()) @register_unit_format("new") def format_new(unit, **options): return "new format" ureg = UnitRegistry() assert "{:new}".format(ureg.m) == "new format" def test_ipython(self): alltext = [] class Pretty: @staticmethod def text(text): alltext.append(text) ureg = UnitRegistry() x = ureg.Unit(UnitsContainer(meter=2, kilogram=1, second=-1)) assert x._repr_html_() == "kilogram meter2/second" assert ( x._repr_latex_() == r"$\frac{\mathrm{kilogram} \cdot " r"\mathrm{meter}^{2}}{\mathrm{second}}$" ) x._repr_pretty_(Pretty, False) assert "".join(alltext) == "kilogram·meter²/second" ureg.default_format = "~" assert x._repr_html_() == "kg m2/s" assert ( x._repr_latex_() == r"$\frac{\mathrm{kg} \cdot \mathrm{m}^{2}}{\mathrm{s}}$" ) alltext = [] x._repr_pretty_(Pretty, False) assert "".join(alltext) == "kg·m²/s" def test_unit_mul(self): x = self.U_("m") assert x * 1 == self.Q_(1, "m") assert x * 0.5 == self.Q_(0.5, "m") assert x * self.Q_(1, "m") == self.Q_(1, "m**2") assert 1 * x == self.Q_(1, "m") def test_unit_div(self): x = self.U_("m") assert x / 1 == self.Q_(1, "m") assert x / 0.5 == self.Q_(2.0, "m") assert x / self.Q_(1, "m") == self.Q_(1) def test_unit_rdiv(self): x = self.U_("m") assert 1 / x == self.Q_(1, "1/m") def test_unit_pow(self): x = self.U_("m") assert x ** 2 == self.U_("m**2") def test_unit_hash(self): x = self.U_("m") assert hash(x) == hash(x._units) def test_unit_eqs(self): x = self.U_("m") assert x == self.U_("m") assert x != self.U_("cm") assert x == self.Q_(1, "m") assert x != self.Q_(2, "m") assert x == UnitsContainer({"meter": 1}) y = self.U_("cm/m") assert y == 0.01 assert self.U_("byte") == self.U_("byte") assert not (self.U_("byte") != self.U_("byte")) def test_unit_cmp(self): x = self.U_("m") assert x < self.U_("km") assert x > self.U_("mm") y = self.U_("m/mm") assert y > 1 assert y < 1e6 def test_dimensionality(self): x = self.U_("m") assert x.dimensionality == UnitsContainer({"[length]": 1}) def test_dimensionless(self): assert self.U_("m/mm").dimensionless assert not self.U_("m").dimensionless def test_unit_casting(self): assert int(self.U_("m/mm")) == 1000 assert float(self.U_("mm/m")) == 1e-3 assert complex(self.U_("mm/mm")) == 1 + 0j @helpers.requires_numpy def test_array_interface(self): import numpy as np x = self.U_("m") arr = np.ones(10) helpers.assert_quantity_equal(arr * x, self.Q_(arr, "m")) helpers.assert_quantity_equal(arr / x, self.Q_(arr, "1/m")) helpers.assert_quantity_equal(x / arr, self.Q_(arr, "m")) class TestRegistry(QuantityTestCase): @classmethod def setup_class(cls): super().setup_class() cls.ureg.autoconvert_offset_to_baseunit = False def test_base(self): ureg = UnitRegistry(None) ureg.define("meter = [length]") with pytest.raises(DefinitionSyntaxError): ureg.define("meter = [length]") with pytest.raises(TypeError): ureg.define(list()) ureg.define("degC = kelvin; offset: 273.15") def test_define(self): ureg = UnitRegistry(None) assert isinstance(dir(ureg), list) assert len(dir(ureg)) > 0 def test_load(self): import pkg_resources from pint import unit data = pkg_resources.resource_filename(unit.__name__, "default_en.txt") ureg1 = UnitRegistry() ureg2 = UnitRegistry(data) assert dir(ureg1) == dir(ureg2) with pytest.raises(ValueError): UnitRegistry(None).load_definitions("notexisting") def test_default_format(self): ureg = UnitRegistry() q = ureg.meter s1 = f"{q}" s2 = f"{q:~}" ureg.default_format = "~" s3 = f"{q}" assert s2 == s3 assert s1 != s3 assert ureg.default_format == "~" def test_iterate(self): ureg = UnitRegistry() assert "meter" in list(ureg) def test_parse_number(self): assert self.ureg.parse_expression("pi") == math.pi assert self.ureg.parse_expression("x", x=2) == 2 assert self.ureg.parse_expression("x", x=2.3) == 2.3 assert self.ureg.parse_expression("x * y", x=2.3, y=3) == 2.3 * 3 assert self.ureg.parse_expression("x", x=(1 + 1j)) == (1 + 1j) def test_parse_single(self): assert self.ureg.parse_expression("meter") == self.Q_( 1, UnitsContainer(meter=1.0) ) assert self.ureg.parse_expression("second") == self.Q_( 1, UnitsContainer(second=1.0) ) def test_parse_alias(self): assert self.ureg.parse_expression("metre") == self.Q_( 1, UnitsContainer(meter=1.0) ) def test_parse_plural(self): assert self.ureg.parse_expression("meters") == self.Q_( 1, UnitsContainer(meter=1.0) ) def test_parse_prefix(self): assert self.ureg.parse_expression("kilometer") == self.Q_( 1, UnitsContainer(kilometer=1.0) ) def test_parse_complex(self): assert self.ureg.parse_expression("kilometre") == self.Q_( 1, UnitsContainer(kilometer=1.0) ) assert self.ureg.parse_expression("kilometres") == self.Q_( 1, UnitsContainer(kilometer=1.0) ) def test_parse_mul_div(self): assert self.ureg.parse_expression("meter*meter") == self.Q_( 1, UnitsContainer(meter=2.0) ) assert self.ureg.parse_expression("meter**2") == self.Q_( 1, UnitsContainer(meter=2.0) ) assert self.ureg.parse_expression("meter*second") == self.Q_( 1, UnitsContainer(meter=1.0, second=1) ) assert self.ureg.parse_expression("meter/second") == self.Q_( 1, UnitsContainer(meter=1.0, second=-1) ) assert self.ureg.parse_expression("meter/second**2") == self.Q_( 1, UnitsContainer(meter=1.0, second=-2) ) def test_parse_pretty(self): assert self.ureg.parse_expression("meter/second²") == self.Q_( 1, UnitsContainer(meter=1.0, second=-2) ) assert self.ureg.parse_expression("m³/s³") == self.Q_( 1, UnitsContainer(meter=3.0, second=-3) ) assert self.ureg.parse_expression("meter² · second") == self.Q_( 1, UnitsContainer(meter=2.0, second=1) ) assert self.ureg.parse_expression("m²·s⁻²") == self.Q_( 1, UnitsContainer(meter=2, second=-2) ) assert self.ureg.parse_expression("meter⁰.⁵·second") == self.Q_( 1, UnitsContainer(meter=0.5, second=1) ) assert self.ureg.parse_expression("meter³⁷/second⁴.³²¹") == self.Q_( 1, UnitsContainer(meter=37, second=-4.321) ) def test_parse_factor(self): assert self.ureg.parse_expression("42*meter") == self.Q_( 42, UnitsContainer(meter=1.0) ) assert self.ureg.parse_expression("meter*42") == self.Q_( 42, UnitsContainer(meter=1.0) ) def test_rep_and_parse(self): q = self.Q_(1, "g/(m**2*s)") assert self.Q_(q.magnitude, str(q.units)) == q def test_as_delta(self): parse = self.ureg.parse_units assert parse("kelvin", as_delta=True) == UnitsContainer(kelvin=1) assert parse("kelvin", as_delta=False) == UnitsContainer(kelvin=1) assert parse("kelvin**(-1)", as_delta=True) == UnitsContainer(kelvin=-1) assert parse("kelvin**(-1)", as_delta=False) == UnitsContainer(kelvin=-1) assert parse("kelvin**2", as_delta=True) == UnitsContainer(kelvin=2) assert parse("kelvin**2", as_delta=False) == UnitsContainer(kelvin=2) assert parse("kelvin*meter", as_delta=True) == UnitsContainer(kelvin=1, meter=1) assert parse("kelvin*meter", as_delta=False) == UnitsContainer( kelvin=1, meter=1 ) @helpers.requires_numpy def test_parse_with_force_ndarray(self): ureg = UnitRegistry(force_ndarray=True) assert ureg.parse_expression("m * s ** -2").units == ureg.m / ureg.s ** 2 def test_parse_expression_with_preprocessor(self): # Add parsing of UDUNITS-style power self.ureg.preprocessors.append( functools.partial( re.sub, r"(?<=[A-Za-z])(?![A-Za-z])(?