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