1import copy 2import math 3import operator as op 4import pickle 5from decimal import Decimal 6from fractions import Fraction 7 8import pytest 9 10from pint import DimensionalityError, OffsetUnitCalculusError, UnitRegistry 11from pint.testsuite import QuantityTestCase, helpers 12from pint.unit import UnitsContainer 13 14 15class FakeWrapper: 16 # Used in test_upcast_type_rejection_on_creation 17 def __init__(self, q): 18 self.q = q 19 20 21class NonIntTypeQuantityTestCase(QuantityTestCase): 22 def assert_quantity_almost_equal( 23 self, first, second, rtol="1e-07", atol="0", msg=None 24 ): 25 26 if isinstance(first, self.Q_): 27 assert isinstance(first.m, (self.NON_INT_TYPE, int)) 28 else: 29 assert isinstance(first, (self.NON_INT_TYPE, int)) 30 31 if isinstance(second, self.Q_): 32 assert isinstance(second.m, (self.NON_INT_TYPE, int)) 33 else: 34 assert isinstance(second, (self.NON_INT_TYPE, int)) 35 super().assert_quantity_almost_equal( 36 first, second, self.NON_INT_TYPE(rtol), self.NON_INT_TYPE(atol), msg 37 ) 38 39 def QP_(self, value, units): 40 assert isinstance(value, str) 41 return self.Q_(self.NON_INT_TYPE(value), units) 42 43 44class _TestBasic: 45 def test_quantity_creation(self): 46 47 value = self.NON_INT_TYPE("4.2") 48 49 for args in ( 50 (value, "meter"), 51 (value, UnitsContainer(meter=1)), 52 (value, self.ureg.meter), 53 ("4.2*meter",), 54 ("4.2/meter**(-1)",), 55 (self.Q_(value, "meter"),), 56 ): 57 x = self.Q_(*args) 58 assert x.magnitude == value 59 assert x.units == self.ureg.UnitsContainer(meter=1) 60 61 x = self.Q_(value, UnitsContainer(length=1)) 62 y = self.Q_(x) 63 assert x.magnitude == y.magnitude 64 assert x.units == y.units 65 assert x is not y 66 67 x = self.Q_(value, None) 68 assert x.magnitude == value 69 assert x.units == UnitsContainer() 70 71 with self.capture_log() as buffer: 72 assert value * self.ureg.meter == self.Q_( 73 value, self.NON_INT_TYPE("2") * self.ureg.meter 74 ) 75 assert len(buffer) == 1 76 77 def test_quantity_comparison(self): 78 x = self.QP_("4.2", "meter") 79 y = self.QP_("4.2", "meter") 80 z = self.QP_("5", "meter") 81 j = self.QP_("5", "meter*meter") 82 83 # identity for single object 84 assert x == x 85 assert not (x != x) 86 87 # identity for multiple objects with same value 88 assert x == y 89 assert not (x != y) 90 91 assert x <= y 92 assert x >= y 93 assert not (x < y) 94 assert not (x > y) 95 96 assert not (x == z) 97 assert x != z 98 assert x < z 99 100 assert z != j 101 102 assert z != j 103 assert self.QP_("0", "meter") == self.QP_("0", "centimeter") 104 assert self.QP_("0", "meter") != self.QP_("0", "second") 105 106 assert self.QP_("10", "meter") < self.QP_("5", "kilometer") 107 108 def test_quantity_comparison_convert(self): 109 assert self.QP_("1000", "millimeter") == self.QP_("1", "meter") 110 assert self.QP_("1000", "millimeter/min") == self.Q_( 111 self.NON_INT_TYPE("1000") / self.NON_INT_TYPE("60"), "millimeter/s" 112 ) 113 114 def test_quantity_hash(self): 115 x = self.QP_("4.2", "meter") 116 x2 = self.QP_("4200", "millimeter") 117 y = self.QP_("2", "second") 118 z = self.QP_("0.5", "hertz") 119 assert hash(x) == hash(x2) 120 121 # Dimensionless equality 122 assert hash(y * z) == hash(1.0) 123 124 # Dimensionless equality from a different unit registry 125 ureg2 = UnitRegistry(force_ndarray=self.FORCE_NDARRAY) 126 y2 = ureg2.Quantity(self.NON_INT_TYPE("2"), "second") 127 z2 = ureg2.Quantity(self.NON_INT_TYPE("0.5"), "hertz") 128 assert hash(y * z) == hash(y2 * z2) 129 130 def test_to_base_units(self): 131 x = self.Q_("1*inch") 132 helpers.assert_quantity_almost_equal( 133 x.to_base_units(), self.QP_("0.0254", "meter") 134 ) 135 x = self.Q_("1*inch*inch") 136 helpers.assert_quantity_almost_equal( 137 x.to_base_units(), 138 self.Q_( 139 self.NON_INT_TYPE("0.0254") ** self.NON_INT_TYPE("2.0"), "meter*meter" 140 ), 141 ) 142 x = self.Q_("1*inch/minute") 143 helpers.assert_quantity_almost_equal( 144 x.to_base_units(), 145 self.Q_( 146 self.NON_INT_TYPE("0.0254") / self.NON_INT_TYPE("60"), "meter/second" 147 ), 148 ) 149 150 def test_convert(self): 151 helpers.assert_quantity_almost_equal( 152 self.Q_("2 inch").to("meter"), 153 self.Q_(self.NON_INT_TYPE("2") * self.NON_INT_TYPE("0.0254"), "meter"), 154 ) 155 helpers.assert_quantity_almost_equal( 156 self.Q_("2 meter").to("inch"), 157 self.Q_(self.NON_INT_TYPE("2") / self.NON_INT_TYPE("0.0254"), "inch"), 158 ) 159 helpers.assert_quantity_almost_equal( 160 self.Q_("2 sidereal_year").to("second"), self.QP_("63116297.5325", "second") 161 ) 162 helpers.assert_quantity_almost_equal( 163 self.Q_("2.54 centimeter/second").to("inch/second"), 164 self.Q_("1 inch/second"), 165 ) 166 assert round(abs(self.Q_("2.54 centimeter").to("inch").magnitude - 1), 7) == 0 167 assert ( 168 round(abs(self.Q_("2 second").to("millisecond").magnitude - 2000), 7) == 0 169 ) 170 171 def test_convert_from(self): 172 x = self.Q_("2*inch") 173 meter = self.ureg.meter 174 175 # from quantity 176 helpers.assert_quantity_almost_equal( 177 meter.from_(x), 178 self.Q_(self.NON_INT_TYPE("2") * self.NON_INT_TYPE("0.0254"), "meter"), 179 ) 180 helpers.assert_quantity_almost_equal( 181 meter.m_from(x), self.NON_INT_TYPE("2") * self.NON_INT_TYPE("0.0254") 182 ) 183 184 # from unit 185 helpers.assert_quantity_almost_equal( 186 meter.from_(self.ureg.inch), self.QP_("0.0254", "meter") 187 ) 188 helpers.assert_quantity_almost_equal( 189 meter.m_from(self.ureg.inch), self.NON_INT_TYPE("0.0254") 190 ) 191 192 # from number 193 helpers.assert_quantity_almost_equal( 194 meter.from_(2, strict=False), self.QP_("2", "meter") 195 ) 196 helpers.assert_quantity_almost_equal( 197 meter.m_from(self.NON_INT_TYPE("2"), strict=False), self.NON_INT_TYPE("2") 198 ) 199 200 # from number (strict mode) 201 with pytest.raises(ValueError): 202 meter.from_(self.NON_INT_TYPE("2")) 203 with pytest.raises(ValueError): 204 meter.m_from(self.NON_INT_TYPE("2")) 205 206 def test_context_attr(self): 207 assert self.ureg.meter == self.QP_("1", "meter") 208 209 def test_both_symbol(self): 210 assert self.QP_("2", "ms") == self.QP_("2", "millisecond") 211 assert self.QP_("2", "cm") == self.QP_("2", "centimeter") 212 213 def test_dimensionless_units(self): 214 twopi = self.NON_INT_TYPE("2") * self.ureg.pi 215 assert ( 216 round(abs(self.QP_("360", "degree").to("radian").magnitude - twopi), 7) == 0 217 ) 218 assert round(abs(self.Q_(twopi, "radian") - self.QP_("360", "degree")), 7) == 0 219 assert self.QP_("1", "radian").dimensionality == UnitsContainer() 220 assert self.QP_("1", "radian").dimensionless 221 assert not self.QP_("1", "radian").unitless 222 223 assert self.QP_("1", "meter") / self.QP_("1", "meter") == 1 224 assert (self.QP_("1", "meter") / self.QP_("1", "mm")).to("") == 1000 225 226 assert self.Q_(10) // self.QP_("360", "degree") == 1 227 assert self.QP_("400", "degree") // self.Q_(twopi) == 1 228 assert self.QP_("400", "degree") // twopi == 1 229 assert 7 // self.QP_("360", "degree") == 1 230 231 def test_offset(self): 232 helpers.assert_quantity_almost_equal( 233 self.QP_("0", "kelvin").to("kelvin"), self.QP_("0", "kelvin") 234 ) 235 helpers.assert_quantity_almost_equal( 236 self.QP_("0", "degC").to("kelvin"), self.QP_("273.15", "kelvin") 237 ) 238 helpers.assert_quantity_almost_equal( 239 self.QP_("0", "degF").to("kelvin"), 240 self.QP_("255.372222", "kelvin"), 241 rtol=0.01, 242 ) 243 244 helpers.assert_quantity_almost_equal( 245 self.QP_("100", "kelvin").to("kelvin"), self.QP_("100", "kelvin") 246 ) 247 helpers.assert_quantity_almost_equal( 248 self.QP_("100", "degC").to("kelvin"), self.QP_("373.15", "kelvin") 249 ) 250 helpers.assert_quantity_almost_equal( 251 self.QP_("100", "degF").to("kelvin"), 252 self.QP_("310.92777777", "kelvin"), 253 rtol=0.01, 254 ) 255 256 helpers.assert_quantity_almost_equal( 257 self.QP_("0", "kelvin").to("degC"), self.QP_("-273.15", "degC") 258 ) 259 helpers.assert_quantity_almost_equal( 260 self.QP_("100", "kelvin").to("degC"), self.QP_("-173.15", "degC") 261 ) 262 helpers.assert_quantity_almost_equal( 263 self.QP_("0", "kelvin").to("degF"), self.QP_("-459.67", "degF"), rtol=0.01 264 ) 265 helpers.assert_quantity_almost_equal( 266 self.QP_("100", "kelvin").to("degF"), self.QP_("-279.67", "degF"), rtol=0.01 267 ) 268 269 helpers.assert_quantity_almost_equal( 270 self.QP_("32", "degF").to("degC"), self.QP_("0", "degC"), atol=0.01 271 ) 272 helpers.assert_quantity_almost_equal( 273 self.QP_("100", "degC").to("degF"), self.QP_("212", "degF"), atol=0.01 274 ) 275 276 helpers.assert_quantity_almost_equal( 277 self.QP_("54", "degF").to("degC"), self.QP_("12.2222", "degC"), atol=0.01 278 ) 279 helpers.assert_quantity_almost_equal( 280 self.QP_("12", "degC").to("degF"), self.QP_("53.6", "degF"), atol=0.01 281 ) 282 283 helpers.assert_quantity_almost_equal( 284 self.QP_("12", "kelvin").to("degC"), self.QP_("-261.15", "degC"), atol=0.01 285 ) 286 helpers.assert_quantity_almost_equal( 287 self.QP_("12", "degC").to("kelvin"), self.QP_("285.15", "kelvin"), atol=0.01 288 ) 289 290 helpers.assert_quantity_almost_equal( 291 self.QP_("12", "kelvin").to("degR"), self.QP_("21.6", "degR"), atol=0.01 292 ) 293 helpers.assert_quantity_almost_equal( 294 self.QP_("12", "degR").to("kelvin"), 295 self.QP_("6.66666667", "kelvin"), 296 atol=0.01, 297 ) 298 299 helpers.assert_quantity_almost_equal( 300 self.QP_("12", "degC").to("degR"), self.QP_("513.27", "degR"), atol=0.01 301 ) 302 helpers.assert_quantity_almost_equal( 303 self.QP_("12", "degR").to("degC"), 304 self.QP_("-266.483333", "degC"), 305 atol=0.01, 306 ) 307 308 def test_offset_delta(self): 309 helpers.assert_quantity_almost_equal( 310 self.QP_("0", "delta_degC").to("kelvin"), self.QP_("0", "kelvin") 311 ) 312 helpers.assert_quantity_almost_equal( 313 self.QP_("0", "delta_degF").to("kelvin"), self.QP_("0", "kelvin"), rtol=0.01 314 ) 315 316 helpers.assert_quantity_almost_equal( 317 self.QP_("100", "kelvin").to("delta_degC"), self.QP_("100", "delta_degC") 318 ) 319 helpers.assert_quantity_almost_equal( 320 self.QP_("100", "kelvin").to("delta_degF"), 321 self.QP_("180", "delta_degF"), 322 rtol=0.01, 323 ) 324 helpers.assert_quantity_almost_equal( 325 self.QP_("100", "delta_degF").to("kelvin"), 326 self.QP_("55.55555556", "kelvin"), 327 rtol=0.01, 328 ) 329 helpers.assert_quantity_almost_equal( 330 self.QP_("100", "delta_degC").to("delta_degF"), 331 self.QP_("180", "delta_degF"), 332 rtol=0.01, 333 ) 334 helpers.assert_quantity_almost_equal( 335 self.QP_("100", "delta_degF").to("delta_degC"), 336 self.QP_("55.55555556", "delta_degC"), 337 rtol=0.01, 338 ) 339 340 helpers.assert_quantity_almost_equal( 341 self.QP_("12.3", "delta_degC").to("delta_degF"), 342 self.QP_("22.14", "delta_degF"), 343 rtol=0.01, 344 ) 345 346 def test_pickle(self): 347 for protocol in range(pickle.HIGHEST_PROTOCOL + 1): 348 for magnitude, unit in ( 349 ("32", ""), 350 ("2.4", ""), 351 ("32", "m/s"), 352 ("2.4", "m/s"), 353 ): 354 with self.subTest(protocol=protocol, magnitude=magnitude, unit=unit): 355 q1 = self.QP_(magnitude, unit) 356 q2 = pickle.loads(pickle.dumps(q1, protocol)) 357 assert q1 == q2 358 359 def test_notiter(self): 360 # Verify that iter() crashes immediately, without needing to draw any 361 # element from it, if the magnitude isn't iterable 362 x = self.QP_("1", "m") 363 with pytest.raises(TypeError): 364 iter(x) 365 366 367class _TestQuantityBasicMath: 368 369 FORCE_NDARRAY = False 370 371 def _test_inplace(self, operator, value1, value2, expected_result, unit=None): 372 if isinstance(value1, str): 373 value1 = self.Q_(value1) 374 if isinstance(value2, str): 375 value2 = self.Q_(value2) 376 if isinstance(expected_result, str): 377 expected_result = self.Q_(expected_result) 378 379 if unit is not None: 380 value1 = value1 * unit 381 value2 = value2 * unit 382 expected_result = expected_result * unit 383 384 value1 = copy.copy(value1) 385 value2 = copy.copy(value2) 386 id1 = id(value1) 387 id2 = id(value2) 388 value1 = operator(value1, value2) 389 value2_cpy = copy.copy(value2) 390 helpers.assert_quantity_almost_equal(value1, expected_result) 391 assert id1 == id(value1) 392 helpers.assert_quantity_almost_equal(value2, value2_cpy) 393 assert id2 == id(value2) 394 395 def _test_not_inplace(self, operator, value1, value2, expected_result, unit=None): 396 if isinstance(value1, str): 397 value1 = self.Q_(value1) 398 if isinstance(value2, str): 399 value2 = self.Q_(value2) 400 if isinstance(expected_result, str): 401 expected_result = self.Q_(expected_result) 402 403 if unit is not None: 404 value1 = value1 * unit 405 value2 = value2 * unit 406 expected_result = expected_result * unit 407 408 id1 = id(value1) 409 id2 = id(value2) 410 411 value1_cpy = copy.copy(value1) 412 value2_cpy = copy.copy(value2) 413 414 result = operator(value1, value2) 415 416 helpers.assert_quantity_almost_equal(expected_result, result) 417 helpers.assert_quantity_almost_equal(value1, value1_cpy) 418 helpers.assert_quantity_almost_equal(value2, value2_cpy) 419 assert id(result) != id1 420 assert id(result) != id2 421 422 def _test_quantity_add_sub(self, unit, func): 423 x = self.Q_(unit, "centimeter") 424 y = self.Q_(unit, "inch") 425 z = self.Q_(unit, "second") 426 a = self.Q_(unit, None) 427 428 func(op.add, x, x, self.Q_(unit + unit, "centimeter")) 429 func( 430 op.add, x, y, self.Q_(unit + self.NON_INT_TYPE("2.54") * unit, "centimeter") 431 ) 432 func( 433 op.add, 434 y, 435 x, 436 self.Q_(unit + unit / (self.NON_INT_TYPE("2.54") * unit), "inch"), 437 ) 438 func(op.add, a, unit, self.Q_(unit + unit, None)) 439 with pytest.raises(DimensionalityError): 440 op.add(self.NON_INT_TYPE("10"), x) 441 with pytest.raises(DimensionalityError): 442 op.add(x, self.NON_INT_TYPE("10")) 443 with pytest.raises(DimensionalityError): 444 op.add(x, z) 445 446 func(op.sub, x, x, self.Q_(unit - unit, "centimeter")) 447 func( 448 op.sub, x, y, self.Q_(unit - self.NON_INT_TYPE("2.54") * unit, "centimeter") 449 ) 450 func( 451 op.sub, 452 y, 453 x, 454 self.Q_(unit - unit / (self.NON_INT_TYPE("2.54") * unit), "inch"), 455 ) 456 func(op.sub, a, unit, self.Q_(unit - unit, None)) 457 with pytest.raises(DimensionalityError): 458 op.sub(self.NON_INT_TYPE("10"), x) 459 with pytest.raises(DimensionalityError): 460 op.sub(x, self.NON_INT_TYPE("10")) 461 with pytest.raises(DimensionalityError): 462 op.sub(x, z) 463 464 def _test_quantity_iadd_isub(self, unit, func): 465 x = self.Q_(unit, "centimeter") 466 y = self.Q_(unit, "inch") 467 z = self.Q_(unit, "second") 468 a = self.Q_(unit, None) 469 470 func(op.iadd, x, x, self.Q_(unit + unit, "centimeter")) 471 func( 472 op.iadd, 473 x, 474 y, 475 self.Q_(unit + self.NON_INT_TYPE("2.54") * unit, "centimeter"), 476 ) 477 func(op.iadd, y, x, self.Q_(unit + unit / self.NON_INT_TYPE("2.54"), "inch")) 478 func(op.iadd, a, unit, self.Q_(unit + unit, None)) 479 with pytest.raises(DimensionalityError): 480 op.iadd(self.NON_INT_TYPE("10"), x) 481 with pytest.raises(DimensionalityError): 482 op.iadd(x, self.NON_INT_TYPE("10")) 483 with pytest.raises(DimensionalityError): 484 op.iadd(x, z) 485 486 func(op.isub, x, x, self.Q_(unit - unit, "centimeter")) 487 func(op.isub, x, y, self.Q_(unit - self.NON_INT_TYPE("2.54"), "centimeter")) 488 func(op.isub, y, x, self.Q_(unit - unit / self.NON_INT_TYPE("2.54"), "inch")) 489 func(op.isub, a, unit, self.Q_(unit - unit, None)) 490 with pytest.raises(DimensionalityError): 491 op.sub(self.NON_INT_TYPE("10"), x) 492 with pytest.raises(DimensionalityError): 493 op.sub(x, self.NON_INT_TYPE("10")) 494 with pytest.raises(DimensionalityError): 495 op.sub(x, z) 496 497 def _test_quantity_mul_div(self, unit, func): 498 func(op.mul, unit * self.NON_INT_TYPE("10"), "4.2*meter", "42*meter", unit) 499 func(op.mul, "4.2*meter", unit * self.NON_INT_TYPE("10"), "42*meter", unit) 500 func(op.mul, "4.2*meter", "10*inch", "42*meter*inch", unit) 501 func(op.truediv, unit * self.NON_INT_TYPE("42"), "4.2*meter", "10/meter", unit) 502 func( 503 op.truediv, "4.2*meter", unit * self.NON_INT_TYPE("10"), "0.42*meter", unit 504 ) 505 func(op.truediv, "4.2*meter", "10*inch", "0.42*meter/inch", unit) 506 507 def _test_quantity_imul_idiv(self, unit, func): 508 # func(op.imul, 10.0, '4.2*meter', '42*meter') 509 func(op.imul, "4.2*meter", self.NON_INT_TYPE("10"), "42*meter", unit) 510 func(op.imul, "4.2*meter", "10*inch", "42*meter*inch", unit) 511 # func(op.truediv, 42, '4.2*meter', '10/meter') 512 func( 513 op.itruediv, "4.2*meter", unit * self.NON_INT_TYPE("10"), "0.42*meter", unit 514 ) 515 func(op.itruediv, "4.2*meter", "10*inch", "0.42*meter/inch", unit) 516 517 def _test_quantity_floordiv(self, unit, func): 518 a = self.Q_("10*meter") 519 b = self.Q_("3*second") 520 with pytest.raises(DimensionalityError): 521 op.floordiv(a, b) 522 with pytest.raises(DimensionalityError): 523 op.floordiv(self.NON_INT_TYPE("3"), b) 524 with pytest.raises(DimensionalityError): 525 op.floordiv(a, self.NON_INT_TYPE("3")) 526 with pytest.raises(DimensionalityError): 527 op.ifloordiv(a, b) 528 with pytest.raises(DimensionalityError): 529 op.ifloordiv(self.NON_INT_TYPE("3"), b) 530 with pytest.raises(DimensionalityError): 531 op.ifloordiv(a, self.NON_INT_TYPE("3")) 532 func( 533 op.floordiv, 534 unit * self.NON_INT_TYPE("10"), 535 "4.2*meter/meter", 536 self.NON_INT_TYPE("2"), 537 unit, 538 ) 539 func(op.floordiv, "10*meter", "4.2*inch", self.NON_INT_TYPE("93"), unit) 540 541 def _test_quantity_mod(self, unit, func): 542 a = self.Q_("10*meter") 543 b = self.Q_("3*second") 544 with pytest.raises(DimensionalityError): 545 op.mod(a, b) 546 with pytest.raises(DimensionalityError): 547 op.mod(3, b) 548 with pytest.raises(DimensionalityError): 549 op.mod(a, 3) 550 with pytest.raises(DimensionalityError): 551 op.imod(a, b) 552 with pytest.raises(DimensionalityError): 553 op.imod(3, b) 554 with pytest.raises(DimensionalityError): 555 op.imod(a, 3) 556 func( 557 op.mod, 558 unit * self.NON_INT_TYPE("10"), 559 "4.2*meter/meter", 560 self.NON_INT_TYPE("1.6"), 561 unit, 562 ) 563 564 def _test_quantity_ifloordiv(self, unit, func): 565 func( 566 op.ifloordiv, 567 self.NON_INT_TYPE("10"), 568 "4.2*meter/meter", 569 self.NON_INT_TYPE("2"), 570 unit, 571 ) 572 func(op.ifloordiv, "10*meter", "4.2*inch", self.NON_INT_TYPE("93"), unit) 573 574 def _test_quantity_divmod_one(self, a, b): 575 if isinstance(a, str): 576 a = self.Q_(a) 577 if isinstance(b, str): 578 b = self.Q_(b) 579 580 q, r = divmod(a, b) 581 assert q == a // b 582 assert r == a % b 583 helpers.assert_quantity_equal(a, (q * b) + r) 584 assert q == math.floor(q) 585 if b > (0 * b): 586 assert (0 * b) <= r < b 587 else: 588 assert (0 * b) >= r > b 589 if isinstance(a, self.Q_): 590 assert r.units == a.units 591 else: 592 assert r.unitless 593 assert q.unitless 594 595 copy_a = copy.copy(a) 596 a %= b 597 assert a == r 598 copy_a //= b 599 assert copy_a == q 600 601 def _test_quantity_divmod(self): 602 self._test_quantity_divmod_one("10*meter", "4.2*inch") 603 604 # Disabling these tests as it yields different results without Quantities 605 # >>> from decimal import Decimal as D 606 # >>> divmod(-D('100'), D('3')) 607 # (Decimal('-33'), Decimal('-1')) 608 # >>> divmod(-100, 3) 609 # (-34, 2) 610 611 # self._test_quantity_divmod_one("-10*meter", "4.2*inch") 612 # self._test_quantity_divmod_one("-10*meter", "-4.2*inch") 613 # self._test_quantity_divmod_one("10*meter", "-4.2*inch") 614 615 self._test_quantity_divmod_one("400*degree", "3") 616 self._test_quantity_divmod_one("4", "180 degree") 617 self._test_quantity_divmod_one(4, "180 degree") 618 self._test_quantity_divmod_one("20", 4) 619 self._test_quantity_divmod_one("300*degree", "100 degree") 620 621 a = self.Q_("10*meter") 622 b = self.Q_("3*second") 623 with pytest.raises(DimensionalityError): 624 divmod(a, b) 625 with pytest.raises(DimensionalityError): 626 divmod(3, b) 627 with pytest.raises(DimensionalityError): 628 divmod(a, 3) 629 630 def _test_numeric(self, unit, ifunc): 631 self._test_quantity_add_sub(unit, self._test_not_inplace) 632 self._test_quantity_iadd_isub(unit, ifunc) 633 self._test_quantity_mul_div(unit, self._test_not_inplace) 634 self._test_quantity_imul_idiv(unit, ifunc) 635 self._test_quantity_floordiv(unit, self._test_not_inplace) 636 self._test_quantity_mod(unit, self._test_not_inplace) 637 self._test_quantity_divmod() 638 # self._test_quantity_ifloordiv(unit, ifunc) 639 640 def test_quantity_abs_round(self): 641 642 value = self.NON_INT_TYPE("4.2") 643 x = self.Q_(-value, "meter") 644 y = self.Q_(value, "meter") 645 646 for fun in (abs, round, op.pos, op.neg): 647 zx = self.Q_(fun(x.magnitude), "meter") 648 zy = self.Q_(fun(y.magnitude), "meter") 649 rx = fun(x) 650 ry = fun(y) 651 assert rx == zx, "while testing {0}".format(fun) 652 assert ry == zy, "while testing {0}".format(fun) 653 assert rx is not zx, "while testing {0}".format(fun) 654 assert ry is not zy, "while testing {0}".format(fun) 655 656 def test_quantity_float_complex(self): 657 x = self.QP_("-4.2", None) 658 y = self.QP_("4.2", None) 659 z = self.QP_("1", "meter") 660 for fun in (float, complex): 661 assert fun(x) == fun(x.magnitude) 662 assert fun(y) == fun(y.magnitude) 663 with pytest.raises(DimensionalityError): 664 fun(z) 665 666 def test_not_inplace(self): 667 self._test_numeric(self.NON_INT_TYPE("1.0"), self._test_not_inplace) 668 669 670class _TestOffsetUnitMath: 671 @classmethod 672 def setup_class(cls): 673 cls.ureg.autoconvert_offset_to_baseunit = False 674 cls.ureg.default_as_delta = True 675 676 additions = [ 677 # --- input tuple -------------------- | -- expected result -- 678 ((("100", "kelvin"), ("10", "kelvin")), ("110", "kelvin")), 679 ((("100", "kelvin"), ("10", "degC")), "error"), 680 ((("100", "kelvin"), ("10", "degF")), "error"), 681 ((("100", "kelvin"), ("10", "degR")), ("105.56", "kelvin")), 682 ((("100", "kelvin"), ("10", "delta_degC")), ("110", "kelvin")), 683 ((("100", "kelvin"), ("10", "delta_degF")), ("105.56", "kelvin")), 684 ((("100", "degC"), ("10", "kelvin")), "error"), 685 ((("100", "degC"), ("10", "degC")), "error"), 686 ((("100", "degC"), ("10", "degF")), "error"), 687 ((("100", "degC"), ("10", "degR")), "error"), 688 ((("100", "degC"), ("10", "delta_degC")), ("110", "degC")), 689 ((("100", "degC"), ("10", "delta_degF")), ("105.56", "degC")), 690 ((("100", "degF"), ("10", "kelvin")), "error"), 691 ((("100", "degF"), ("10", "degC")), "error"), 692 ((("100", "degF"), ("10", "degF")), "error"), 693 ((("100", "degF"), ("10", "degR")), "error"), 694 ((("100", "degF"), ("10", "delta_degC")), ("118", "degF")), 695 ((("100", "degF"), ("10", "delta_degF")), ("110", "degF")), 696 ((("100", "degR"), ("10", "kelvin")), ("118", "degR")), 697 ((("100", "degR"), ("10", "degC")), "error"), 698 ((("100", "degR"), ("10", "degF")), "error"), 699 ((("100", "degR"), ("10", "degR")), ("110", "degR")), 700 ((("100", "degR"), ("10", "delta_degC")), ("118", "degR")), 701 ((("100", "degR"), ("10", "delta_degF")), ("110", "degR")), 702 ((("100", "delta_degC"), ("10", "kelvin")), ("110", "kelvin")), 703 ((("100", "delta_degC"), ("10", "degC")), ("110", "degC")), 704 ((("100", "delta_degC"), ("10", "degF")), ("190", "degF")), 705 ((("100", "delta_degC"), ("10", "degR")), ("190", "degR")), 706 ((("100", "delta_degC"), ("10", "delta_degC")), ("110", "delta_degC")), 707 ((("100", "delta_degC"), ("10", "delta_degF")), ("105.56", "delta_degC")), 708 ((("100", "delta_degF"), ("10", "kelvin")), ("65.56", "kelvin")), 709 ((("100", "delta_degF"), ("10", "degC")), ("65.56", "degC")), 710 ((("100", "delta_degF"), ("10", "degF")), ("110", "degF")), 711 ((("100", "delta_degF"), ("10", "degR")), ("110", "degR")), 712 ((("100", "delta_degF"), ("10", "delta_degC")), ("118", "delta_degF")), 713 ((("100", "delta_degF"), ("10", "delta_degF")), ("110", "delta_degF")), 714 ] 715 716 @pytest.mark.parametrize(("input", "expected_output"), additions) 717 def test_addition(self, input_tuple, expected): 718 self.ureg.autoconvert_offset_to_baseunit = False 719 qin1, qin2 = input_tuple 720 q1, q2 = self.QP_(*qin1), self.QP_(*qin2) 721 # update input tuple with new values to have correct values on failure 722 input_tuple = q1, q2 723 if expected == "error": 724 with pytest.raises(OffsetUnitCalculusError): 725 op.add(q1, q2) 726 else: 727 expected = self.QP_(*expected) 728 assert op.add(q1, q2).units == expected.units 729 helpers.assert_quantity_almost_equal(op.add(q1, q2), expected, atol="0.01") 730 731 subtractions = [ 732 ((("100", "kelvin"), ("10", "kelvin")), ("90", "kelvin")), 733 ((("100", "kelvin"), ("10", "degC")), ("-183.15", "kelvin")), 734 ((("100", "kelvin"), ("10", "degF")), ("-160.93", "kelvin")), 735 ((("100", "kelvin"), ("10", "degR")), ("94.44", "kelvin")), 736 ((("100", "kelvin"), ("10", "delta_degC")), ("90", "kelvin")), 737 ((("100", "kelvin"), ("10", "delta_degF")), ("94.44", "kelvin")), 738 ((("100", "degC"), ("10", "kelvin")), ("363.15", "delta_degC")), 739 ((("100", "degC"), ("10", "degC")), ("90", "delta_degC")), 740 ((("100", "degC"), ("10", "degF")), ("112.22", "delta_degC")), 741 ((("100", "degC"), ("10", "degR")), ("367.59", "delta_degC")), 742 ((("100", "degC"), ("10", "delta_degC")), ("90", "degC")), 743 ((("100", "degC"), ("10", "delta_degF")), ("94.44", "degC")), 744 ((("100", "degF"), ("10", "kelvin")), ("541.67", "delta_degF")), 745 ((("100", "degF"), ("10", "degC")), ("50", "delta_degF")), 746 ((("100", "degF"), ("10", "degF")), ("90", "delta_degF")), 747 ((("100", "degF"), ("10", "degR")), ("549.67", "delta_degF")), 748 ((("100", "degF"), ("10", "delta_degC")), ("82", "degF")), 749 ((("100", "degF"), ("10", "delta_degF")), ("90", "degF")), 750 ((("100", "degR"), ("10", "kelvin")), ("82", "degR")), 751 ((("100", "degR"), ("10", "degC")), ("-409.67", "degR")), 752 ((("100", "degR"), ("10", "degF")), ("-369.67", "degR")), 753 ((("100", "degR"), ("10", "degR")), ("90", "degR")), 754 ((("100", "degR"), ("10", "delta_degC")), ("82", "degR")), 755 ((("100", "degR"), ("10", "delta_degF")), ("90", "degR")), 756 ((("100", "delta_degC"), ("10", "kelvin")), ("90", "kelvin")), 757 ((("100", "delta_degC"), ("10", "degC")), ("90", "degC")), 758 ((("100", "delta_degC"), ("10", "degF")), ("170", "degF")), 759 ((("100", "delta_degC"), ("10", "degR")), ("170", "degR")), 760 ((("100", "delta_degC"), ("10", "delta_degC")), ("90", "delta_degC")), 761 ((("100", "delta_degC"), ("10", "delta_degF")), ("94.44", "delta_degC")), 762 ((("100", "delta_degF"), ("10", "kelvin")), ("45.56", "kelvin")), 763 ((("100", "delta_degF"), ("10", "degC")), ("45.56", "degC")), 764 ((("100", "delta_degF"), ("10", "degF")), ("90", "degF")), 765 ((("100", "delta_degF"), ("10", "degR")), ("90", "degR")), 766 ((("100", "delta_degF"), ("10", "delta_degC")), ("82", "delta_degF")), 767 ((("100", "delta_degF"), ("10", "delta_degF")), ("90", "delta_degF")), 768 ] 769 770 @pytest.mark.parametrize(("input", "expected_output"), subtractions) 771 def test_subtraction(self, input_tuple, expected): 772 self.ureg.autoconvert_offset_to_baseunit = False 773 qin1, qin2 = input_tuple 774 q1, q2 = self.QP_(*qin1), self.QP_(*qin2) 775 input_tuple = q1, q2 776 if expected == "error": 777 with pytest.raises(OffsetUnitCalculusError): 778 op.sub(q1, q2) 779 else: 780 expected = self.QP_(*expected) 781 assert op.sub(q1, q2).units == expected.units 782 helpers.assert_quantity_almost_equal(op.sub(q1, q2), expected, atol=0.01) 783 784 multiplications = [ 785 ((("100", "kelvin"), ("10", "kelvin")), ("1000", "kelvin**2")), 786 ((("100", "kelvin"), ("10", "degC")), "error"), 787 ((("100", "kelvin"), ("10", "degF")), "error"), 788 ((("100", "kelvin"), ("10", "degR")), ("1000", "kelvin*degR")), 789 ((("100", "kelvin"), ("10", "delta_degC")), ("1000", "kelvin*delta_degC")), 790 ((("100", "kelvin"), ("10", "delta_degF")), ("1000", "kelvin*delta_degF")), 791 ((("100", "degC"), ("10", "kelvin")), "error"), 792 ((("100", "degC"), ("10", "degC")), "error"), 793 ((("100", "degC"), ("10", "degF")), "error"), 794 ((("100", "degC"), ("10", "degR")), "error"), 795 ((("100", "degC"), ("10", "delta_degC")), "error"), 796 ((("100", "degC"), ("10", "delta_degF")), "error"), 797 ((("100", "degF"), ("10", "kelvin")), "error"), 798 ((("100", "degF"), ("10", "degC")), "error"), 799 ((("100", "degF"), ("10", "degF")), "error"), 800 ((("100", "degF"), ("10", "degR")), "error"), 801 ((("100", "degF"), ("10", "delta_degC")), "error"), 802 ((("100", "degF"), ("10", "delta_degF")), "error"), 803 ((("100", "degR"), ("10", "kelvin")), ("1000", "degR*kelvin")), 804 ((("100", "degR"), ("10", "degC")), "error"), 805 ((("100", "degR"), ("10", "degF")), "error"), 806 ((("100", "degR"), ("10", "degR")), ("1000", "degR**2")), 807 ((("100", "degR"), ("10", "delta_degC")), ("1000", "degR*delta_degC")), 808 ((("100", "degR"), ("10", "delta_degF")), ("1000", "degR*delta_degF")), 809 ((("100", "delta_degC"), ("10", "kelvin")), ("1000", "delta_degC*kelvin")), 810 ((("100", "delta_degC"), ("10", "degC")), "error"), 811 ((("100", "delta_degC"), ("10", "degF")), "error"), 812 ((("100", "delta_degC"), ("10", "degR")), ("1000", "delta_degC*degR")), 813 ((("100", "delta_degC"), ("10", "delta_degC")), ("1000", "delta_degC**2")), 814 ( 815 (("100", "delta_degC"), ("10", "delta_degF")), 816 ("1000", "delta_degC*delta_degF"), 817 ), 818 ((("100", "delta_degF"), ("10", "kelvin")), ("1000", "delta_degF*kelvin")), 819 ((("100", "delta_degF"), ("10", "degC")), "error"), 820 ((("100", "delta_degF"), ("10", "degF")), "error"), 821 ((("100", "delta_degF"), ("10", "degR")), ("1000", "delta_degF*degR")), 822 ( 823 (("100", "delta_degF"), ("10", "delta_degC")), 824 ("1000", "delta_degF*delta_degC"), 825 ), 826 ((("100", "delta_degF"), ("10", "delta_degF")), ("1000", "delta_degF**2")), 827 ] 828 829 @pytest.mark.parametrize(("input", "expected_output"), multiplications) 830 def test_multiplication(self, input_tuple, expected): 831 self.ureg.autoconvert_offset_to_baseunit = False 832 qin1, qin2 = input_tuple 833 q1, q2 = self.QP_(*qin1), self.QP_(*qin2) 834 input_tuple = q1, q2 835 if expected == "error": 836 with pytest.raises(OffsetUnitCalculusError): 837 op.mul(q1, q2) 838 else: 839 expected = self.QP_(*expected) 840 assert op.mul(q1, q2).units == expected.units 841 helpers.assert_quantity_almost_equal(op.mul(q1, q2), expected, atol=0.01) 842 843 divisions = [ 844 ((("100", "kelvin"), ("10", "kelvin")), ("10", "")), 845 ((("100", "kelvin"), ("10", "degC")), "error"), 846 ((("100", "kelvin"), ("10", "degF")), "error"), 847 ((("100", "kelvin"), ("10", "degR")), ("10", "kelvin/degR")), 848 ((("100", "kelvin"), ("10", "delta_degC")), ("10", "kelvin/delta_degC")), 849 ((("100", "kelvin"), ("10", "delta_degF")), ("10", "kelvin/delta_degF")), 850 ((("100", "degC"), ("10", "kelvin")), "error"), 851 ((("100", "degC"), ("10", "degC")), "error"), 852 ((("100", "degC"), ("10", "degF")), "error"), 853 ((("100", "degC"), ("10", "degR")), "error"), 854 ((("100", "degC"), ("10", "delta_degC")), "error"), 855 ((("100", "degC"), ("10", "delta_degF")), "error"), 856 ((("100", "degF"), ("10", "kelvin")), "error"), 857 ((("100", "degF"), ("10", "degC")), "error"), 858 ((("100", "degF"), ("10", "degF")), "error"), 859 ((("100", "degF"), ("10", "degR")), "error"), 860 ((("100", "degF"), ("10", "delta_degC")), "error"), 861 ((("100", "degF"), ("10", "delta_degF")), "error"), 862 ((("100", "degR"), ("10", "kelvin")), ("10", "degR/kelvin")), 863 ((("100", "degR"), ("10", "degC")), "error"), 864 ((("100", "degR"), ("10", "degF")), "error"), 865 ((("100", "degR"), ("10", "degR")), ("10", "")), 866 ((("100", "degR"), ("10", "delta_degC")), ("10", "degR/delta_degC")), 867 ((("100", "degR"), ("10", "delta_degF")), ("10", "degR/delta_degF")), 868 ((("100", "delta_degC"), ("10", "kelvin")), ("10", "delta_degC/kelvin")), 869 ((("100", "delta_degC"), ("10", "degC")), "error"), 870 ((("100", "delta_degC"), ("10", "degF")), "error"), 871 ((("100", "delta_degC"), ("10", "degR")), ("10", "delta_degC/degR")), 872 ((("100", "delta_degC"), ("10", "delta_degC")), ("10", "")), 873 ( 874 (("100", "delta_degC"), ("10", "delta_degF")), 875 ("10", "delta_degC/delta_degF"), 876 ), 877 ((("100", "delta_degF"), ("10", "kelvin")), ("10", "delta_degF/kelvin")), 878 ((("100", "delta_degF"), ("10", "degC")), "error"), 879 ((("100", "delta_degF"), ("10", "degF")), "error"), 880 ((("100", "delta_degF"), ("10", "degR")), ("10", "delta_degF/degR")), 881 ( 882 (("100", "delta_degF"), ("10", "delta_degC")), 883 ("10", "delta_degF/delta_degC"), 884 ), 885 ((("100", "delta_degF"), ("10", "delta_degF")), ("10", "")), 886 ] 887 888 @pytest.mark.parametrize(("input", "expected_output"), divisions) 889 def test_truedivision(self, input_tuple, expected): 890 self.ureg.autoconvert_offset_to_baseunit = False 891 qin1, qin2 = input_tuple 892 q1, q2 = self.QP_(*qin1), self.QP_(*qin2) 893 input_tuple = q1, q2 894 if expected == "error": 895 with pytest.raises(OffsetUnitCalculusError): 896 op.truediv(q1, q2) 897 else: 898 expected = self.QP_(*expected) 899 assert op.truediv(q1, q2).units == expected.units 900 helpers.assert_quantity_almost_equal( 901 op.truediv(q1, q2), expected, atol=0.01 902 ) 903 904 multiplications_with_autoconvert_to_baseunit = [ 905 ((("100", "kelvin"), ("10", "degC")), ("28315.0", "kelvin**2")), 906 ((("100", "kelvin"), ("10", "degF")), ("26092.78", "kelvin**2")), 907 ((("100", "degC"), ("10", "kelvin")), ("3731.5", "kelvin**2")), 908 ((("100", "degC"), ("10", "degC")), ("105657.42", "kelvin**2")), 909 ((("100", "degC"), ("10", "degF")), ("97365.20", "kelvin**2")), 910 ((("100", "degC"), ("10", "degR")), ("3731.5", "kelvin*degR")), 911 ((("100", "degC"), ("10", "delta_degC")), ("3731.5", "kelvin*delta_degC")), 912 ((("100", "degC"), ("10", "delta_degF")), ("3731.5", "kelvin*delta_degF")), 913 ((("100", "degF"), ("10", "kelvin")), ("3109.28", "kelvin**2")), 914 ((("100", "degF"), ("10", "degC")), ("88039.20", "kelvin**2")), 915 ((("100", "degF"), ("10", "degF")), ("81129.69", "kelvin**2")), 916 ((("100", "degF"), ("10", "degR")), ("3109.28", "kelvin*degR")), 917 ((("100", "degF"), ("10", "delta_degC")), ("3109.28", "kelvin*delta_degC")), 918 ((("100", "degF"), ("10", "delta_degF")), ("3109.28", "kelvin*delta_degF")), 919 ((("100", "degR"), ("10", "degC")), ("28315.0", "degR*kelvin")), 920 ((("100", "degR"), ("10", "degF")), ("26092.78", "degR*kelvin")), 921 ((("100", "delta_degC"), ("10", "degC")), ("28315.0", "delta_degC*kelvin")), 922 ((("100", "delta_degC"), ("10", "degF")), ("26092.78", "delta_degC*kelvin")), 923 ((("100", "delta_degF"), ("10", "degC")), ("28315.0", "delta_degF*kelvin")), 924 ((("100", "delta_degF"), ("10", "degF")), ("26092.78", "delta_degF*kelvin")), 925 ] 926 927 @pytest.mark.parametrize( 928 ("input", "expected_output"), multiplications_with_autoconvert_to_baseunit 929 ) 930 def test_multiplication_with_autoconvert(self, input_tuple, expected): 931 self.ureg.autoconvert_offset_to_baseunit = True 932 qin1, qin2 = input_tuple 933 q1, q2 = self.QP_(*qin1), self.QP_(*qin2) 934 input_tuple = q1, q2 935 if expected == "error": 936 with pytest.raises(OffsetUnitCalculusError): 937 op.mul(q1, q2) 938 else: 939 expected = self.QP_(*expected) 940 assert op.mul(q1, q2).units == expected.units 941 helpers.assert_quantity_almost_equal(op.mul(q1, q2), expected, atol=0.01) 942 943 multiplications_with_scalar = [ 944 ((("10", "kelvin"), "2"), ("20.0", "kelvin")), 945 ((("10", "kelvin**2"), "2"), ("20.0", "kelvin**2")), 946 ((("10", "degC"), "2"), ("20.0", "degC")), 947 ((("10", "1/degC"), "2"), "error"), 948 ((("10", "degC**0.5"), "2"), "error"), 949 ((("10", "degC**2"), "2"), "error"), 950 ((("10", "degC**-2"), "2"), "error"), 951 ] 952 953 @pytest.mark.parametrize(("input", "expected_output"), multiplications_with_scalar) 954 def test_multiplication_with_scalar(self, input_tuple, expected): 955 self.ureg.default_as_delta = False 956 in1, in2 = input_tuple 957 if type(in1) is tuple: 958 in1, in2 = self.QP_(*in1), self.NON_INT_TYPE(in2) 959 else: 960 in1, in2 = in1, self.QP_(*in2) 961 input_tuple = in1, in2 # update input_tuple for better tracebacks 962 if expected == "error": 963 with pytest.raises(OffsetUnitCalculusError): 964 op.mul(in1, in2) 965 else: 966 expected = self.QP_(*expected) 967 assert op.mul(in1, in2).units == expected.units 968 helpers.assert_quantity_almost_equal( 969 op.mul(in1, in2), expected, atol="0.01" 970 ) 971 972 divisions_with_scalar = [ # without / with autoconvert to base unit 973 ((("10", "kelvin"), "2"), [("5.0", "kelvin"), ("5.0", "kelvin")]), 974 ((("10", "kelvin**2"), "2"), [("5.0", "kelvin**2"), ("5.0", "kelvin**2")]), 975 ((("10", "degC"), "2"), ["error", "error"]), 976 ((("10", "degC**2"), "2"), ["error", "error"]), 977 ((("10", "degC**-2"), "2"), ["error", "error"]), 978 (("2", ("10", "kelvin")), [("0.2", "1/kelvin"), ("0.2", "1/kelvin")]), 979 # (('2', ('10', "degC")), ["error", (2 / 283.15, "1/kelvin")]), 980 (("2", ("10", "degC**2")), ["error", "error"]), 981 (("2", ("10", "degC**-2")), ["error", "error"]), 982 ] 983 984 @pytest.mark.parametrize(("input", "expected_output"), divisions_with_scalar) 985 def test_division_with_scalar(self, input_tuple, expected): 986 self.ureg.default_as_delta = False 987 in1, in2 = input_tuple 988 if type(in1) is tuple: 989 in1, in2 = self.QP_(*in1), self.NON_INT_TYPE(in2) 990 else: 991 in1, in2 = self.NON_INT_TYPE(in1), self.QP_(*in2) 992 input_tuple = in1, in2 # update input_tuple for better tracebacks 993 expected_copy = expected[:] 994 for i, mode in enumerate([False, True]): 995 self.ureg.autoconvert_offset_to_baseunit = mode 996 if expected_copy[i] == "error": 997 with pytest.raises(OffsetUnitCalculusError): 998 op.truediv(in1, in2) 999 else: 1000 expected = self.QP_(*expected_copy[i]) 1001 assert op.truediv(in1, in2).units == expected.units 1002 helpers.assert_quantity_almost_equal(op.truediv(in1, in2), expected) 1003 1004 exponentiation = [ # results without / with autoconvert 1005 ((("10", "degC"), "1"), [("10", "degC"), ("10", "degC")]), 1006 # ((('10', "degC"), 0.5), ["error", (283.15 ** '0.5', "kelvin**0.5")]), 1007 ((("10", "degC"), "0"), [("1.0", ""), ("1.0", "")]), 1008 # ((('10', "degC"), -1), ["error", (1 / (10 + 273.15), "kelvin**-1")]), 1009 # ((('10', "degC"), -2), ["error", (1 / (10 + 273.15) ** 2.0, "kelvin**-2")]), 1010 # ((('0', "degC"), -2), ["error", (1 / (273.15) ** 2, "kelvin**-2")]), 1011 # ((('10', "degC"), ('2', "")), ["error", ((283.15) ** 2, "kelvin**2")]), 1012 ((("10", "degC"), ("10", "degK")), ["error", "error"]), 1013 ( 1014 (("10", "kelvin"), ("2", "")), 1015 [("100.0", "kelvin**2"), ("100.0", "kelvin**2")], 1016 ), 1017 (("2", ("2", "kelvin")), ["error", "error"]), 1018 # (('2', ('500.0', "millikelvin/kelvin")), [2 ** 0.5, 2 ** 0.5]), 1019 # (('2', ('0.5', "kelvin/kelvin")), [2 ** 0.5, 2 ** 0.5]), 1020 # ( 1021 # (('10', "degC"), ('500.0', "millikelvin/kelvin")), 1022 # ["error", (283.15 ** '0.5', "kelvin**0.5")], 1023 # ), 1024 ] 1025 1026 @pytest.mark.parametrize(("input", "expected_output"), exponentiation) 1027 def test_exponentiation(self, input_tuple, expected): 1028 self.ureg.default_as_delta = False 1029 in1, in2 = input_tuple 1030 if type(in1) is tuple and type(in2) is tuple: 1031 in1, in2 = self.QP_(*in1), self.QP_(*in2) 1032 elif not type(in1) is tuple and type(in2) is tuple: 1033 in1, in2 = self.NON_INT_TYPE(in1), self.QP_(*in2) 1034 else: 1035 in1, in2 = self.QP_(*in1), self.NON_INT_TYPE(in2) 1036 input_tuple = in1, in2 1037 expected_copy = expected[:] 1038 for i, mode in enumerate([False, True]): 1039 self.ureg.autoconvert_offset_to_baseunit = mode 1040 if expected_copy[i] == "error": 1041 with pytest.raises((OffsetUnitCalculusError, DimensionalityError)): 1042 op.pow(in1, in2) 1043 else: 1044 if type(expected_copy[i]) is tuple: 1045 expected = self.QP_(*expected_copy[i]) 1046 assert op.pow(in1, in2).units == expected.units 1047 else: 1048 expected = expected_copy[i] 1049 helpers.assert_quantity_almost_equal(op.pow(in1, in2), expected) 1050 1051 1052class NonIntTypeQuantityTestQuantityFloat(_TestBasic, NonIntTypeQuantityTestCase): 1053 1054 kwargs = dict(non_int_type=float) 1055 1056 1057class NonIntTypeQuantityTestQuantityBasicMathFloat( 1058 _TestQuantityBasicMath, NonIntTypeQuantityTestCase 1059): 1060 1061 kwargs = dict(non_int_type=float) 1062 1063 1064class NonIntTypeQuantityTestOffsetUnitMathFloat( 1065 _TestOffsetUnitMath, NonIntTypeQuantityTestCase 1066): 1067 1068 kwargs = dict(non_int_type=float) 1069 1070 1071class NonIntTypeQuantityTestQuantityDecimal(_TestBasic, NonIntTypeQuantityTestCase): 1072 1073 kwargs = dict(non_int_type=Decimal) 1074 1075 1076class NonIntTypeQuantityTestQuantityBasicMathDecimal( 1077 _TestQuantityBasicMath, NonIntTypeQuantityTestCase 1078): 1079 1080 kwargs = dict(non_int_type=Decimal) 1081 1082 1083class NonIntTypeQuantityTestOffsetUnitMathDecimal( 1084 _TestOffsetUnitMath, NonIntTypeQuantityTestCase 1085): 1086 1087 kwargs = dict(non_int_type=Decimal) 1088 1089 1090class NonIntTypeQuantityTestQuantityFraction(_TestBasic, NonIntTypeQuantityTestCase): 1091 1092 kwargs = dict(non_int_type=Fraction) 1093 1094 1095class NonIntTypeQuantityTestQuantityBasicMathFraction( 1096 _TestQuantityBasicMath, NonIntTypeQuantityTestCase 1097): 1098 1099 kwargs = dict(non_int_type=Fraction) 1100 1101 1102class NonIntTypeQuantityTestOffsetUnitMathFraction( 1103 _TestOffsetUnitMath, NonIntTypeQuantityTestCase 1104): 1105 1106 kwargs = dict(non_int_type=Fraction) 1107