Repository: hgrecco/pint

Issue:
Unit tests fails with numpy 1.13.1
Refs: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=876921

Thanks for fixing.

```
S.S................................................./usr/lib/python2.7/unittest/case.py:340: RuntimeWarning: TestResult has no addExpectedFailure method, reporting as passes
  RuntimeWarning)
.......S...S............................SSSSSSSSSSS.................S...................................................................................................................................................E.E...E.................................................................................................................................................................................................................................................................................................../build/1st/python-pint-0.8.1/.pybuild/pythonX.Y_2.7/build/pint/testsuite/test_quantity.py:287: RuntimeWarning: to_compact applied to non numerical types has an undefined behavior.
  self.assertQuantityAlmostIdentical(q.to_compact(unit=unit),
.......................................F..F..........................................................................................................................................................................
======================================================================
ERROR: test_inplace_exponentiation (pint.testsuite.test_quantity.TestOffsetUnitMath) [with input = ((10, u'degC'), (2, u'')); expected_output = [u'error', (80173.92249999999, u'kelvin**2')]]
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/build/1st/python-pint-0.8.1/.pybuild/pythonX.Y_2.7/build/pint/testsuite/parameterized.py", line 116, in new_method
    return method(self, *param_values)
  File "/build/1st/python-pint-0.8.1/.pybuild/pythonX.Y_2.7/build/pint/testsuite/parameterized.py", line 137, in newfunc
    return func(*arg, **kwargs)
  File "/build/1st/python-pint-0.8.1/.pybuild/pythonX.Y_2.7/build/pint/testsuite/test_quantity.py", line 1165, in test_inplace_exponentiation
    self.assertEqual(op.ipow(in1_cp, in2).units, expected.units)
  File "/build/1st/python-pint-0.8.1/.pybuild/pythonX.Y_2.7/build/pint/quantity.py", line 961, in __ipow__
    self._magnitude **= _to_magnitude(other, self.force_ndarray)
TypeError: unsupported operand type(s) for ** or pow(): 'numpy.ndarray' and 'Quantity'

======================================================================
ERROR: test_inplace_exponentiation (pint.testsuite.test_quantity.TestOffsetUnitMath) [with input = ((10, u'kelvin'), (2, u'')); expected_output = [(100.0, u'kelvin**2'), (100.0, u'kelvin**2')]]
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/build/1st/python-pint-0.8.1/.pybuild/pythonX.Y_2.7/build/pint/testsuite/parameterized.py", line 116, in new_method
    return method(self, *param_values)
  File "/build/1st/python-pint-0.8.1/.pybuild/pythonX.Y_2.7/build/pint/testsuite/parameterized.py", line 137, in newfunc
    return func(*arg, **kwargs)
  File "/build/1st/python-pint-0.8.1/.pybuild/pythonX.Y_2.7/build/pint/testsuite/test_quantity.py", line 1165, in test_inplace_exponentiation
    self.assertEqual(op.ipow(in1_cp, in2).units, expected.units)
  File "/build/1st/python-pint-0.8.1/.pybuild/pythonX.Y_2.7/build/pint/quantity.py", line 961, in __ipow__
    self._magnitude **= _to_magnitude(other, self.force_ndarray)
TypeError: unsupported operand type(s) for ** or pow(): 'numpy.ndarray' and 'Quantity'

======================================================================
ERROR: test_inplace_exponentiation (pint.testsuite.test_quantity.TestOffsetUnitMath) [with input = ((10, u'degC'), (500.0, u'millikelvin/kelvin')); expected_output = [u'error', (16.827061537891872, u'kelvin**0.5')]]
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/build/1st/python-pint-0.8.1/.pybuild/pythonX.Y_2.7/build/pint/testsuite/parameterized.py", line 116, in new_method
    return method(self, *param_values)
  File "/build/1st/python-pint-0.8.1/.pybuild/pythonX.Y_2.7/build/pint/testsuite/parameterized.py", line 137, in newfunc
    return func(*arg, **kwargs)
  File "/build/1st/python-pint-0.8.1/.pybuild/pythonX.Y_2.7/build/pint/testsuite/test_quantity.py", line 1165, in test_inplace_exponentiation
    self.assertEqual(op.ipow(in1_cp, in2).units, expected.units)
  File "/build/1st/python-pint-0.8.1/.pybuild/pythonX.Y_2.7/build/pint/quantity.py", line 961, in __ipow__
    self._magnitude **= _to_magnitude(other, self.force_ndarray)
TypeError: unsupported operand type(s) for ** or pow(): 'numpy.ndarray' and 'Quantity'

======================================================================
FAIL: test_isfinite (pint.testsuite.test_umath.TestFloatingUfuncs)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/build/1st/python-pint-0.8.1/.pybuild/pythonX.Y_2.7/build/pint/testsuite/test_umath.py", line 617, in test_isfinite
    (self.q1, self.qm, self.qless))
  File "/build/1st/python-pint-0.8.1/.pybuild/pythonX.Y_2.7/build/pint/testsuite/test_umath.py", line 101, in _testn
    self._test1(func, ok_with, raise_with, output_units=None, results=results)
  File "/build/1st/python-pint-0.8.1/.pybuild/pythonX.Y_2.7/build/pint/testsuite/test_umath.py", line 85, in _test1
    self.assertQuantityAlmostEqual(qm, res, rtol=rtol, msg=err_msg)
  File "/build/1st/python-pint-0.8.1/.pybuild/pythonX.Y_2.7/build/pint/testsuite/__init__.py", line 117, in assertQuantityAlmostEqual
    np.testing.assert_allclose(m1, m2, rtol=rtol, atol=atol, err_msg=msg)
  File "/usr/lib/python2.7/dist-packages/numpy/testing/utils.py", line 1395, in assert_allclose
    verbose=verbose, header=header, equal_nan=equal_nan)
  File "/usr/lib/python2.7/dist-packages/numpy/testing/utils.py", line 778, in assert_array_compare
    raise AssertionError(msg)
AssertionError: 
Not equal to tolerance rtol=1e-06, atol=0
At isreal with [ 1.  2.  3.  4.] joule
(mismatch 100.0%)
 x: array(False, dtype=bool)
 y: array([ True,  True,  True,  True], dtype=bool)

======================================================================
FAIL: test_isreal (pint.testsuite.test_umath.TestFloatingUfuncs)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/build/1st/python-pint-0.8.1/.pybuild/pythonX.Y_2.7/build/pint/testsuite/test_umath.py", line 609, in test_isreal
    (self.q1, self.qm, self.qless))
  File "/build/1st/python-pint-0.8.1/.pybuild/pythonX.Y_2.7/build/pint/testsuite/test_umath.py", line 101, in _testn
    self._test1(func, ok_with, raise_with, output_units=None, results=results)
  File "/build/1st/python-pint-0.8.1/.pybuild/pythonX.Y_2.7/build/pint/testsuite/test_umath.py", line 85, in _test1
    self.assertQuantityAlmostEqual(qm, res, rtol=rtol, msg=err_msg)
  File "/build/1st/python-pint-0.8.1/.pybuild/pythonX.Y_2.7/build/pint/testsuite/__init__.py", line 117, in assertQuantityAlmostEqual
    np.testing.assert_allclose(m1, m2, rtol=rtol, atol=atol, err_msg=msg)
  File "/usr/lib/python2.7/dist-packages/numpy/testing/utils.py", line 1395, in assert_allclose
    verbose=verbose, header=header, equal_nan=equal_nan)
  File "/usr/lib/python2.7/dist-packages/numpy/testing/utils.py", line 778, in assert_array_compare
    raise AssertionError(msg)
AssertionError: 
Not equal to tolerance rtol=1e-06, atol=0
At isreal with [ 1.  2.  3.  4.] joule
(mismatch 100.0%)
 x: array(False, dtype=bool)
 y: array([ True,  True,  True,  True], dtype=bool)

----------------------------------------------------------------------
Ran 779 tests in 40.510s
```

Comments:

Patch:
diff --git a/.travis.yml b/.travis.yml
index 800263e..fd6781b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,7 +1,6 @@
 language: python
 
 env:
-  - UNCERTAINTIES="N" PYTHON="2.7" NUMPY_VERSION=1.11.2
   - UNCERTAINTIES="N" PYTHON="3.3" NUMPY_VERSION=1.9.2
   - UNCERTAINTIES="N" PYTHON="3.4" NUMPY_VERSION=1.11.2
   - UNCERTAINTIES="N" PYTHON="3.5" NUMPY_VERSION=1.11.2
@@ -9,6 +8,12 @@ env:
   - UNCERTAINTIES="N" PYTHON="3.6" NUMPY_VERSION=1.11.2
   - UNCERTAINTIES="N" PYTHON="2.7" NUMPY_VERSION=0
   - UNCERTAINTIES="N" PYTHON="3.5" NUMPY_VERSION=0
+  # Test with the latest numpy version
+  - UNCERTAINTIES="N" PYTHON="2.7" NUMPY_VERSION=1.14
+  - UNCERTAINTIES="N" PYTHON="3.4" NUMPY_VERSION=1.14
+  - UNCERTAINTIES="N" PYTHON="3.5" NUMPY_VERSION=1.14
+  - UNCERTAINTIES="Y" PYTHON="3.5" NUMPY_VERSION=1.14
+  - UNCERTAINTIES="N" PYTHON="3.6" NUMPY_VERSION=1.14
 
 before_install:
   - sudo apt-get update
diff --git a/pint/quantity.py b/pint/quantity.py
index 8a6599b..88bfdac 100644
--- a/pint/quantity.py
+++ b/pint/quantity.py
@@ -1003,8 +1003,8 @@ class _Quantity(PrettyIPython, SharedRegistryObject):
                         raise OffsetUnitCalculusError(self._units)
 
                 if getattr(other, 'dimensionless', False):
-                    other = other.to_base_units()
-                    self._units **= other.magnitude
+                    other = other.to_base_units().magnitude
+                    self._units **= other
                 elif not getattr(other, 'dimensionless', True):
                     raise DimensionalityError(self._units, 'dimensionless')
                 else:
@@ -1090,6 +1090,20 @@ class _Quantity(PrettyIPython, SharedRegistryObject):
         # We compare to the base class of Quantity because
         # each Quantity class is unique.
         if not isinstance(other, _Quantity):
+            if _eq(other, 0, True):
+                # Handle the special case in which we compare to zero
+                # (or an array of zeros)
+                if self._is_multiplicative:
+                    # compare magnitude
+                    return _eq(self._magnitude, other, False)
+                else:
+                    # compare the magnitude after converting the
+                    # non-multiplicative quantity to base units
+                    if self._REGISTRY.autoconvert_offset_to_baseunit:
+                        return _eq(self.to_base_units()._magnitude, other, False)
+                    else:
+                        raise OffsetUnitCalculusError(self._units)
+
             return (self.dimensionless and
                     _eq(self._convert_magnitude(UnitsContainer()), other, False))
 
@@ -1115,6 +1129,19 @@ class _Quantity(PrettyIPython, SharedRegistryObject):
         if not isinstance(other, self.__class__):
             if self.dimensionless:
                 return op(self._convert_magnitude_not_inplace(UnitsContainer()), other)
+            elif _eq(other, 0, True):
+                # Handle the special case in which we compare to zero
+                # (or an array of zeros)
+                if self._is_multiplicative:
+                    # compare magnitude
+                    return op(self._magnitude, other)
+                else:
+                    # compare the magnitude after converting the
+                    # non-multiplicative quantity to base units
+                    if self._REGISTRY.autoconvert_offset_to_baseunit:
+                        return op(self.to_base_units()._magnitude, other)
+                    else:
+                        raise OffsetUnitCalculusError(self._units)
             else:
                 raise ValueError('Cannot compare Quantity and {}'.format(type(other)))
 


Test patch:
diff --git a/pint/testsuite/test_quantity.py b/pint/testsuite/test_quantity.py
index 54d460a..5c0e22b 100644
--- a/pint/testsuite/test_quantity.py
+++ b/pint/testsuite/test_quantity.py
@@ -1296,3 +1296,107 @@ class TestTimedelta(QuantityTestCase):
         after = 3 * self.ureg.second
         with self.assertRaises(DimensionalityError):
             after -= d
+
+
+class TestCompareZero(QuantityTestCase):
+    """This test case checks the special treatment that the zero value
+    receives in the comparisons: pint>=0.9 supports comparisons against zero
+    even for non-dimensionless quantities
+    """
+
+    def test_equal_zero(self):
+        ureg = self.ureg
+        ureg.autoconvert_offset_to_baseunit = False
+        self.assertTrue(ureg.Quantity(0, ureg.J) == 0)
+        self.assertFalse(ureg.Quantity(0, ureg.J) == ureg.Quantity(0, ''))
+        self.assertFalse(ureg.Quantity(5, ureg.J) == 0)
+
+    @helpers.requires_numpy()
+    def test_equal_zero_NP(self):
+        ureg = self.ureg
+        ureg.autoconvert_offset_to_baseunit = False
+        aeq = np.testing.assert_array_equal
+        aeq(ureg.Quantity(0, ureg.J) == np.zeros(3),
+            np.asarray([True, True, True]))
+        aeq(ureg.Quantity(5, ureg.J) == np.zeros(3),
+            np.asarray([False, False, False]))
+        aeq(ureg.Quantity(np.arange(3), ureg.J) == np.zeros(3),
+            np.asarray([True, False, False]))
+        self.assertFalse(ureg.Quantity(np.arange(4), ureg.J) == np.zeros(3))
+
+    def test_offset_equal_zero(self):
+        ureg =  self.ureg
+        ureg.autoconvert_offset_to_baseunit = False
+        q0 = ureg.Quantity(-273.15, 'degC')
+        q1 = ureg.Quantity(0, 'degC')
+        q2 = ureg.Quantity(5, 'degC')
+        self.assertRaises(OffsetUnitCalculusError, q0.__eq__, 0)
+        self.assertRaises(OffsetUnitCalculusError, q1.__eq__, 0)
+        self.assertRaises(OffsetUnitCalculusError, q2.__eq__, 0)
+        self.assertFalse(q0 == ureg.Quantity(0, ''))
+
+    def test_offset_autoconvert_equal_zero(self):
+        ureg =  self.ureg
+        ureg.autoconvert_offset_to_baseunit = True
+        q0 = ureg.Quantity(-273.15, 'degC')
+        q1 = ureg.Quantity(0, 'degC')
+        q2 = ureg.Quantity(5, 'degC')
+        self.assertTrue(q0 == 0)
+        self.assertFalse(q1 == 0)
+        self.assertFalse(q2 == 0)
+        self.assertFalse(q0 == ureg.Quantity(0, ''))
+
+    def test_gt_zero(self):
+        ureg = self.ureg
+        ureg.autoconvert_offset_to_baseunit = False
+        q0 = ureg.Quantity(0, 'J')
+        q0m = ureg.Quantity(0, 'm')
+        q0less = ureg.Quantity(0, '')
+        qpos = ureg.Quantity(5, 'J')
+        qneg = ureg.Quantity(-5, 'J')
+        self.assertTrue(qpos > q0)
+        self.assertTrue(qpos > 0)
+        self.assertFalse(qneg > 0)
+        self.assertRaises(DimensionalityError, qpos.__gt__, q0less)
+        self.assertRaises(DimensionalityError, qpos.__gt__, q0m)
+
+    @helpers.requires_numpy()
+    def test_gt_zero_NP(self):
+        ureg = self.ureg
+        ureg.autoconvert_offset_to_baseunit = False
+        qpos = ureg.Quantity(5, 'J')
+        qneg = ureg.Quantity(-5, 'J')
+        aeq = np.testing.assert_array_equal
+        aeq(qpos > np.zeros(3), np.asarray([True, True, True]))
+        aeq(qneg > np.zeros(3), np.asarray([False, False, False]))
+        aeq(ureg.Quantity(np.arange(-1, 2), ureg.J) > np.zeros(3),
+            np.asarray([False, False, True]))
+        aeq(ureg.Quantity(np.arange(-1, 2), ureg.J) > np.zeros(3),
+            np.asarray([False, False, True]))
+        self.assertRaises(ValueError,
+                          ureg.Quantity(np.arange(-1, 2), ureg.J).__gt__,
+                          np.zeros(4))
+
+    def test_offset_gt_zero(self):
+        ureg =  self.ureg
+        ureg.autoconvert_offset_to_baseunit = False
+        q0 = ureg.Quantity(-273.15, 'degC')
+        q1 = ureg.Quantity(0, 'degC')
+        q2 = ureg.Quantity(5, 'degC')
+        self.assertRaises(OffsetUnitCalculusError, q0.__gt__, 0)
+        self.assertRaises(OffsetUnitCalculusError, q1.__gt__, 0)
+        self.assertRaises(OffsetUnitCalculusError, q2.__gt__, 0)
+        self.assertRaises(DimensionalityError, q1.__gt__,
+                          ureg.Quantity(0, ''))
+
+    def test_offset_autoconvert_gt_zero(self):
+        ureg =  self.ureg
+        ureg.autoconvert_offset_to_baseunit = True
+        q0 = ureg.Quantity(-273.15, 'degC')
+        q1 = ureg.Quantity(0, 'degC')
+        q2 = ureg.Quantity(5, 'degC')
+        self.assertFalse(q0 > 0)
+        self.assertTrue(q1 > 0)
+        self.assertTrue(q2 > 0)
+        self.assertRaises(DimensionalityError, q1.__gt__,
+                          ureg.Quantity(0, ''))
\ No newline at end of file
diff --git a/pint/testsuite/test_umath.py b/pint/testsuite/test_umath.py
index 0d0c544..589aaa4 100644
--- a/pint/testsuite/test_umath.py
+++ b/pint/testsuite/test_umath.py
@@ -613,7 +613,7 @@ class TestFloatingUfuncs(TestUFuncs):
                     (self.q1, self.qm, self.qless))
 
     def test_isfinite(self):
-        self._testn(np.isreal,
+        self._testn(np.isfinite,
                     (self.q1, self.qm, self.qless))
 
     def test_isinf(self):