diff options
author | David Linke <dalito@users.noreply.github.com> | 2014-06-13 02:37:06 +0200 |
---|---|---|
committer | David Linke <dalito@users.noreply.github.com> | 2014-06-13 02:37:06 +0200 |
commit | c06153cbad57e8c33154d1a8e975247f5ec0f12d (patch) | |
tree | 92264fd9980ffa3949a32899af90ee89961f85d3 | |
parent | 8b9ee4776164e5f6d13ceee4cccc8f01debff828 (diff) | |
download | pint-c06153cbad57e8c33154d1a8e975247f5ec0f12d.tar.gz |
Change: Converted functions to Quantity methods/properties
Also reorganized code in parameterized tests.
-rw-r--r-- | pint/quantity.py | 265 | ||||
-rw-r--r-- | pint/testsuite/test_quantity.py | 333 |
2 files changed, 305 insertions, 293 deletions
diff --git a/pint/quantity.py b/pint/quantity.py index 71f2816..74e4463 100644 --- a/pint/quantity.py +++ b/pint/quantity.py @@ -56,68 +56,6 @@ def _check(q1, other): return False -def _is_multiplicative(q): # renamed from _only_multiplicative_units - """Check if the Quantity object has only multiplicative units. - """ - # XXX Turn this into a method/property of _Quantity? - return not _get_non_multiplicative_units(q) - - -def _get_non_multiplicative_units(q): - """Return a list of the of non-multiplicative units of the Quantity object - """ - # XXX Turn this into a method/property of _Quantity? - offset_units = [unit for unit in q.units.keys() - if not q._REGISTRY._units[unit].is_multiplicative] - return offset_units - - -def _get_delta_units(q): - """Return list of delta units ot the Quantity object - """ - # XXX Turn this into a method/property of _Quantity? a class mathod? - delta_units = [u for u in q.units.keys() if u.startswith("delta_")] - return delta_units - - -def _has_compatible_delta(q, unit): - """"Check if Quantity object has a delta_unit that is compatible with unit - """ - # XXX Turn this into a method/property of _Quantity? - deltas = _get_delta_units(q) - if 'delta_' + unit in deltas: - return True - else: # Look for delta units with same dimension as the offset unit - offset_unit_dim = q._REGISTRY._units[unit].reference - for d in deltas: - if q._REGISTRY._units[d].reference == offset_unit_dim: - return True - return False - - -def _ok_for_muldiv(q, no_offset_units=None): - """Checks if Quantity object can be multiplied or divided - - :q: quantity object that is checked - :no_offset_units: number of offset units in q - """ - # XXX Turn this into a method/property of _Quantity? - is_ok = True - if no_offset_units is None: - no_offset_units = len(_get_non_multiplicative_units(q)) - if no_offset_units > 1: - is_ok = False - if no_offset_units == 1: - if len(q.units) > 1: - is_ok = False - if (len(q.units) == 1 - and not q._REGISTRY.autoconvert_offset_to_baseunit): - is_ok = False - if q.units.values()[0] != 1: - is_ok = False - return is_ok - - class _Quantity(object): """Implements a class to describe a physical quantity: the product of a numerical value and a unit of measurement. @@ -344,7 +282,8 @@ class _Quantity(object): :param op: operator function (e.g. operator.add, operator.isub) :type op: function """ - if not _check(self, other): # other not from same Registry or not a Quantity + if not _check(self, other): + # other not from same Registry or not a Quantity try: other_magnitude = _to_magnitude(other, self.force_ndarray) except TypeError: @@ -368,14 +307,11 @@ class _Quantity(object): other.dimensionality) # Next we define some variables to make if-clauses more readable. - reg = self._REGISTRY._units - # For self: - self_non_mul_units = _get_non_multiplicative_units(self) + self_non_mul_units = self._get_non_multiplicative_units() is_self_multiplicative = len(self_non_mul_units) == 0 if len(self_non_mul_units) == 1: self_non_mul_unit = self_non_mul_units[0] - # For other: - other_non_mul_units = _get_non_multiplicative_units(other) + other_non_mul_units = other._get_non_multiplicative_units() is_other_multiplicative = len(other_non_mul_units) == 0 if len(other_non_mul_units) == 1: other_non_mul_unit = other_non_mul_units[0] @@ -383,25 +319,36 @@ class _Quantity(object): # Presence of non-multiplicative units gives rise to several cases. if is_self_multiplicative and is_other_multiplicative: # If only self has a delta unit, other determines unit of result. - if _get_delta_units(self) and not _get_delta_units(other): - self._magnitude = op(self.to(other)._magnitude, other._magnitude) + if self._get_delta_units() and not other._get_delta_units(): + self._magnitude = op(self._convert_magnitude(other.units), + other._magnitude) self._units = copy.copy(other.units) else: - self._magnitude = op(self._magnitude, other.to(self)._magnitude) - elif (len(self_non_mul_units) == 1 and len(other_non_mul_units) == 1 - # order of the dimension of offset units == 1 ? - and reg[self_non_mul_unit].reference.values()[0] == 1 - and reg[other_non_mul_unit].reference.values()[0] == 1 - and self_non_mul_unit == other_non_mul_unit - and op == operator.isub): - # subtraction of two quantities with same offset unit is - # allowed and gives a result in the corresponding delta_unit - self._magnitude = op(self._magnitude, other._magnitude) - self._units['delta_' + self_non_mul_unit] = self.units.pop(self_non_mul_unit) + self._magnitude = op(self._magnitude, + other.to(self.units)._magnitude) + + elif (op == operator.isub and len(self_non_mul_units) == 1 + and self.units[self_non_mul_unit] == 1 + and not other._has_compatible_delta(self_non_mul_unit)): + if self.units == other.units: + self._magnitude = op(self._magnitude, other._magnitude) + else: + self._magnitude = op(self._magnitude, + other.to(self.units)._magnitude) + self.units['delta_' + self_non_mul_unit + ] = self.units.pop(self_non_mul_unit) + + elif (op == operator.isub and len(other_non_mul_units) == 1 + and other.units[other_non_mul_unit] == 1 + and not self._has_compatible_delta(other_non_mul_unit)): + # we convert to self directly since it is multiplicative + self._magnitude = op(self._magnitude, + other.to(self.units)._magnitude) + elif (len(self_non_mul_units) == 1 # order of the dimension of offset unit == 1 ? - and reg[self_non_mul_unit].reference.values()[0] == 1 - and _has_compatible_delta(other, self_non_mul_unit)): + and self._units[self_non_mul_unit] == 1 + and other._has_compatible_delta(self_non_mul_unit)): tu = copy.copy(self.units) # Replace offset unit in self by the corresponding delta unit. # This is done to prevent a shift by offset in the to()-call. @@ -409,13 +356,13 @@ class _Quantity(object): self._magnitude = op(self._magnitude, other.to(tu)._magnitude) elif (len(other_non_mul_units) == 1 # order of the dimension of offset unit == 1 ? - and reg[other_non_mul_unit].reference.values()[0] == 1 - and _has_compatible_delta(self, other_non_mul_unit)): + and other._units[other_non_mul_unit] == 1 + and self._has_compatible_delta(other_non_mul_unit)): tu = copy.copy(other.units) # Replace offset unit in other by the corresponding delta unit. # This is done to prevent a shift by offset in the to()-call. tu['delta_' + other_non_mul_unit] = tu.pop(other_non_mul_unit) - self._magnitude = op(self.to(tu)._magnitude, other._magnitude) + self._magnitude = op(self._convert_magnitude(tu), other._magnitude) self._units = copy.copy(other.units) else: raise OffsetUnitCalculusError(self.units, other.units) @@ -430,7 +377,8 @@ class _Quantity(object): :param op: operator function (e.g. operator.add, operator.isub) :type op: function """ - if not _check(self, other): # other not from same Registry or not a Quantity + if not _check(self, other): + # other not from same Registry or not a Quantity if _eq(other, 0, True): # If the other value is 0 (but not Quantity 0) # do the operation without checking units. @@ -453,14 +401,11 @@ class _Quantity(object): other.dimensionality) # Next we define some variables to make if-clauses more readable. - reg = self._REGISTRY._units - # For self: - self_non_mul_units = _get_non_multiplicative_units(self) + self_non_mul_units = self._get_non_multiplicative_units() is_self_multiplicative = len(self_non_mul_units) == 0 if len(self_non_mul_units) == 1: self_non_mul_unit = self_non_mul_units[0] - # For other: - other_non_mul_units = _get_non_multiplicative_units(other) + other_non_mul_units = other._get_non_multiplicative_units() is_other_multiplicative = len(other_non_mul_units) == 0 if len(other_non_mul_units) == 1: other_non_mul_unit = other_non_mul_units[0] @@ -468,42 +413,53 @@ class _Quantity(object): # Presence of non-multiplicative units gives rise to several cases. if is_self_multiplicative and is_other_multiplicative: # If only self has a delta unit, other determines unit of result. - if _get_delta_units(self) and not _get_delta_units(other): - magnitude = op(self.to(other)._magnitude, other._magnitude) + if self._get_delta_units() and not other._get_delta_units(): + magnitude = op(self._convert_magnitude(other.units), + other._magnitude) units = copy.copy(other.units) else: units = copy.copy(self.units) - magnitude = op(self._magnitude, other.to(self)._magnitude) - elif (len(self_non_mul_units) == 1 and len(other_non_mul_units) == 1 - # order of the dimension of offset units == 1 ? - and reg[self_non_mul_unit].reference.values()[0] == 1 - and reg[other_non_mul_unit].reference.values()[0] == 1 - and self_non_mul_unit == other_non_mul_unit - and op == operator.sub): - # subtraction of two quantities with same offset unit is - # allowed and gives a result in the corresponding delta_unit - magnitude = op(self._magnitude, other._magnitude) + magnitude = op(self._magnitude, + other.to(self.units).magnitude) + + elif (op == operator.sub and len(self_non_mul_units) == 1 + and self.units[self_non_mul_unit] == 1 + and not other._has_compatible_delta(self_non_mul_unit)): + if self.units == other.units: + magnitude = op(self._magnitude, other._magnitude) + else: + magnitude = op(self._magnitude, + other.to(self.units)._magnitude) units = copy.copy(self.units) units['delta_' + self_non_mul_unit] = units.pop(self_non_mul_unit) + + elif (op == operator.sub and len(other_non_mul_units) == 1 + and other.units[other_non_mul_unit] == 1 + and not self._has_compatible_delta(other_non_mul_unit)): + # we convert to self directly since it is multiplicative + magnitude = op(self._magnitude, + other.to(self.units)._magnitude) + units = copy.copy(self.units) + elif (len(self_non_mul_units) == 1 # order of the dimension of offset unit == 1 ? - and reg[self_non_mul_unit].reference.values()[0] == 1 - and _has_compatible_delta(other, self_non_mul_unit)): + and self._units[self_non_mul_unit] == 1 + and other._has_compatible_delta(self_non_mul_unit)): tu = copy.copy(self.units) # Replace offset unit in self by the corresponding delta unit. # This is done to prevent a shift by offset in the to()-call. tu['delta_' + self_non_mul_unit] = tu.pop(self_non_mul_unit) - magnitude = op(self._magnitude, other.to(tu)._magnitude) + magnitude = op(self._magnitude, other.to(tu).magnitude) units = copy.copy(self.units) elif (len(other_non_mul_units) == 1 # order of the dimension of offset unit == 1 ? - and reg[other_non_mul_unit].reference.values()[0] == 1 - and _has_compatible_delta(self, other_non_mul_unit)): + and other._units[other_non_mul_unit] == 1 + and self._has_compatible_delta(other_non_mul_unit)): tu = copy.copy(other.units) # Replace offset unit in other by the corresponding delta unit. # This is done to prevent a shift by offset in the to()-call. tu['delta_' + other_non_mul_unit] = tu.pop(other_non_mul_unit) - magnitude = op(self.to(tu)._magnitude, other._magnitude) + magnitude = op(self._convert_magnitude(tu), other._magnitude) units = copy.copy(other.units) else: raise OffsetUnitCalculusError(self.units, other.units) @@ -546,11 +502,11 @@ class _Quantity(object): if units_op is None: units_op = magnitude_op - offset_units_self = _get_non_multiplicative_units(self) + offset_units_self = self._get_non_multiplicative_units() no_offset_units_self = len(offset_units_self) if not _check(self, other): - if not _ok_for_muldiv(self, no_offset_units_self): + if not self._ok_for_muldiv(no_offset_units_self): raise OffsetUnitCalculusError(self.units, getattr(other, 'units', '')) if len(offset_units_self) == 1: @@ -566,17 +522,17 @@ class _Quantity(object): self._units = units_op(self._units, UnitsContainer()) return self - if not _ok_for_muldiv(self, no_offset_units_self): + if not self._ok_for_muldiv(no_offset_units_self): raise OffsetUnitCalculusError(self.units, other.units) elif no_offset_units_self == 1 and len(self.units) == 1: self.ito_base_units() - no_offset_units_other = len(_get_non_multiplicative_units(other)) + no_offset_units_other = len(other._get_non_multiplicative_units()) - if not _ok_for_muldiv(other, no_offset_units_other): + if not other._ok_for_muldiv(no_offset_units_other): raise OffsetUnitCalculusError(self.units, other.units) elif no_offset_units_other == 1 and len(other.units) == 1: - other.ito_base_units() + other.ito_base_units() self._magnitude = magnitude_op(self._magnitude, other._magnitude) self._units = units_op(self._units, other._units) @@ -596,11 +552,11 @@ class _Quantity(object): if units_op is None: units_op = magnitude_op - offset_units_self = _get_non_multiplicative_units(self) + offset_units_self = self._get_non_multiplicative_units() no_offset_units_self = len(offset_units_self) if not _check(self, other): - if not _ok_for_muldiv(self, no_offset_units_self): + if not self._ok_for_muldiv(no_offset_units_self): raise OffsetUnitCalculusError(self.units, getattr(other, 'units', '')) if len(offset_units_self) == 1: @@ -620,14 +576,14 @@ class _Quantity(object): new_self = self - if not _ok_for_muldiv(self, no_offset_units_self): + if not self._ok_for_muldiv(no_offset_units_self): raise OffsetUnitCalculusError(self.units, other.units) elif no_offset_units_self == 1 and len(self.units) == 1: new_self = self.to_base_units() - no_offset_units_other = len(_get_non_multiplicative_units(other)) + no_offset_units_other = len(other._get_non_multiplicative_units()) - if not _ok_for_muldiv(other, no_offset_units_other): + if not other._ok_for_muldiv(no_offset_units_other): raise OffsetUnitCalculusError(self.units, other.units) elif no_offset_units_other == 1 and len(other.units) == 1: other = other.to_base_units() @@ -672,8 +628,8 @@ class _Quantity(object): except TypeError: return NotImplemented - no_offset_units_self = len(_get_non_multiplicative_units(self)) - if not _ok_for_muldiv(self, no_offset_units_self): + no_offset_units_self = len(self._get_non_multiplicative_units()) + if not self._ok_for_muldiv(no_offset_units_self): raise OffsetUnitCalculusError(self.units, '') elif no_offset_units_self == 1 and len(self.units) == 1: self = self.to_base_units() @@ -686,8 +642,8 @@ class _Quantity(object): except TypeError: return NotImplemented - no_offset_units_self = len(_get_non_multiplicative_units(self)) - if not _ok_for_muldiv(self, no_offset_units_self): + no_offset_units_self = len(self._get_non_multiplicative_units()) + if not self._ok_for_muldiv(no_offset_units_self): raise OffsetUnitCalculusError(self.units, '') elif no_offset_units_self == 1 and len(self.units) == 1: self = self.to_base_units() @@ -707,7 +663,7 @@ class _Quantity(object): except TypeError: return NotImplemented else: - if not _is_multiplicative(self): + if not self._is_multiplicative: self.ito_base_units() self._magnitude **= _to_magnitude(other, self.force_ndarray) self._units **= other @@ -720,7 +676,7 @@ class _Quantity(object): return NotImplemented else: new_self = self - if not _is_multiplicative(self): + if not self._is_multiplicative: new_self = self.to_base_units() magnitude = new_self._magnitude ** _to_magnitude(other, self.force_ndarray) @@ -1141,3 +1097,58 @@ class _Quantity(object): error = error * abs(self.magnitude) return self._REGISTRY.Measurement(copy.copy(self.magnitude), error, self.units) + + # methods/properties that help for math operations with offset units + @property + def _is_multiplicative(self): + """Check if the Quantity object has only multiplicative units. + """ + # XXX Turn this into a method/property of _Quantity? + return not self._get_non_multiplicative_units() + + def _get_non_multiplicative_units(self): + """Return a list of the of non-multiplicative units of the Quantity object + """ + offset_units = [unit for unit in self.units.keys() + if not self._REGISTRY._units[unit].is_multiplicative] + return offset_units + + def _get_delta_units(self): + """Return list of delta units ot the Quantity object + """ + delta_units = [u for u in self.units.keys() if u.startswith("delta_")] + return delta_units + + def _has_compatible_delta(self, unit): + """"Check if Quantity object has a delta_unit that is compatible with unit + """ + deltas = self._get_delta_units() + if 'delta_' + unit in deltas: + return True + else: # Look for delta units with same dimension as the offset unit + offset_unit_dim = self._REGISTRY._units[unit].reference + for d in deltas: + if self._REGISTRY._units[d].reference == offset_unit_dim: + return True + return False + + def _ok_for_muldiv(self, no_offset_units=None): + """Checks if Quantity object can be multiplied or divided + + :q: quantity object that is checked + :no_offset_units: number of offset units in q + """ + is_ok = True + if no_offset_units is None: + no_offset_units = len(self._get_non_multiplicative_units()) + if no_offset_units > 1: + is_ok = False + if no_offset_units == 1: + if len(self._units) > 1: + is_ok = False + if (len(self._units) == 1 + and not self._REGISTRY.autoconvert_offset_to_baseunit): + is_ok = False + if self._units.values()[0] != 1: + is_ok = False + return is_ok diff --git a/pint/testsuite/test_quantity.py b/pint/testsuite/test_quantity.py index 7a428fb..8778d73 100644 --- a/pint/testsuite/test_quantity.py +++ b/pint/testsuite/test_quantity.py @@ -453,6 +453,10 @@ class TestDimensionsWithDefaultRegistry(TestDimensions): class TestOffsetUnitMath(QuantityTestCase, ParameterizedTestCase): + def setup(self): + self.ureg.autoconvert_offset_to_baseunit = False + self.ureg.default_as_delta = True + additions = [ # --- input tuple -------------------- | -- expected result -- (((100, 'kelvin'), (10, 'kelvin')), (110, 'kelvin')), @@ -498,31 +502,69 @@ class TestOffsetUnitMath(QuantityTestCase, ParameterizedTestCase): (((100, 'delta_degF'), (10, 'delta_degF')), (110, 'delta_degF')), ] + @ParameterizedTestCase.parameterize(("input", "expected_output"), + additions) + def test_addition(self, input_tuple, expected): + self.ureg.autoconvert_offset_to_baseunit = False + qin1, qin2 = input_tuple + q1, q2 = self.Q_(*qin1), self.Q_(*qin2) + # update input tuple with new values to have correct values on failure + input_tuple = q1, q2 + if expected == 'error': + self.assertRaises(OffsetUnitCalculusError, op.add, q1, q2) + else: + expected = self.Q_(*expected) + self.assertEqual(op.add(q1, q2).units, expected.units) + self.assertQuantityAlmostEqual(op.add(q1, q2), expected, + atol=0.01) + + @helpers.requires_numpy() + @ParameterizedTestCase.parameterize(("input", "expected_output"), + additions) + def test_inplace_addition(self, input_tuple, expected): + self.ureg.autoconvert_offset_to_baseunit = False + (q1v, q1u), (q2v, q2u) = input_tuple + # update input tuple with new values to have correct values on failure + input_tuple = ((np.array([q1v]*2, dtype=np.float), q1u), + (np.array([q2v]*2, dtype=np.float), q2u)) + Q_ = self.Q_ + qin1, qin2 = input_tuple + q1, q2 = Q_(*qin1), Q_(*qin2) + q1_cp = copy.copy(q1) + if expected == 'error': + self.assertRaises(OffsetUnitCalculusError, op.iadd, q1_cp, q2) + else: + expected = np.array([expected[0]]*2, dtype=np.float), expected[1] + self.assertEqual(op.iadd(q1_cp, q2).units, Q_(*expected).units) + q1_cp = copy.copy(q1) + self.assertQuantityAlmostEqual(op.iadd(q1_cp, q2), Q_(*expected), + atol=0.01) + subtractions = [ (((100, 'kelvin'), (10, 'kelvin')), (90, 'kelvin')), - (((100, 'kelvin'), (10, 'degC')), 'error'), - (((100, 'kelvin'), (10, 'degF')), 'error'), + (((100, 'kelvin'), (10, 'degC')), (-183.15, 'kelvin')), + (((100, 'kelvin'), (10, 'degF')), (-160.93, 'kelvin')), (((100, 'kelvin'), (10, 'degR')), (94.44, 'kelvin')), (((100, 'kelvin'), (10, 'delta_degC')), (90, 'kelvin')), (((100, 'kelvin'), (10, 'delta_degF')), (94.44, 'kelvin')), - (((100, 'degC'), (10, 'kelvin')), 'error'), + (((100, 'degC'), (10, 'kelvin')), (363.15, 'delta_degC')), (((100, 'degC'), (10, 'degC')), (90, 'delta_degC')), - (((100, 'degC'), (10, 'degF')), 'error'), - (((100, 'degC'), (10, 'degR')), 'error'), + (((100, 'degC'), (10, 'degF')), (112.22, 'delta_degC')), + (((100, 'degC'), (10, 'degR')), (367.59, 'delta_degC')), (((100, 'degC'), (10, 'delta_degC')), (90, 'degC')), (((100, 'degC'), (10, 'delta_degF')), (94.44, 'degC')), - (((100, 'degF'), (10, 'kelvin')), 'error'), - (((100, 'degF'), (10, 'degC')), 'error'), + (((100, 'degF'), (10, 'kelvin')), (541.67, 'delta_degF')), + (((100, 'degF'), (10, 'degC')), (50, 'delta_degF')), (((100, 'degF'), (10, 'degF')), (90, 'delta_degF')), - (((100, 'degF'), (10, 'degR')), 'error'), + (((100, 'degF'), (10, 'degR')), (549.67, 'delta_degF')), (((100, 'degF'), (10, 'delta_degC')), (82, 'degF')), (((100, 'degF'), (10, 'delta_degF')), (90, 'degF')), (((100, 'degR'), (10, 'kelvin')), (82, 'degR')), - (((100, 'degR'), (10, 'degC')), 'error'), - (((100, 'degR'), (10, 'degF')), 'error'), + (((100, 'degR'), (10, 'degC')), (-409.67, 'degR')), + (((100, 'degR'), (10, 'degF')), (-369.67, 'degR')), (((100, 'degR'), (10, 'degR')), (90, 'degR')), (((100, 'degR'), (10, 'delta_degC')), (82, 'degR')), (((100, 'degR'), (10, 'delta_degF')), (90, 'degR')), @@ -542,6 +584,44 @@ class TestOffsetUnitMath(QuantityTestCase, ParameterizedTestCase): (((100, 'delta_degF'), (10, 'delta_degF')), (90, 'delta_degF')), ] + @ParameterizedTestCase.parameterize(("input", "expected_output"), + subtractions) + def test_subtraction(self, input_tuple, expected): + self.ureg.autoconvert_offset_to_baseunit = False + qin1, qin2 = input_tuple + q1, q2 = self.Q_(*qin1), self.Q_(*qin2) + input_tuple = q1, q2 + if expected == 'error': + self.assertRaises(OffsetUnitCalculusError, op.sub, q1, q2) + else: + expected = self.Q_(*expected) + self.assertEqual(op.sub(q1, q2).units, expected.units) + self.assertQuantityAlmostEqual(op.sub(q1, q2), expected, + atol=0.01) + +# @unittest.expectedFailure + @helpers.requires_numpy() + @ParameterizedTestCase.parameterize(("input", "expected_output"), + subtractions) + def test_inplace_subtraction(self, input_tuple, expected): + self.ureg.autoconvert_offset_to_baseunit = False + (q1v, q1u), (q2v, q2u) = input_tuple + # update input tuple with new values to have correct values on failure + input_tuple = ((np.array([q1v]*2, dtype=np.float), q1u), + (np.array([q2v]*2, dtype=np.float), q2u)) + Q_ = self.Q_ + qin1, qin2 = input_tuple + q1, q2 = Q_(*qin1), Q_(*qin2) + q1_cp = copy.copy(q1) + if expected == 'error': + self.assertRaises(OffsetUnitCalculusError, op.isub, q1_cp, q2) + else: + expected = np.array([expected[0]]*2, dtype=np.float), expected[1] + self.assertEqual(op.isub(q1_cp, q2).units, Q_(*expected).units) + q1_cp = copy.copy(q1) + self.assertQuantityAlmostEqual(op.isub(q1_cp, q2), Q_(*expected), + atol=0.01) + multiplications = [ (((100, 'kelvin'), (10, 'kelvin')), (1000, 'kelvin**2')), (((100, 'kelvin'), (10, 'degC')), 'error'), @@ -586,6 +666,43 @@ class TestOffsetUnitMath(QuantityTestCase, ParameterizedTestCase): (((100, 'delta_degF'), (10, 'delta_degF')), (1000, 'delta_degF**2')), ] + @ParameterizedTestCase.parameterize(("input", "expected_output"), + multiplications) + def test_multiplication(self, input_tuple, expected): + self.ureg.autoconvert_offset_to_baseunit = False + qin1, qin2 = input_tuple + q1, q2 = self.Q_(*qin1), self.Q_(*qin2) + input_tuple = q1, q2 + if expected == 'error': + self.assertRaises(OffsetUnitCalculusError, op.mul, q1, q2) + else: + expected = self.Q_(*expected) + self.assertEqual(op.mul(q1, q2).units, expected.units) + self.assertQuantityAlmostEqual(op.mul(q1, q2), expected, + atol=0.01) + + @helpers.requires_numpy() + @ParameterizedTestCase.parameterize(("input", "expected_output"), + multiplications) + def test_inplace_multiplication(self, input_tuple, expected): + self.ureg.autoconvert_offset_to_baseunit = False + (q1v, q1u), (q2v, q2u) = input_tuple + # update input tuple with new values to have correct values on failure + input_tuple = ((np.array([q1v]*2, dtype=np.float), q1u), + (np.array([q2v]*2, dtype=np.float), q2u)) + Q_ = self.Q_ + qin1, qin2 = input_tuple + q1, q2 = Q_(*qin1), Q_(*qin2) + q1_cp = copy.copy(q1) + if expected == 'error': + self.assertRaises(OffsetUnitCalculusError, op.imul, q1_cp, q2) + else: + expected = np.array([expected[0]]*2, dtype=np.float), expected[1] + self.assertEqual(op.imul(q1_cp, q2).units, Q_(*expected).units) + q1_cp = copy.copy(q1) + self.assertQuantityAlmostEqual(op.imul(q1_cp, q2), Q_(*expected), + atol=0.01) + divisions = [ (((100, 'kelvin'), (10, 'kelvin')), (10, '')), (((100, 'kelvin'), (10, 'degC')), 'error'), @@ -630,150 +747,6 @@ class TestOffsetUnitMath(QuantityTestCase, ParameterizedTestCase): (((100, 'delta_degF'), (10, 'delta_degF')), (10, '')), ] - multiplications_with_autoconvert_to_baseunit = [ - (((100, 'kelvin'), (10, 'degC')), (28315., 'kelvin**2')), - (((100, 'kelvin'), (10, 'degF')), (26092.78, 'kelvin**2')), - - (((100, 'degC'), (10, 'kelvin')), (3731.5, 'kelvin**2')), - (((100, 'degC'), (10, 'degC')), (105657.42, 'kelvin**2')), - (((100, 'degC'), (10, 'degF')), (97365.20, 'kelvin**2')), - (((100, 'degC'), (10, 'degR')), (3731.5, 'kelvin*degR')), - (((100, 'degC'), (10, 'delta_degC')), (3731.5, 'kelvin*delta_degC')), - (((100, 'degC'), (10, 'delta_degF')), (3731.5, 'kelvin*delta_degF')), - - (((100, 'degF'), (10, 'kelvin')), (3109.28, 'kelvin**2')), - (((100, 'degF'), (10, 'degC')), (88039.20, 'kelvin**2')), - (((100, 'degF'), (10, 'degF')), (81129.69, 'kelvin**2')), - (((100, 'degF'), (10, 'degR')), (3109.28, 'kelvin*degR')), - (((100, 'degF'), (10, 'delta_degC')), (3109.28, 'kelvin*delta_degC')), - (((100, 'degF'), (10, 'delta_degF')), (3109.28, 'kelvin*delta_degF')), - - (((100, 'degR'), (10, 'degC')), (28315., 'degR*kelvin')), - (((100, 'degR'), (10, 'degF')), (26092.78, 'degR*kelvin')), - - (((100, 'delta_degC'), (10, 'degC')), (28315., 'delta_degC*kelvin')), - (((100, 'delta_degC'), (10, 'degF')), (26092.78, 'delta_degC*kelvin')), - - (((100, 'delta_degF'), (10, 'degC')), (28315., 'delta_degF*kelvin')), - (((100, 'delta_degF'), (10, 'degF')), (26092.78, 'delta_degF*kelvin')), - ] - - def setup(self): - self.ureg.autoconvert_offset_to_baseunit = False - self.ureg.default_as_delta = True - - @ParameterizedTestCase.parameterize(("input", "expected_output"), - additions) - def test_addition(self, input_tuple, expected): - self.ureg.autoconvert_offset_to_baseunit = False - qin1, qin2 = input_tuple - q1, q2 = self.Q_(*qin1), self.Q_(*qin2) - # update input tuple with new values to have correct values on failure - input_tuple = q1, q2 - if expected == 'error': - self.assertRaises(OffsetUnitCalculusError, op.add, q1, q2) - else: - expected = self.Q_(*expected) - self.assertEqual(op.add(q1, q2).units, expected.units) - self.assertQuantityAlmostEqual(op.add(q1, q2), expected, - atol=0.01) - - @helpers.requires_numpy() - @ParameterizedTestCase.parameterize(("input", "expected_output"), - additions) - def test_inplace_addition(self, input_tuple, expected): - self.ureg.autoconvert_offset_to_baseunit = False - (q1v, q1u), (q2v, q2u) = input_tuple - # update input tuple with new values to have correct values on failure - input_tuple = ((np.array([q1v]*2, dtype=np.float), q1u), - (np.array([q2v]*2, dtype=np.float), q2u)) - Q_ = self.Q_ - qin1, qin2 = input_tuple - q1, q2 = Q_(*qin1), Q_(*qin2) - q1_copy = copy.copy(q1) - if expected == 'error': - self.assertRaises(OffsetUnitCalculusError, op.iadd, q1, q2) - else: - expected = np.array([expected[0]]*2, dtype=np.float), expected[1] - self.assertEqual(op.iadd(q1, q2).units, Q_(*expected).units) - q1 = q1_copy - self.assertQuantityAlmostEqual(op.iadd(q1, q2), Q_(*expected), - atol=0.01) - - @ParameterizedTestCase.parameterize(("input", "expected_output"), - subtractions) - def test_subtraction(self, input_tuple, expected): - self.ureg.autoconvert_offset_to_baseunit = False - qin1, qin2 = input_tuple - q1, q2 = self.Q_(*qin1), self.Q_(*qin2) - input_tuple = q1, q2 - if expected == 'error': - self.assertRaises(OffsetUnitCalculusError, op.sub, q1, q2) - else: - expected = self.Q_(*expected) - self.assertEqual(op.sub(q1, q2).units, expected.units) - self.assertQuantityAlmostEqual(op.sub(q1, q2), expected, - atol=0.01) - - @helpers.requires_numpy() - @ParameterizedTestCase.parameterize(("input", "expected_output"), - subtractions) - def test_inplace_subtraction(self, input_tuple, expected): - self.ureg.autoconvert_offset_to_baseunit = False - (q1v, q1u), (q2v, q2u) = input_tuple - # update input tuple with new values to have correct values on failure - input_tuple = ((np.array([q1v]*2, dtype=np.float), q1u), - (np.array([q2v]*2, dtype=np.float), q2u)) - Q_ = self.Q_ - qin1, qin2 = input_tuple - q1, q2 = Q_(*qin1), Q_(*qin2) - q1_copy = copy.copy(q1) - if expected == 'error': - self.assertRaises(OffsetUnitCalculusError, op.isub, q1, q2) - else: - expected = np.array([expected[0]]*2, dtype=np.float), expected[1] - self.assertEqual(op.isub(q1, q2).units, Q_(*expected).units) - q1 = q1_copy - self.assertQuantityAlmostEqual(op.isub(q1, q2), Q_(*expected), - atol=0.01) - - @ParameterizedTestCase.parameterize(("input", "expected_output"), - multiplications) - def test_multiplication(self, input_tuple, expected): - self.ureg.autoconvert_offset_to_baseunit = False - qin1, qin2 = input_tuple - q1, q2 = self.Q_(*qin1), self.Q_(*qin2) - input_tuple = q1, q2 - if expected == 'error': - self.assertRaises(OffsetUnitCalculusError, op.mul, q1, q2) - else: - expected = self.Q_(*expected) - self.assertEqual(op.mul(q1, q2).units, expected.units) - self.assertQuantityAlmostEqual(op.mul(q1, q2), expected, - atol=0.01) - - @helpers.requires_numpy() - @ParameterizedTestCase.parameterize(("input", "expected_output"), - multiplications) - def test_inplace_multiplication(self, input_tuple, expected): - self.ureg.autoconvert_offset_to_baseunit = False - (q1v, q1u), (q2v, q2u) = input_tuple - # update input tuple with new values to have correct values on failure - input_tuple = ((np.array([q1v]*2, dtype=np.float), q1u), - (np.array([q2v]*2, dtype=np.float), q2u)) - Q_ = self.Q_ - qin1, qin2 = input_tuple - q1, q2 = Q_(*qin1), Q_(*qin2) - q1_copy = copy.copy(q1) - if expected == 'error': - self.assertRaises(OffsetUnitCalculusError, op.imul, q1, q2) - else: - expected = np.array([expected[0]]*2, dtype=np.float), expected[1] - self.assertEqual(op.imul(q1, q2).units, Q_(*expected).units) - q1 = q1_copy - self.assertQuantityAlmostEqual(op.imul(q1, q2), Q_(*expected), - atol=0.01) - @ParameterizedTestCase.parameterize(("input", "expected_output"), divisions) def test_truedivision(self, input_tuple, expected): @@ -801,20 +774,48 @@ class TestOffsetUnitMath(QuantityTestCase, ParameterizedTestCase): Q_ = self.Q_ qin1, qin2 = input_tuple q1, q2 = Q_(*qin1), Q_(*qin2) - q1_copy = copy.copy(q1) + q1_cp = copy.copy(q1) if expected == 'error': - self.assertRaises(OffsetUnitCalculusError, op.itruediv, q1, q2) + self.assertRaises(OffsetUnitCalculusError, op.itruediv, q1_cp, q2) else: expected = np.array([expected[0]]*2, dtype=np.float), expected[1] - self.assertEqual(op.itruediv(q1, q2).units, Q_(*expected).units) - q1 = q1_copy - self.assertQuantityAlmostEqual(op.itruediv(q1, q2), Q_(*expected), - atol=0.01) + self.assertEqual(op.itruediv(q1_cp, q2).units, Q_(*expected).units) + q1_cp = copy.copy(q1) + self.assertQuantityAlmostEqual(op.itruediv(q1_cp, q2), + Q_(*expected), atol=0.01) + + multiplications_with_autoconvert_to_baseunit = [ + (((100, 'kelvin'), (10, 'degC')), (28315., 'kelvin**2')), + (((100, 'kelvin'), (10, 'degF')), (26092.78, 'kelvin**2')), + + (((100, 'degC'), (10, 'kelvin')), (3731.5, 'kelvin**2')), + (((100, 'degC'), (10, 'degC')), (105657.42, 'kelvin**2')), + (((100, 'degC'), (10, 'degF')), (97365.20, 'kelvin**2')), + (((100, 'degC'), (10, 'degR')), (3731.5, 'kelvin*degR')), + (((100, 'degC'), (10, 'delta_degC')), (3731.5, 'kelvin*delta_degC')), + (((100, 'degC'), (10, 'delta_degF')), (3731.5, 'kelvin*delta_degF')), + + (((100, 'degF'), (10, 'kelvin')), (3109.28, 'kelvin**2')), + (((100, 'degF'), (10, 'degC')), (88039.20, 'kelvin**2')), + (((100, 'degF'), (10, 'degF')), (81129.69, 'kelvin**2')), + (((100, 'degF'), (10, 'degR')), (3109.28, 'kelvin*degR')), + (((100, 'degF'), (10, 'delta_degC')), (3109.28, 'kelvin*delta_degC')), + (((100, 'degF'), (10, 'delta_degF')), (3109.28, 'kelvin*delta_degF')), + + (((100, 'degR'), (10, 'degC')), (28315., 'degR*kelvin')), + (((100, 'degR'), (10, 'degF')), (26092.78, 'degR*kelvin')), + + (((100, 'delta_degC'), (10, 'degC')), (28315., 'delta_degC*kelvin')), + (((100, 'delta_degC'), (10, 'degF')), (26092.78, 'delta_degC*kelvin')), + + (((100, 'delta_degF'), (10, 'degC')), (28315., 'delta_degF*kelvin')), + (((100, 'delta_degF'), (10, 'degF')), (26092.78, 'delta_degF*kelvin')), + ] @ParameterizedTestCase.parameterize( ("input", "expected_output"), multiplications_with_autoconvert_to_baseunit) - def test_multiplication_with_autconvert(self, input_tuple, expected): + def test_multiplication_with_autoconvert(self, input_tuple, expected): self.ureg.autoconvert_offset_to_baseunit = True qin1, qin2 = input_tuple q1, q2 = self.Q_(*qin1), self.Q_(*qin2) @@ -840,14 +841,14 @@ class TestOffsetUnitMath(QuantityTestCase, ParameterizedTestCase): Q_ = self.Q_ qin1, qin2 = input_tuple q1, q2 = Q_(*qin1), Q_(*qin2) - q1_copy = copy.copy(q1) + q1_cp = copy.copy(q1) if expected == 'error': - self.assertRaises(OffsetUnitCalculusError, op.imul, q1, q2) + self.assertRaises(OffsetUnitCalculusError, op.imul, q1_cp, q2) else: expected = np.array([expected[0]]*2, dtype=np.float), expected[1] - self.assertEqual(op.imul(q1, q2).units, Q_(*expected).units) - q1 = q1_copy - self.assertQuantityAlmostEqual(op.imul(q1, q2), Q_(*expected), + self.assertEqual(op.imul(q1_cp, q2).units, Q_(*expected).units) + q1_cp = copy.copy(q1) + self.assertQuantityAlmostEqual(op.imul(q1_cp, q2), Q_(*expected), atol=0.01) multiplications_with_scalar = [ |