1import copy 2import functools 3import logging 4import math 5import re 6 7import pytest 8 9from pint import ( 10 DefinitionSyntaxError, 11 DimensionalityError, 12 RedefinitionError, 13 UndefinedUnitError, 14) 15from pint.compat import np 16from pint.registry import LazyRegistry, UnitRegistry 17from pint.testsuite import QuantityTestCase, helpers 18from pint.util import ParserHelper, UnitsContainer 19 20 21class TestUnit(QuantityTestCase): 22 def test_creation(self): 23 for arg in ("meter", UnitsContainer(meter=1), self.U_("m")): 24 assert self.U_(arg)._units == UnitsContainer(meter=1) 25 with pytest.raises(TypeError): 26 self.U_(1) 27 28 def test_deepcopy(self): 29 x = self.U_(UnitsContainer(meter=1)) 30 assert x == copy.deepcopy(x) 31 32 def test_unit_repr(self): 33 x = self.U_(UnitsContainer(meter=1)) 34 assert str(x) == "meter" 35 assert repr(x) == "<Unit('meter')>" 36 37 def test_unit_formatting(self, subtests): 38 x = self.U_(UnitsContainer(meter=2, kilogram=1, second=-1)) 39 for spec, result in ( 40 ("{}", str(x)), 41 ("{!s}", str(x)), 42 ("{!r}", repr(x)), 43 ( 44 "{:L}", 45 r"\frac{\mathrm{kilogram} \cdot \mathrm{meter}^{2}}{\mathrm{second}}", 46 ), 47 ("{:P}", "kilogram·meter²/second"), 48 ("{:H}", "kilogram meter<sup>2</sup>/second"), 49 ("{:C}", "kilogram*meter**2/second"), 50 ("{:Lx}", r"\si[]{\kilo\gram\meter\squared\per\second}"), 51 ("{:~}", "kg * m ** 2 / s"), 52 ("{:L~}", r"\frac{\mathrm{kg} \cdot \mathrm{m}^{2}}{\mathrm{s}}"), 53 ("{:P~}", "kg·m²/s"), 54 ("{:H~}", "kg m<sup>2</sup>/s"), 55 ("{:C~}", "kg*m**2/s"), 56 ): 57 with subtests.test(spec): 58 assert spec.format(x) == result 59 60 def test_unit_default_formatting(self, subtests): 61 ureg = UnitRegistry() 62 x = ureg.Unit(UnitsContainer(meter=2, kilogram=1, second=-1)) 63 for spec, result in ( 64 ( 65 "L", 66 r"\frac{\mathrm{kilogram} \cdot \mathrm{meter}^{2}}{\mathrm{second}}", 67 ), 68 ("P", "kilogram·meter²/second"), 69 ("H", "kilogram meter<sup>2</sup>/second"), 70 ("C", "kilogram*meter**2/second"), 71 ("~", "kg * m ** 2 / s"), 72 ("L~", r"\frac{\mathrm{kg} \cdot \mathrm{m}^{2}}{\mathrm{s}}"), 73 ("P~", "kg·m²/s"), 74 ("H~", "kg m<sup>2</sup>/s"), 75 ("C~", "kg*m**2/s"), 76 ): 77 with subtests.test(spec): 78 ureg.default_format = spec 79 assert f"{x}" == result, f"Failed for {spec}, {result}" 80 81 def test_unit_formatting_snake_case(self, subtests): 82 # Test that snake_case units are escaped where appropriate 83 ureg = UnitRegistry() 84 x = ureg.Unit(UnitsContainer(oil_barrel=1)) 85 for spec, result in ( 86 ("L", r"\mathrm{oil\_barrel}"), 87 ("P", "oil_barrel"), 88 ("H", "oil_barrel"), 89 ("C", "oil_barrel"), 90 ("~", "oil_bbl"), 91 ("L~", r"\mathrm{oil\_bbl}"), 92 ("P~", "oil_bbl"), 93 ("H~", "oil_bbl"), 94 ("C~", "oil_bbl"), 95 ): 96 with subtests.test(spec): 97 ureg.default_format = spec 98 assert f"{x}" == result, f"Failed for {spec}, {result}" 99 100 def test_unit_formatting_custom(self, monkeypatch): 101 from pint import formatting, register_unit_format 102 103 monkeypatch.setattr(formatting, "_FORMATTERS", formatting._FORMATTERS.copy()) 104 105 @register_unit_format("new") 106 def format_new(unit, **options): 107 return "new format" 108 109 ureg = UnitRegistry() 110 111 assert "{:new}".format(ureg.m) == "new format" 112 113 def test_ipython(self): 114 alltext = [] 115 116 class Pretty: 117 @staticmethod 118 def text(text): 119 alltext.append(text) 120 121 ureg = UnitRegistry() 122 x = ureg.Unit(UnitsContainer(meter=2, kilogram=1, second=-1)) 123 assert x._repr_html_() == "kilogram meter<sup>2</sup>/second" 124 assert ( 125 x._repr_latex_() == r"$\frac{\mathrm{kilogram} \cdot " 126 r"\mathrm{meter}^{2}}{\mathrm{second}}$" 127 ) 128 x._repr_pretty_(Pretty, False) 129 assert "".join(alltext) == "kilogram·meter²/second" 130 ureg.default_format = "~" 131 assert x._repr_html_() == "kg m<sup>2</sup>/s" 132 assert ( 133 x._repr_latex_() == r"$\frac{\mathrm{kg} \cdot \mathrm{m}^{2}}{\mathrm{s}}$" 134 ) 135 alltext = [] 136 x._repr_pretty_(Pretty, False) 137 assert "".join(alltext) == "kg·m²/s" 138 139 def test_unit_mul(self): 140 x = self.U_("m") 141 assert x * 1 == self.Q_(1, "m") 142 assert x * 0.5 == self.Q_(0.5, "m") 143 assert x * self.Q_(1, "m") == self.Q_(1, "m**2") 144 assert 1 * x == self.Q_(1, "m") 145 146 def test_unit_div(self): 147 x = self.U_("m") 148 assert x / 1 == self.Q_(1, "m") 149 assert x / 0.5 == self.Q_(2.0, "m") 150 assert x / self.Q_(1, "m") == self.Q_(1) 151 152 def test_unit_rdiv(self): 153 x = self.U_("m") 154 assert 1 / x == self.Q_(1, "1/m") 155 156 def test_unit_pow(self): 157 x = self.U_("m") 158 assert x ** 2 == self.U_("m**2") 159 160 def test_unit_hash(self): 161 x = self.U_("m") 162 assert hash(x) == hash(x._units) 163 164 def test_unit_eqs(self): 165 x = self.U_("m") 166 assert x == self.U_("m") 167 assert x != self.U_("cm") 168 169 assert x == self.Q_(1, "m") 170 assert x != self.Q_(2, "m") 171 172 assert x == UnitsContainer({"meter": 1}) 173 174 y = self.U_("cm/m") 175 assert y == 0.01 176 177 assert self.U_("byte") == self.U_("byte") 178 assert not (self.U_("byte") != self.U_("byte")) 179 180 def test_unit_cmp(self): 181 182 x = self.U_("m") 183 assert x < self.U_("km") 184 assert x > self.U_("mm") 185 186 y = self.U_("m/mm") 187 assert y > 1 188 assert y < 1e6 189 190 def test_dimensionality(self): 191 192 x = self.U_("m") 193 assert x.dimensionality == UnitsContainer({"[length]": 1}) 194 195 def test_dimensionless(self): 196 197 assert self.U_("m/mm").dimensionless 198 assert not self.U_("m").dimensionless 199 200 def test_unit_casting(self): 201 202 assert int(self.U_("m/mm")) == 1000 203 assert float(self.U_("mm/m")) == 1e-3 204 assert complex(self.U_("mm/mm")) == 1 + 0j 205 206 @helpers.requires_numpy 207 def test_array_interface(self): 208 import numpy as np 209 210 x = self.U_("m") 211 arr = np.ones(10) 212 helpers.assert_quantity_equal(arr * x, self.Q_(arr, "m")) 213 helpers.assert_quantity_equal(arr / x, self.Q_(arr, "1/m")) 214 helpers.assert_quantity_equal(x / arr, self.Q_(arr, "m")) 215 216 217class TestRegistry(QuantityTestCase): 218 @classmethod 219 def setup_class(cls): 220 super().setup_class() 221 cls.ureg.autoconvert_offset_to_baseunit = False 222 223 def test_base(self): 224 ureg = UnitRegistry(None) 225 ureg.define("meter = [length]") 226 with pytest.raises(DefinitionSyntaxError): 227 ureg.define("meter = [length]") 228 with pytest.raises(TypeError): 229 ureg.define(list()) 230 ureg.define("degC = kelvin; offset: 273.15") 231 232 def test_define(self): 233 ureg = UnitRegistry(None) 234 assert isinstance(dir(ureg), list) 235 assert len(dir(ureg)) > 0 236 237 def test_load(self): 238 import pkg_resources 239 240 from pint import unit 241 242 data = pkg_resources.resource_filename(unit.__name__, "default_en.txt") 243 ureg1 = UnitRegistry() 244 ureg2 = UnitRegistry(data) 245 assert dir(ureg1) == dir(ureg2) 246 with pytest.raises(ValueError): 247 UnitRegistry(None).load_definitions("notexisting") 248 249 def test_default_format(self): 250 ureg = UnitRegistry() 251 q = ureg.meter 252 s1 = f"{q}" 253 s2 = f"{q:~}" 254 ureg.default_format = "~" 255 s3 = f"{q}" 256 assert s2 == s3 257 assert s1 != s3 258 assert ureg.default_format == "~" 259 260 def test_iterate(self): 261 ureg = UnitRegistry() 262 assert "meter" in list(ureg) 263 264 def test_parse_number(self): 265 assert self.ureg.parse_expression("pi") == math.pi 266 assert self.ureg.parse_expression("x", x=2) == 2 267 assert self.ureg.parse_expression("x", x=2.3) == 2.3 268 assert self.ureg.parse_expression("x * y", x=2.3, y=3) == 2.3 * 3 269 assert self.ureg.parse_expression("x", x=(1 + 1j)) == (1 + 1j) 270 271 def test_parse_single(self): 272 assert self.ureg.parse_expression("meter") == self.Q_( 273 1, UnitsContainer(meter=1.0) 274 ) 275 assert self.ureg.parse_expression("second") == self.Q_( 276 1, UnitsContainer(second=1.0) 277 ) 278 279 def test_parse_alias(self): 280 assert self.ureg.parse_expression("metre") == self.Q_( 281 1, UnitsContainer(meter=1.0) 282 ) 283 284 def test_parse_plural(self): 285 assert self.ureg.parse_expression("meters") == self.Q_( 286 1, UnitsContainer(meter=1.0) 287 ) 288 289 def test_parse_prefix(self): 290 assert self.ureg.parse_expression("kilometer") == self.Q_( 291 1, UnitsContainer(kilometer=1.0) 292 ) 293 294 def test_parse_complex(self): 295 assert self.ureg.parse_expression("kilometre") == self.Q_( 296 1, UnitsContainer(kilometer=1.0) 297 ) 298 assert self.ureg.parse_expression("kilometres") == self.Q_( 299 1, UnitsContainer(kilometer=1.0) 300 ) 301 302 def test_parse_mul_div(self): 303 assert self.ureg.parse_expression("meter*meter") == self.Q_( 304 1, UnitsContainer(meter=2.0) 305 ) 306 assert self.ureg.parse_expression("meter**2") == self.Q_( 307 1, UnitsContainer(meter=2.0) 308 ) 309 assert self.ureg.parse_expression("meter*second") == self.Q_( 310 1, UnitsContainer(meter=1.0, second=1) 311 ) 312 assert self.ureg.parse_expression("meter/second") == self.Q_( 313 1, UnitsContainer(meter=1.0, second=-1) 314 ) 315 assert self.ureg.parse_expression("meter/second**2") == self.Q_( 316 1, UnitsContainer(meter=1.0, second=-2) 317 ) 318 319 def test_parse_pretty(self): 320 assert self.ureg.parse_expression("meter/second²") == self.Q_( 321 1, UnitsContainer(meter=1.0, second=-2) 322 ) 323 assert self.ureg.parse_expression("m³/s³") == self.Q_( 324 1, UnitsContainer(meter=3.0, second=-3) 325 ) 326 assert self.ureg.parse_expression("meter² · second") == self.Q_( 327 1, UnitsContainer(meter=2.0, second=1) 328 ) 329 assert self.ureg.parse_expression("m²·s⁻²") == self.Q_( 330 1, UnitsContainer(meter=2, second=-2) 331 ) 332 assert self.ureg.parse_expression("meter⁰.⁵·second") == self.Q_( 333 1, UnitsContainer(meter=0.5, second=1) 334 ) 335 assert self.ureg.parse_expression("meter³⁷/second⁴.³²¹") == self.Q_( 336 1, UnitsContainer(meter=37, second=-4.321) 337 ) 338 339 def test_parse_factor(self): 340 assert self.ureg.parse_expression("42*meter") == self.Q_( 341 42, UnitsContainer(meter=1.0) 342 ) 343 assert self.ureg.parse_expression("meter*42") == self.Q_( 344 42, UnitsContainer(meter=1.0) 345 ) 346 347 def test_rep_and_parse(self): 348 q = self.Q_(1, "g/(m**2*s)") 349 assert self.Q_(q.magnitude, str(q.units)) == q 350 351 def test_as_delta(self): 352 parse = self.ureg.parse_units 353 assert parse("kelvin", as_delta=True) == UnitsContainer(kelvin=1) 354 assert parse("kelvin", as_delta=False) == UnitsContainer(kelvin=1) 355 assert parse("kelvin**(-1)", as_delta=True) == UnitsContainer(kelvin=-1) 356 assert parse("kelvin**(-1)", as_delta=False) == UnitsContainer(kelvin=-1) 357 assert parse("kelvin**2", as_delta=True) == UnitsContainer(kelvin=2) 358 assert parse("kelvin**2", as_delta=False) == UnitsContainer(kelvin=2) 359 assert parse("kelvin*meter", as_delta=True) == UnitsContainer(kelvin=1, meter=1) 360 assert parse("kelvin*meter", as_delta=False) == UnitsContainer( 361 kelvin=1, meter=1 362 ) 363 364 @helpers.requires_numpy 365 def test_parse_with_force_ndarray(self): 366 ureg = UnitRegistry(force_ndarray=True) 367 368 assert ureg.parse_expression("m * s ** -2").units == ureg.m / ureg.s ** 2 369 370 def test_parse_expression_with_preprocessor(self): 371 # Add parsing of UDUNITS-style power 372 self.ureg.preprocessors.append( 373 functools.partial( 374 re.sub, 375 r"(?<=[A-Za-z])(?![A-Za-z])(?<![0-9\-][eE])(?<![0-9\-])(?=[0-9\-])", 376 "**", 377 ) 378 ) 379 # Test equality 380 assert self.ureg.parse_expression("42 m2") == self.Q_( 381 42, UnitsContainer(meter=2.0) 382 ) 383 assert self.ureg.parse_expression("1e6 Hz s-2") == self.Q_( 384 1e6, UnitsContainer(second=-3.0) 385 ) 386 assert self.ureg.parse_expression("3 metre3") == self.Q_( 387 3, UnitsContainer(meter=3.0) 388 ) 389 # Clean up and test previously expected value 390 self.ureg.preprocessors.pop() 391 assert self.ureg.parse_expression("1e6 Hz s-2") == self.Q_( 392 999998.0, UnitsContainer() 393 ) 394 395 def test_parse_unit_with_preprocessor(self): 396 # Add parsing of UDUNITS-style power 397 self.ureg.preprocessors.append( 398 functools.partial( 399 re.sub, 400 r"(?<=[A-Za-z])(?![A-Za-z])(?<![0-9\-][eE])(?<![0-9\-])(?=[0-9\-])", 401 "**", 402 ) 403 ) 404 # Test equality 405 assert self.ureg.parse_units("m2") == UnitsContainer(meter=2.0) 406 assert self.ureg.parse_units("m-2") == UnitsContainer(meter=-2.0) 407 # Clean up 408 self.ureg.preprocessors.pop() 409 410 def test_name(self): 411 with pytest.raises(UndefinedUnitError): 412 self.ureg.get_name("asdf") 413 414 def test_symbol(self): 415 with pytest.raises(UndefinedUnitError): 416 self.ureg.get_symbol("asdf") 417 418 assert self.ureg.get_symbol("meter") == "m" 419 assert self.ureg.get_symbol("second") == "s" 420 assert self.ureg.get_symbol("hertz") == "Hz" 421 422 assert self.ureg.get_symbol("kilometer") == "km" 423 assert self.ureg.get_symbol("megahertz") == "MHz" 424 assert self.ureg.get_symbol("millisecond") == "ms" 425 426 def test_imperial_symbol(self): 427 assert self.ureg.get_symbol("inch") == "in" 428 assert self.ureg.get_symbol("foot") == "ft" 429 assert self.ureg.get_symbol("inches") == "in" 430 assert self.ureg.get_symbol("feet") == "ft" 431 assert self.ureg.get_symbol("international_foot") == "ft" 432 assert self.ureg.get_symbol("international_inch") == "in" 433 434 def test_pint(self): 435 assert self.ureg.pint < self.ureg.liter 436 assert self.ureg.pint < self.ureg.imperial_pint 437 438 def test_wraps(self): 439 def func(x): 440 return x 441 442 ureg = self.ureg 443 444 with pytest.raises(TypeError): 445 ureg.wraps((3 * ureg.meter, [None])) 446 with pytest.raises(TypeError): 447 ureg.wraps((None, [3 * ureg.meter])) 448 449 f0 = ureg.wraps(None, [None])(func) 450 assert f0(3.0) == 3.0 451 452 f0 = ureg.wraps(None, None)(func) 453 assert f0(3.0) == 3.0 454 455 f1 = ureg.wraps(None, ["meter"])(func) 456 with pytest.raises(ValueError): 457 f1(3.0) 458 assert f1(3.0 * ureg.centimeter) == 0.03 459 assert f1(3.0 * ureg.meter) == 3.0 460 with pytest.raises(DimensionalityError): 461 f1(3 * ureg.second) 462 463 f1b = ureg.wraps(None, [ureg.meter])(func) 464 with pytest.raises(ValueError): 465 f1b(3.0) 466 assert f1b(3.0 * ureg.centimeter) == 0.03 467 assert f1b(3.0 * ureg.meter) == 3.0 468 with pytest.raises(DimensionalityError): 469 f1b(3 * ureg.second) 470 471 f1c = ureg.wraps("meter", [ureg.meter])(func) 472 assert f1c(3.0 * ureg.centimeter) == 0.03 * ureg.meter 473 assert f1c(3.0 * ureg.meter) == 3.0 * ureg.meter 474 with pytest.raises(DimensionalityError): 475 f1c(3 * ureg.second) 476 477 f1d = ureg.wraps(ureg.meter, [ureg.meter])(func) 478 assert f1d(3.0 * ureg.centimeter) == 0.03 * ureg.meter 479 assert f1d(3.0 * ureg.meter) == 3.0 * ureg.meter 480 with pytest.raises(DimensionalityError): 481 f1d(3 * ureg.second) 482 483 f1 = ureg.wraps(None, "meter")(func) 484 with pytest.raises(ValueError): 485 f1(3.0) 486 assert f1(3.0 * ureg.centimeter) == 0.03 487 assert f1(3.0 * ureg.meter) == 3.0 488 with pytest.raises(DimensionalityError): 489 f1(3 * ureg.second) 490 491 f2 = ureg.wraps("centimeter", ["meter"])(func) 492 with pytest.raises(ValueError): 493 f2(3.0) 494 assert f2(3.0 * ureg.centimeter) == 0.03 * ureg.centimeter 495 assert f2(3.0 * ureg.meter) == 3 * ureg.centimeter 496 497 f3 = ureg.wraps("centimeter", ["meter"], strict=False)(func) 498 assert f3(3) == 3 * ureg.centimeter 499 assert f3(3.0 * ureg.centimeter) == 0.03 * ureg.centimeter 500 assert f3(3.0 * ureg.meter) == 3.0 * ureg.centimeter 501 502 def gfunc(x, y): 503 return x + y 504 505 g0 = ureg.wraps(None, [None, None])(gfunc) 506 assert g0(3, 1) == 4 507 508 g1 = ureg.wraps(None, ["meter", "centimeter"])(gfunc) 509 with pytest.raises(ValueError): 510 g1(3 * ureg.meter, 1) 511 assert g1(3 * ureg.meter, 1 * ureg.centimeter) == 4 512 assert g1(3 * ureg.meter, 1 * ureg.meter) == 3 + 100 513 514 def hfunc(x, y): 515 return x, y 516 517 h0 = ureg.wraps(None, [None, None])(hfunc) 518 assert h0(3, 1) == (3, 1) 519 520 h1 = ureg.wraps(["meter", "centimeter"], [None, None])(hfunc) 521 assert h1(3, 1) == [3 * ureg.meter, 1 * ureg.cm] 522 523 h2 = ureg.wraps(("meter", "centimeter"), [None, None])(hfunc) 524 assert h2(3, 1) == (3 * ureg.meter, 1 * ureg.cm) 525 526 h3 = ureg.wraps((None,), (None, None))(hfunc) 527 assert h3(3, 1) == (3, 1) 528 529 def test_wrap_referencing(self): 530 531 ureg = self.ureg 532 533 def gfunc(x, y): 534 return x + y 535 536 def gfunc2(x, y): 537 return x ** 2 + y 538 539 def gfunc3(x, y): 540 return x ** 2 * y 541 542 rst = 3.0 * ureg.meter + 1.0 * ureg.centimeter 543 544 g0 = ureg.wraps("=A", ["=A", "=A"])(gfunc) 545 assert g0(3.0 * ureg.meter, 1.0 * ureg.centimeter) == rst.to("meter") 546 assert g0(3, 1) == 4 547 548 g1 = ureg.wraps("=A", ["=A", "=A"])(gfunc) 549 assert g1(3.0 * ureg.meter, 1.0 * ureg.centimeter) == rst.to("centimeter") 550 551 g2 = ureg.wraps("=A", ["=A", "=A"])(gfunc) 552 assert g2(3.0 * ureg.meter, 1.0 * ureg.centimeter) == rst.to("meter") 553 554 g3 = ureg.wraps("=A**2", ["=A", "=A**2"])(gfunc2) 555 a = 3.0 * ureg.meter 556 b = (2.0 * ureg.centimeter) ** 2 557 assert g3(a, b) == gfunc2(a, b) 558 assert g3(3, 2) == gfunc2(3, 2) 559 560 g4 = ureg.wraps("=A**2 * B", ["=A", "=B"])(gfunc3) 561 assert g4(3.0 * ureg.meter, 2.0 * ureg.second) == ureg( 562 "(3*meter)**2 * 2 *second" 563 ) 564 assert g4(3.0 * ureg.meter, 2.0) == ureg("(3*meter)**2 * 2") 565 assert g4(3.0, 2.0 * ureg.second) == ureg("3**2 * 2 * second") 566 567 def test_check(self): 568 def func(x): 569 return x 570 571 ureg = self.ureg 572 573 f0 = ureg.check("[length]")(func) 574 with pytest.raises(DimensionalityError): 575 f0(3.0) 576 assert f0(3.0 * ureg.centimeter) == 0.03 * ureg.meter 577 with pytest.raises(DimensionalityError): 578 f0(3.0 * ureg.kilogram) 579 580 f0b = ureg.check(ureg.meter)(func) 581 with pytest.raises(DimensionalityError): 582 f0b(3.0) 583 assert f0b(3.0 * ureg.centimeter) == 0.03 * ureg.meter 584 with pytest.raises(DimensionalityError): 585 f0b(3.0 * ureg.kilogram) 586 587 def gfunc(x, y): 588 return x / y 589 590 g0 = ureg.check(None, None)(gfunc) 591 assert g0(6, 2) == 3 592 assert g0(6 * ureg.parsec, 2) == 3 * ureg.parsec 593 594 g1 = ureg.check("[speed]", "[time]")(gfunc) 595 with pytest.raises(DimensionalityError): 596 g1(3.0, 1) 597 with pytest.raises(DimensionalityError): 598 g1(1 * ureg.parsec, 1 * ureg.angstrom) 599 with pytest.raises(TypeError): 600 g1(1 * ureg.km / ureg.hour, 1 * ureg.hour, 3.0) 601 assert ( 602 g1(3.6 * ureg.km / ureg.hour, 1 * ureg.second) 603 == 1 * ureg.meter / ureg.second ** 2 604 ) 605 606 with pytest.raises(TypeError): 607 ureg.check("[speed]")(gfunc) 608 with pytest.raises(TypeError): 609 ureg.check("[speed]", "[time]", "[mass]")(gfunc) 610 611 def test_to_ref_vs_to(self): 612 self.ureg.autoconvert_offset_to_baseunit = True 613 q = 8.0 * self.ureg.inch 614 t = 8.0 * self.ureg.degF 615 dt = 8.0 * self.ureg.delta_degF 616 assert q.to("yard").magnitude == self.ureg._units[ 617 "inch" 618 ].converter.to_reference(8.0) 619 assert t.to("kelvin").magnitude == self.ureg._units[ 620 "degF" 621 ].converter.to_reference(8.0) 622 assert dt.to("kelvin").magnitude == self.ureg._units[ 623 "delta_degF" 624 ].converter.to_reference(8.0) 625 626 def test_redefinition(self, caplog): 627 d = UnitRegistry().define 628 629 with caplog.at_level(logging.DEBUG): 630 d("meter = [fruits]") 631 d("kilo- = 1000") 632 d("[speed] = [vegetables]") 633 634 # aliases 635 d("bla = 3.2 meter = inch") 636 d("myk- = 1000 = kilo-") 637 638 assert len(caplog.records) == 5 639 640 def test_convert_parse_str(self): 641 ureg = self.ureg 642 assert ureg.convert(1, "meter", "inch") == ureg.convert( 643 1, UnitsContainer(meter=1), UnitsContainer(inch=1) 644 ) 645 646 @helpers.requires_numpy 647 def test_convert_inplace(self): 648 ureg = self.ureg 649 650 # Conversions with single units take a different codepath than 651 # Conversions with more than one unit. 652 src_dst1 = UnitsContainer(meter=1), UnitsContainer(inch=1) 653 src_dst2 = UnitsContainer(meter=1, second=-1), UnitsContainer(inch=1, minute=-1) 654 for src, dst in (src_dst1, src_dst2): 655 v = (ureg.convert(1, src, dst),) 656 657 a = np.ones((3, 1)) 658 ac = np.ones((3, 1)) 659 660 r1 = ureg.convert(a, src, dst) 661 np.testing.assert_allclose(r1, v * ac) 662 assert r1 is not a 663 664 r2 = ureg.convert(a, src, dst, inplace=True) 665 np.testing.assert_allclose(r2, v * ac) 666 assert r2 is a 667 668 def test_repeated_convert(self): 669 # Because of caching, repeated conversions were failing. 670 self.ureg.convert(1, "m", "ft") 671 self.ureg.convert(1, "m", "ft") 672 673 def test_singular_SI_prefix_convert(self): 674 # Fix for issue 156 675 self.ureg.convert(1, "mm", "m") 676 self.ureg.convert(1, "ms", "s") 677 self.ureg.convert(1, "m", "mm") 678 self.ureg.convert(1, "s", "ms") 679 680 def test_parse_units(self): 681 ureg = self.ureg 682 assert ureg.parse_units("") == ureg.Unit("") 683 with pytest.raises(ValueError): 684 ureg.parse_units("2 * meter") 685 686 def test_parse_string_pattern(self): 687 ureg = self.ureg 688 assert ureg.parse_pattern("10'11", r"{foot}'{inch}") == [ 689 ureg.Quantity(10.0, "foot"), 690 ureg.Quantity(11.0, "inch"), 691 ] 692 693 def test_parse_string_pattern_no_preprocess(self): 694 """Were preprocessors enabled, this would be interpreted as 10*11, not 695 two separate units, and thus cause the parsing to fail""" 696 ureg = self.ureg 697 assert ureg.parse_pattern("10 11", r"{kg} {lb}") == [ 698 ureg.Quantity(10.0, "kilogram"), 699 ureg.Quantity(11.0, "pound"), 700 ] 701 702 def test_parse_pattern_many_results(self): 703 ureg = self.ureg 704 assert ureg.parse_pattern( 705 "1.5kg or 2kg will be fine, if you do not have 3kg", 706 r"{kg}kg", 707 many=True, 708 ) == [ 709 [ureg.Quantity(1.5, "kilogram")], 710 [ureg.Quantity(2.0, "kilogram")], 711 [ureg.Quantity(3.0, "kilogram")], 712 ] 713 714 def test_parse_pattern_many_results_two_units(self): 715 ureg = self.ureg 716 assert ureg.parse_pattern("10'10 or 10'11", "{foot}'{inch}", many=True) == [ 717 [ureg.Quantity(10.0, "foot"), ureg.Quantity(10.0, "inch")], 718 [ureg.Quantity(10.0, "foot"), ureg.Quantity(11.0, "inch")], 719 ] 720 721 def test_case_sensitivity(self): 722 ureg = self.ureg 723 # Default 724 with pytest.raises(UndefinedUnitError): 725 ureg.parse_units("Meter") 726 with pytest.raises(UndefinedUnitError): 727 ureg.parse_units("j") 728 # Force True 729 with pytest.raises(UndefinedUnitError): 730 ureg.parse_units("Meter", case_sensitive=True) 731 with pytest.raises(UndefinedUnitError): 732 ureg.parse_units("j", case_sensitive=True) 733 # Force False 734 assert ureg.parse_units("Meter", case_sensitive=False) == UnitsContainer( 735 meter=1 736 ) 737 assert ureg.parse_units("j", case_sensitive=False) == UnitsContainer(joule=1) 738 739 740class TestCaseInsensitiveRegistry(QuantityTestCase): 741 742 kwargs = dict(case_sensitive=False) 743 744 def test_case_sensitivity(self): 745 ureg = self.ureg 746 # Default 747 assert ureg.parse_units("Meter") == UnitsContainer(meter=1) 748 assert ureg.parse_units("j") == UnitsContainer(joule=1) 749 # Force True 750 with pytest.raises(UndefinedUnitError): 751 ureg.parse_units("Meter", case_sensitive=True) 752 with pytest.raises(UndefinedUnitError): 753 ureg.parse_units("j", case_sensitive=True) 754 # Force False 755 assert ureg.parse_units("Meter", case_sensitive=False) == UnitsContainer( 756 meter=1 757 ) 758 assert ureg.parse_units("j", case_sensitive=False) == UnitsContainer(joule=1) 759 760 761class TestCompatibleUnits(QuantityTestCase): 762 def _test(self, input_units): 763 gd = self.ureg.get_dimensionality 764 dim = gd(input_units) 765 equiv = self.ureg.get_compatible_units(input_units) 766 for eq in equiv: 767 assert gd(eq) == dim 768 assert equiv == self.ureg.get_compatible_units(dim) 769 770 def _test2(self, units1, units2): 771 equiv1 = self.ureg.get_compatible_units(units1) 772 equiv2 = self.ureg.get_compatible_units(units2) 773 assert equiv1 == equiv2 774 775 def test_many(self): 776 self._test(self.ureg.meter) 777 self._test(self.ureg.seconds) 778 self._test(self.ureg.newton) 779 self._test(self.ureg.kelvin) 780 781 def test_context_sp(self): 782 783 gd = self.ureg.get_dimensionality 784 785 # length, frequency, energy 786 valid = [ 787 gd(self.ureg.meter), 788 gd(self.ureg.hertz), 789 gd(self.ureg.joule), 790 1 / gd(self.ureg.meter), 791 ] 792 793 with self.ureg.context("sp"): 794 equiv = self.ureg.get_compatible_units(self.ureg.meter) 795 result = set() 796 for eq in equiv: 797 dim = gd(eq) 798 result.add(dim) 799 assert dim in valid 800 801 assert len(result) == len(valid) 802 803 def test_get_base_units(self): 804 ureg = UnitRegistry() 805 assert ureg.get_base_units("") == (1, ureg.Unit("")) 806 assert ureg.get_base_units("pi") == (math.pi, ureg.Unit("")) 807 assert ureg.get_base_units("ln10") == (math.log(10), ureg.Unit("")) 808 assert ureg.get_base_units("meter") == ureg.get_base_units( 809 ParserHelper(meter=1) 810 ) 811 812 def test_get_compatible_units(self): 813 ureg = UnitRegistry() 814 assert ureg.get_compatible_units("") == frozenset() 815 assert ureg.get_compatible_units("meter") == ureg.get_compatible_units( 816 ParserHelper(meter=1) 817 ) 818 819 820class TestRegistryWithDefaultRegistry(TestRegistry): 821 @classmethod 822 def setup_class(cls): 823 from pint import _DEFAULT_REGISTRY 824 825 cls.ureg = _DEFAULT_REGISTRY 826 cls.Q_ = cls.ureg.Quantity 827 828 def test_lazy(self): 829 x = LazyRegistry() 830 x.test = "test" 831 assert isinstance(x, UnitRegistry) 832 y = LazyRegistry() 833 y("meter") 834 assert isinstance(y, UnitRegistry) 835 836 def test_redefinition(self): 837 d = self.ureg.define 838 with pytest.raises(DefinitionSyntaxError): 839 d("meter = [time]") 840 with pytest.raises(RedefinitionError): 841 d("meter = [newdim]") 842 with pytest.raises(RedefinitionError): 843 d("kilo- = 1000") 844 with pytest.raises(RedefinitionError): 845 d("[speed] = [length]") 846 847 # aliases 848 assert "inch" in self.ureg._units 849 with pytest.raises(RedefinitionError): 850 d("bla = 3.2 meter = inch") 851 with pytest.raises(RedefinitionError): 852 d("myk- = 1000 = kilo-") 853 854 855class TestConvertWithOffset(QuantityTestCase): 856 857 # The dicts in convert_with_offset are used to create a UnitsContainer. 858 # We create UnitsContainer to avoid any auto-conversion of units. 859 convert_with_offset = [ 860 (({"degC": 1}, {"degC": 1}), 10), 861 (({"degC": 1}, {"kelvin": 1}), 283.15), 862 (({"degC": 1}, {"degC": 1, "millimeter": 1, "meter": -1}), "error"), 863 (({"degC": 1}, {"kelvin": 1, "millimeter": 1, "meter": -1}), 283150), 864 (({"kelvin": 1}, {"degC": 1}), -263.15), 865 (({"kelvin": 1}, {"kelvin": 1}), 10), 866 (({"kelvin": 1}, {"degC": 1, "millimeter": 1, "meter": -1}), "error"), 867 (({"kelvin": 1}, {"kelvin": 1, "millimeter": 1, "meter": -1}), 10000), 868 (({"degC": 1, "millimeter": 1, "meter": -1}, {"degC": 1}), "error"), 869 (({"degC": 1, "millimeter": 1, "meter": -1}, {"kelvin": 1}), "error"), 870 ( 871 ( 872 {"degC": 1, "millimeter": 1, "meter": -1}, 873 {"degC": 1, "millimeter": 1, "meter": -1}, 874 ), 875 10, 876 ), 877 ( 878 ( 879 {"degC": 1, "millimeter": 1, "meter": -1}, 880 {"kelvin": 1, "millimeter": 1, "meter": -1}, 881 ), 882 "error", 883 ), 884 (({"kelvin": 1, "millimeter": 1, "meter": -1}, {"degC": 1}), -273.14), 885 (({"kelvin": 1, "millimeter": 1, "meter": -1}, {"kelvin": 1}), 0.01), 886 ( 887 ( 888 {"kelvin": 1, "millimeter": 1, "meter": -1}, 889 {"degC": 1, "millimeter": 1, "meter": -1}, 890 ), 891 "error", 892 ), 893 ( 894 ( 895 {"kelvin": 1, "millimeter": 1, "meter": -1}, 896 {"kelvin": 1, "millimeter": 1, "meter": -1}, 897 ), 898 10, 899 ), 900 (({"degC": 2}, {"kelvin": 2}), "error"), 901 (({"degC": 1, "degF": 1}, {"kelvin": 2}), "error"), 902 (({"degC": 1, "kelvin": 1}, {"kelvin": 2}), "error"), 903 ] 904 905 @pytest.mark.parametrize(("input_tuple", "expected"), convert_with_offset) 906 def test_to_and_from_offset_units(self, input_tuple, expected): 907 src, dst = input_tuple 908 src, dst = UnitsContainer(src), UnitsContainer(dst) 909 value = 10.0 910 convert = self.ureg.convert 911 if isinstance(expected, str): 912 with pytest.raises(DimensionalityError): 913 convert(value, src, dst) 914 if src != dst: 915 with pytest.raises(DimensionalityError): 916 convert(value, dst, src) 917 else: 918 helpers.assert_quantity_almost_equal( 919 convert(value, src, dst), expected, atol=0.001 920 ) 921 if src != dst: 922 helpers.assert_quantity_almost_equal( 923 convert(expected, dst, src), value, atol=0.001 924 ) 925 926 def test_alias(self): 927 # Use load_definitions 928 ureg = UnitRegistry( 929 [ 930 "canonical = [] = can = alias1 = alias2\n", 931 # overlapping aliases 932 "@alias canonical = alias2 = alias3\n", 933 # Against another alias 934 "@alias alias3 = alias4\n", 935 ] 936 ) 937 938 # Use define 939 ureg.define("@alias canonical = alias5") 940 941 # Test that new aliases work 942 # Test that pre-existing aliases and symbol are not eliminated 943 for a in ("can", "alias1", "alias2", "alias3", "alias4", "alias5"): 944 assert ureg.Unit(a) == ureg.Unit("canonical") 945 946 # Test that aliases defined multiple times are not duplicated 947 assert ureg._units["canonical"].aliases == ( 948 "alias1", 949 "alias2", 950 "alias3", 951 "alias4", 952 "alias5", 953 ) 954 955 # Define against unknown name 956 with pytest.raises(KeyError): 957 ureg.define("@alias notexist = something") 958