summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHernan Grecco <hernan.grecco@gmail.com>2014-03-29 18:22:35 -0300
committerHernan Grecco <hernan.grecco@gmail.com>2014-03-29 19:38:26 -0300
commit384ef9e90f3915d42a7ac8b413056d15d078b9de (patch)
tree56d3164634d22ee679c3ba9b61e6a511975903bb
parente215db7b28bc67e5cd126f8734cdcb8bddc2a4e0 (diff)
downloadpint-384ef9e90f3915d42a7ac8b413056d15d078b9de.tar.gz
Implemented better handling of Quantities with mutable magnitudes
Only if the magnitude is a `numpy.ndarray`, the in place math operations take place. In any other case, another object Quantity object is created and returned. See #104
-rw-r--r--pint/quantity.py77
-rw-r--r--pint/testsuite/__init__.py33
-rw-r--r--pint/testsuite/test_issues.py20
-rw-r--r--pint/testsuite/test_quantity.py309
4 files changed, 292 insertions, 147 deletions
diff --git a/pint/quantity.py b/pint/quantity.py
index 5a9e3f3..97d3b33 100644
--- a/pint/quantity.py
+++ b/pint/quantity.py
@@ -336,7 +336,10 @@ class _Quantity(object):
return self.__class__(magnitude, units)
def __iadd__(self, other):
- return self._iadd_sub(other, operator.iadd)
+ if not isinstance(self._magnitude, ndarray):
+ return self._add_sub(other, operator.add)
+ else:
+ return self._iadd_sub(other, operator.iadd)
def __add__(self, other):
return self._add_sub(other, operator.add)
@@ -344,7 +347,10 @@ class _Quantity(object):
__radd__ = __add__
def __isub__(self, other):
- return self._iadd_sub(other, operator.isub)
+ if not isinstance(self._magnitude, ndarray):
+ return self._add_sub(other, operator.sub)
+ else:
+ return self._iadd_sub(other, operator.isub)
def __sub__(self, other):
return self._add_sub(other, operator.sub)
@@ -387,11 +393,45 @@ class _Quantity(object):
return self
def _mul_div(self, other, magnitude_op, units_op=None):
- ret = copy.copy(self)
- return ret._imul_div(other, magnitude_op, units_op)
+ """Perform multiplication or division operation and return the result.
+
+ :param other: object to be multiplied/divided with self
+ :type other: Quantity or any type accepted by :func:`_to_magnitude`
+ :param magnitude_op: operator function to perform on the magnitudes (e.g. operator.mul)
+ :type magnitude_op: function
+ :param units_op: operator function to perform on the units; if None, *magnitude_op* is used
+ :type units_op: function or None
+ """
+ if units_op is None:
+ units_op = magnitude_op
+
+ new_self = self
+ if self.__used:
+ if not _only_multiplicative_units(self):
+ new_self = self.to_base_units()
+
+ if _check(self, other):
+ if not _only_multiplicative_units(other):
+ other = other.to_base_units()
+ magnitude = magnitude_op(new_self._magnitude, other._magnitude)
+ units = units_op(new_self._units, other._units)
+ else:
+ try:
+ other_magnitude = _to_magnitude(other, self.force_ndarray)
+ except TypeError:
+ return NotImplemented
+ magnitude = magnitude_op(new_self._magnitude, other_magnitude)
+ units = units_op(new_self._units, UnitsContainer())
+
+ ret = self.__class__(magnitude, units)
+ ret.__used = True
+ return ret
def __imul__(self, other):
- return self._imul_div(other, operator.imul)
+ if not isinstance(self._magnitude, ndarray):
+ return self._mul_div(other, operator.mul)
+ else:
+ return self._imul_div(other, operator.imul)
def __mul__(self, other):
return self._mul_div(other, operator.mul)
@@ -399,13 +439,19 @@ class _Quantity(object):
__rmul__ = __mul__
def __itruediv__(self, other):
- return self._imul_div(other, operator.itruediv)
+ if not isinstance(self._magnitude, ndarray):
+ return self._mul_div(other, operator.truediv)
+ else:
+ return self._imul_div(other, operator.itruediv)
def __truediv__(self, other):
return self._mul_div(other, operator.truediv)
def __ifloordiv__(self, other):
- return self._imul_div(other, operator.ifloordiv, units_op=operator.itruediv)
+ if not isinstance(self._magnitude, ndarray):
+ return self._mul_div(other, operator.floordiv, units_op=operator.itruediv)
+ else:
+ return self._imul_div(other, operator.ifloordiv, units_op=operator.itruediv)
def __floordiv__(self, other):
return self._mul_div(other, operator.floordiv, units_op=operator.truediv)
@@ -429,6 +475,9 @@ class _Quantity(object):
__idiv__ = __itruediv__
def __ipow__(self, other):
+ if not isinstance(self._magnitude, ndarray):
+ return self.__pow__(other)
+
try:
other_magnitude = _to_magnitude(other, self.force_ndarray)
except TypeError:
@@ -441,8 +490,18 @@ class _Quantity(object):
return self
def __pow__(self, other):
- ret = copy.copy(self)
- return operator.ipow(ret, other)
+ try:
+ other_magnitude = _to_magnitude(other, self.force_ndarray)
+ except TypeError:
+ return NotImplemented
+ else:
+ new_self = self
+ if not _only_multiplicative_units(self):
+ new_self = self.to_base_units()
+
+ magnitude = new_self._magnitude ** _to_magnitude(other, self.force_ndarray)
+ units = new_self._units ** other
+ return self.__class__(magnitude, units)
def __abs__(self):
return self.__class__(abs(self._magnitude), self._units)
diff --git a/pint/testsuite/__init__.py b/pint/testsuite/__init__.py
index c29f7a7..98a506d 100644
--- a/pint/testsuite/__init__.py
+++ b/pint/testsuite/__init__.py
@@ -5,7 +5,7 @@ from __future__ import division, unicode_literals, print_function, absolute_impo
import os
import logging
-from pint.compat import ndarray, unittest
+from pint.compat import ndarray, unittest, np
from pint import logger, UnitRegistry
from pint.quantity import _Quantity
@@ -37,6 +37,8 @@ class TestHandler(BufferingHandler):
class TestCase(unittest.TestCase):
+ FORCE_NDARRAY = False
+
@classmethod
def setUpClass(cls):
cls.ureg = UnitRegistry(force_ndarray=cls.FORCE_NDARRAY)
@@ -61,6 +63,35 @@ class TestCase(unittest.TestCase):
seq2 = seq2.tolist()
unittest.TestCase.assertSequenceEqual(self, seq1, seq2, msg, seq_type)
+ def assertQuantityAlmostEqual(self, first, second, places=None, msg=None, delta=None):
+ if msg is None:
+ msg = 'Comparing %r and %r. ' % (first, second)
+
+ if isinstance(first, _Quantity) and isinstance(second, _Quantity):
+ second = second.to(first)
+ m1, m2 = first.magnitude, second.magnitude
+ self.assertEqual(first.units, second.units, msg=msg + 'Units are not equal.')
+ elif isinstance(first, _Quantity):
+ self.assertTrue(first.dimensionless, msg=msg + 'The first is not dimensionless.')
+ first = first.to('')
+ m1, m2 = first.magnitude, second
+ elif isinstance(second, _Quantity):
+ self.assertTrue(second.dimensionless, msg=msg + 'The second is not dimensionless.')
+ second = second.to('')
+ m1, m2 = first, second.magnitude
+ else:
+ m1, m2 = first, second
+
+ if isinstance(m1, ndarray) or isinstance(m2, ndarray):
+ if delta is not None:
+ rtol, atol = 0, delta
+ else:
+ places = places or 7
+ rtol, atol = 10 ** (-places), 0
+ np.testing.assert_allclose(m1, m2, rtol=rtol, atol=atol, err_msg=msg)
+ else:
+ unittest.TestCase.assertAlmostEqual(self, m1, m2, places, msg, delta)
+
def assertAlmostEqual(self, first, second, places=None, msg=None, delta=None):
if isinstance(first, _Quantity) and isinstance(second, _Quantity):
second = second.to(first)
diff --git a/pint/testsuite/test_issues.py b/pint/testsuite/test_issues.py
index a2e7e7b..270bfaf 100644
--- a/pint/testsuite/test_issues.py
+++ b/pint/testsuite/test_issues.py
@@ -228,6 +228,26 @@ class TestIssues(TestCase):
self.assertRaises(ValueError, func, 'METER')
self.assertEqual(val, func('METER', False))
+ def test_issue104(self):
+ ureg = UnitRegistry()
+
+ x = [ureg('1 meter'), ureg('1 meter'), ureg('1 meter')]
+ y = [ureg('1 meter')] * 3
+
+ def summer(values):
+ if not values:
+ return 0
+ total = values[0]
+ for v in values[1:]:
+ total += v
+
+ return total
+
+ self.assertQuantityAlmostEqual(summer(x), ureg.Quantity(3, 'meter'))
+ self.assertQuantityAlmostEqual(x[0], ureg.Quantity(1, 'meter'))
+ self.assertQuantityAlmostEqual(summer(y), ureg.Quantity(3, 'meter'))
+ self.assertQuantityAlmostEqual(y[0], ureg.Quantity(1, 'meter'))
+
@unittest.skipUnless(HAS_NUMPY, 'Numpy not present')
class TestIssuesNP(TestCase):
diff --git a/pint/testsuite/test_quantity.py b/pint/testsuite/test_quantity.py
index 0be2290..6ae0752 100644
--- a/pint/testsuite/test_quantity.py
+++ b/pint/testsuite/test_quantity.py
@@ -8,55 +8,14 @@ import operator as op
from pint import DimensionalityError, UnitRegistry
from pint.unit import UnitsContainer
-from pint.compat import string_types, PYTHON3
-from pint.testsuite import TestCase
+from pint.compat import string_types, PYTHON3, HAS_NUMPY, np
+from pint.testsuite import TestCase, unittest
class TestQuantity(TestCase):
FORCE_NDARRAY = False
- def _test_inplace(self, operator, value1, value2, expected_result):
- if isinstance(value1, string_types):
- value1 = self.Q_(value1)
- if isinstance(value2, string_types):
- value2 = self.Q_(value2)
- if isinstance(expected_result, string_types):
- expected_result = self.Q_(expected_result)
-
- value1 = copy.copy(value1)
- value2 = copy.copy(value2)
- id1 = id(value1)
- id2 = id(value2)
- value1 = operator(value1, value2)
- value2_cpy = copy.copy(value2)
- self.assertAlmostEqual(value1, expected_result)
- self.assertEqual(id1, id(value1))
- self.assertAlmostEqual(value2, value2_cpy)
- self.assertEqual(id2, id(value2))
-
- def _test_not_inplace(self, operator, value1, value2, expected_result):
- if isinstance(value1, string_types):
- value1 = self.Q_(value1)
- if isinstance(value2, string_types):
- value2 = self.Q_(value2)
- if isinstance(expected_result, string_types):
- expected_result = self.Q_(expected_result)
-
- id1 = id(value1)
- id2 = id(value2)
-
- value1_cpy = copy.copy(value1)
- value2_cpy = copy.copy(value2)
-
- result = operator(value1, value2)
-
- self.assertAlmostEqual(expected_result, result)
- self.assertAlmostEqual(value1, value1_cpy)
- self.assertAlmostEqual(value2, value2_cpy)
- self.assertNotEqual(id(result), id1)
- self.assertNotEqual(id(result), id2)
-
def test_quantity_creation(self):
for args in ((4.2, 'meter'),
(4.2, UnitsContainer(meter=1)),
@@ -162,100 +121,6 @@ class TestQuantity(TestCase):
ureg.default_format = spec
self.assertEqual('{0}'.format(x), result)
- def test_quantity_add_sub(self):
- x = self.Q_(1., 'centimeter')
- y = self.Q_(1., 'inch')
- z = self.Q_(1., 'second')
- a = self.Q_(1., None)
-
- self._test_not_inplace(op.add, x, x, self.Q_(2., 'centimeter'))
- self._test_not_inplace(op.add, x, y, self.Q_(1 + 2.54, 'centimeter'))
- self._test_not_inplace(op.add, y, x, self.Q_(1 + 1 / 2.54, 'inch'))
- self._test_not_inplace(op.add, a, 1, self.Q_(1 + 1, None))
- self.assertRaises(DimensionalityError, op.add, 10, x)
- self.assertRaises(DimensionalityError, op.add, x, 10)
- self.assertRaises(DimensionalityError, op.add, x, z)
-
- self._test_not_inplace(op.sub, x, x, self.Q_(0., 'centimeter'))
- self._test_not_inplace(op.sub, x, y, self.Q_(1 - 2.54, 'centimeter'))
- self._test_not_inplace(op.sub, y, x, self.Q_(1 - 1 / 2.54, 'inch'))
- self._test_not_inplace(op.sub, a, 1, self.Q_(1 - 1, None))
- self.assertRaises(DimensionalityError, op.sub, 10, x)
- self.assertRaises(DimensionalityError, op.sub, x, 10)
- self.assertRaises(DimensionalityError, op.sub, x, z)
-
- def test_quantity_iadd_isub(self):
- x = self.Q_(1., 'centimeter')
- y = self.Q_(1., 'inch')
- z = self.Q_(1., 'second')
- a = self.Q_(1., None)
-
- self._test_inplace(op.iadd, x, x, self.Q_(2., 'centimeter'))
- self._test_inplace(op.iadd, x, y, self.Q_(1 + 2.54, 'centimeter'))
- self._test_inplace(op.iadd, y, x, self.Q_(1 + 1 / 2.54, 'inch'))
- self._test_inplace(op.iadd, a, 1, self.Q_(1 + 1, None))
- self.assertRaises(DimensionalityError, op.iadd, 10, x)
- self.assertRaises(DimensionalityError, op.iadd, x, 10)
- self.assertRaises(DimensionalityError, op.iadd, x, z)
-
- self._test_inplace(op.isub, x, x, self.Q_(0., 'centimeter'))
- self._test_inplace(op.isub, x, y, self.Q_(1 - 2.54, 'centimeter'))
- self._test_inplace(op.isub, y, x, self.Q_(1 - 1 / 2.54, 'inch'))
- self._test_inplace(op.isub, a, 1, self.Q_(1 - 1, None))
- self.assertRaises(DimensionalityError, op.sub, 10, x)
- self.assertRaises(DimensionalityError, op.sub, x, 10)
- self.assertRaises(DimensionalityError, op.sub, x, z)
-
- def test_quantity_mul_div(self):
- self._test_not_inplace(op.mul, 10.0, '4.2*meter', '42*meter')
- self._test_not_inplace(op.mul, '4.2*meter', 10.0, '42*meter')
- self._test_not_inplace(op.mul, '4.2*meter', '10*inch', '42*meter*inch')
- self._test_not_inplace(op.truediv, 42, '4.2*meter', '10/meter')
- self._test_not_inplace(op.truediv, '4.2*meter', 10.0, '0.42*meter')
- self._test_not_inplace(op.truediv, '4.2*meter', '10*inch', '0.42*meter/inch')
-
- def test_quantity_imul_idiv(self):
- #self._test_inplace(op.imul, 10.0, '4.2*meter', '42*meter')
- self._test_inplace(op.imul, '4.2*meter', 10.0, '42*meter')
- self._test_inplace(op.imul, '4.2*meter', '10*inch', '42*meter*inch')
- #self._test_not_inplace(op.truediv, 42, '4.2*meter', '10/meter')
- self._test_inplace(op.itruediv, '4.2*meter', 10.0, '0.42*meter')
- self._test_inplace(op.itruediv, '4.2*meter', '10*inch', '0.42*meter/inch')
-
- def test_quantity_floordiv(self):
- self._test_not_inplace(op.floordiv, 10.0, '4.2*meter', '2/meter')
- self._test_not_inplace(op.floordiv, '24*meter', 10.0, '2*meter')
- self._test_not_inplace(op.floordiv, '10*meter', '4.2*inch', '2*meter/inch')
-
- #self._test_inplace(op.ifloordiv, 10.0, '4.2*meter', '2/meter')
- self._test_inplace(op.ifloordiv, '24*meter', 10.0, '2*meter')
- self._test_inplace(op.ifloordiv, '10*meter', '4.2*inch', '2*meter/inch')
-
- def test_quantity_abs_round(self):
-
- x = self.Q_(-4.2, 'meter')
- y = self.Q_(4.2, 'meter')
- # In Python 3+ round of x is delegated to x.__round__, instead of round(x.__float__)
- # and therefore it can be properly implemented by Pint
- for fun in (abs, op.pos, op.neg) + (round, ) if PYTHON3 else ():
- zx = self.Q_(fun(x.magnitude), 'meter')
- zy = self.Q_(fun(y.magnitude), 'meter')
- rx = fun(x)
- ry = fun(y)
- self.assertEqual(rx, zx, 'while testing {0}'.format(fun))
- self.assertEqual(ry, zy, 'while testing {0}'.format(fun))
- self.assertIsNot(rx, zx, 'while testing {0}'.format(fun))
- self.assertIsNot(ry, zy, 'while testing {0}'.format(fun))
-
- def test_quantity_float_complex(self):
- x = self.Q_(-4.2, None)
- y = self.Q_(4.2, None)
- z = self.Q_(1, 'meter')
- for fun in (float, complex):
- self.assertEqual(fun(x), fun(x.magnitude))
- self.assertEqual(fun(y), fun(y.magnitude))
- self.assertRaises(DimensionalityError, fun, z)
-
def test_to_base_units(self):
x = self.Q_('1*inch')
self.assertAlmostEqual(x.to_base_units(), self.Q_(0.0254, 'meter'))
@@ -351,6 +216,176 @@ class TestQuantity(TestCase):
pickle_test(self.Q_(2.4, 'm/s'))
+class TestQuantityBasicMath(TestCase):
+
+ FORCE_NDARRAY = False
+
+ def _test_inplace(self, operator, value1, value2, expected_result, unit=None):
+ if isinstance(value1, string_types):
+ value1 = self.Q_(value1)
+ if isinstance(value2, string_types):
+ value2 = self.Q_(value2)
+ if isinstance(expected_result, string_types):
+ expected_result = self.Q_(expected_result)
+
+ if not unit is None:
+ value1 = value1 * unit
+ value2 = value2 * unit
+ expected_result = expected_result * unit
+
+ value1 = copy.copy(value1)
+ value2 = copy.copy(value2)
+ id1 = id(value1)
+ id2 = id(value2)
+ value1 = operator(value1, value2)
+ value2_cpy = copy.copy(value2)
+ self.assertQuantityAlmostEqual(value1, expected_result)
+ self.assertEqual(id1, id(value1))
+ self.assertQuantityAlmostEqual(value2, value2_cpy)
+ self.assertEqual(id2, id(value2))
+
+ def _test_not_inplace(self, operator, value1, value2, expected_result, unit=None):
+ if isinstance(value1, string_types):
+ value1 = self.Q_(value1)
+ if isinstance(value2, string_types):
+ value2 = self.Q_(value2)
+ if isinstance(expected_result, string_types):
+ expected_result = self.Q_(expected_result)
+
+ if not unit is None:
+ value1 = value1 * unit
+ value2 = value2 * unit
+ expected_result = expected_result * unit
+
+ id1 = id(value1)
+ id2 = id(value2)
+
+ value1_cpy = copy.copy(value1)
+ value2_cpy = copy.copy(value2)
+
+ result = operator(value1, value2)
+
+ self.assertQuantityAlmostEqual(expected_result, result)
+ self.assertQuantityAlmostEqual(value1, value1_cpy)
+ self.assertQuantityAlmostEqual(value2, value2_cpy)
+ self.assertNotEqual(id(result), id1)
+ self.assertNotEqual(id(result), id2)
+
+ def _test_quantity_add_sub(self, unit, func):
+ x = self.Q_(unit, 'centimeter')
+ y = self.Q_(unit, 'inch')
+ z = self.Q_(unit, 'second')
+ a = self.Q_(unit, None)
+
+ func(op.add, x, x, self.Q_(unit + unit, 'centimeter'))
+ func(op.add, x, y, self.Q_(unit + 2.54 * unit, 'centimeter'))
+ func(op.add, y, x, self.Q_(unit + unit / (2.54 * unit), 'inch'))
+ func(op.add, a, unit, self.Q_(unit + unit, None))
+ self.assertRaises(DimensionalityError, op.add, 10, x)
+ self.assertRaises(DimensionalityError, op.add, x, 10)
+ self.assertRaises(DimensionalityError, op.add, x, z)
+
+ func(op.sub, x, x, self.Q_(unit - unit, 'centimeter'))
+ func(op.sub, x, y, self.Q_(unit - 2.54 * unit, 'centimeter'))
+ func(op.sub, y, x, self.Q_(unit - unit / (2.54 * unit), 'inch'))
+ func(op.sub, a, unit, self.Q_(unit - unit, None))
+ self.assertRaises(DimensionalityError, op.sub, 10, x)
+ self.assertRaises(DimensionalityError, op.sub, x, 10)
+ self.assertRaises(DimensionalityError, op.sub, x, z)
+
+ def _test_quantity_iadd_isub(self, unit, func):
+ x = self.Q_(unit, 'centimeter')
+ y = self.Q_(unit, 'inch')
+ z = self.Q_(unit, 'second')
+ a = self.Q_(unit, None)
+
+ func(op.iadd, x, x, self.Q_(unit + unit, 'centimeter'))
+ func(op.iadd, x, y, self.Q_(unit + 2.54 * unit, 'centimeter'))
+ func(op.iadd, y, x, self.Q_(unit + unit / 2.54, 'inch'))
+ func(op.iadd, a, unit, self.Q_(unit + unit, None))
+ self.assertRaises(DimensionalityError, op.iadd, 10, x)
+ self.assertRaises(DimensionalityError, op.iadd, x, 10)
+ self.assertRaises(DimensionalityError, op.iadd, x, z)
+
+ func(op.isub, x, x, self.Q_(unit - unit, 'centimeter'))
+ func(op.isub, x, y, self.Q_(unit - 2.54, 'centimeter'))
+ func(op.isub, y, x, self.Q_(unit - unit / 2.54, 'inch'))
+ func(op.isub, a, unit, self.Q_(unit - unit, None))
+ self.assertRaises(DimensionalityError, op.sub, 10, x)
+ self.assertRaises(DimensionalityError, op.sub, x, 10)
+ self.assertRaises(DimensionalityError, op.sub, x, z)
+
+ def _test_quantity_mul_div(self, unit, func):
+ func(op.mul, unit * 10.0, '4.2*meter', '42*meter', unit)
+ func(op.mul, '4.2*meter', unit * 10.0, '42*meter', unit)
+ func(op.mul, '4.2*meter', '10*inch', '42*meter*inch', unit)
+ func(op.truediv, unit * 42, '4.2*meter', '10/meter', unit)
+ func(op.truediv, '4.2*meter', unit * 10.0, '0.42*meter', unit)
+ func(op.truediv, '4.2*meter', '10*inch', '0.42*meter/inch', unit)
+
+ def _test_quantity_imul_idiv(self, unit, func):
+ #func(op.imul, 10.0, '4.2*meter', '42*meter')
+ func(op.imul, '4.2*meter', 10.0, '42*meter', unit)
+ func(op.imul, '4.2*meter', '10*inch', '42*meter*inch', unit)
+ #func(op.truediv, 42, '4.2*meter', '10/meter')
+ func(op.itruediv, '4.2*meter', unit * 10.0, '0.42*meter', unit)
+ func(op.itruediv, '4.2*meter', '10*inch', '0.42*meter/inch', unit)
+
+ def _test_quantity_floordiv(self, unit, func):
+ func(op.floordiv, unit * 10.0, '4.2*meter', '2/meter', unit)
+ func(op.floordiv, '24*meter', unit * 10.0, '2*meter', unit)
+ func(op.floordiv, '10*meter', '4.2*inch', '2*meter/inch', unit)
+
+ def _test_quantity_ifloordiv(self, unit, func):
+ func(op.ifloordiv, 10.0, '4.2*meter', '2/meter', unit)
+ func(op.ifloordiv, '24*meter', 10.0, '2*meter', unit)
+ func(op.ifloordiv, '10*meter', '4.2*inch', '2*meter/inch', unit)
+
+ def _test_numeric(self, unit, ifunc):
+ self._test_quantity_add_sub(unit, self._test_not_inplace)
+ self._test_quantity_iadd_isub(unit, ifunc)
+ self._test_quantity_mul_div(unit, self._test_not_inplace)
+ self._test_quantity_imul_idiv(unit, ifunc)
+ self._test_quantity_floordiv(unit, self._test_not_inplace)
+ #self._test_quantity_ifloordiv(unit, ifunc)
+
+ def test_float(self):
+ self._test_numeric(1., self._test_not_inplace)
+
+ def test_fraction(self):
+ import fractions
+ self._test_numeric(fractions.Fraction(1, 1), self._test_not_inplace)
+
+ @unittest.skipUnless(HAS_NUMPY, 'Requires Numpy')
+ def test_nparray(self):
+ self._test_numeric(np.ones((1, 3)), self._test_inplace)
+
+ def test_quantity_abs_round(self):
+
+ x = self.Q_(-4.2, 'meter')
+ y = self.Q_(4.2, 'meter')
+ # In Python 3+ round of x is delegated to x.__round__, instead of round(x.__float__)
+ # and therefore it can be properly implemented by Pint
+ for fun in (abs, op.pos, op.neg) + (round, ) if PYTHON3 else ():
+ zx = self.Q_(fun(x.magnitude), 'meter')
+ zy = self.Q_(fun(y.magnitude), 'meter')
+ rx = fun(x)
+ ry = fun(y)
+ self.assertEqual(rx, zx, 'while testing {0}'.format(fun))
+ self.assertEqual(ry, zy, 'while testing {0}'.format(fun))
+ self.assertIsNot(rx, zx, 'while testing {0}'.format(fun))
+ self.assertIsNot(ry, zy, 'while testing {0}'.format(fun))
+
+ def test_quantity_float_complex(self):
+ x = self.Q_(-4.2, None)
+ y = self.Q_(4.2, None)
+ z = self.Q_(1, 'meter')
+ for fun in (float, complex):
+ self.assertEqual(fun(x), fun(x.magnitude))
+ self.assertEqual(fun(y), fun(y.magnitude))
+ self.assertRaises(DimensionalityError, fun, z)
+
+
class TestDimensions(TestCase):
FORCE_NDARRAY = False