Repository: hgrecco/pint

Issue:
Wrong handling of reducable units by Quantity.__pow__
Reducable units (like inch / millimeter) are dropped when performing certain basic operations with a numpy array. This is applicable to `Quantity**array` but not `array**Quantity`. I will review the code and make a PR with any other related bugs I find.

```
import pint
import numpy as np
```
Correct behavior
```
np.power(pint.Quantity(3, "in / mm").m_as(""), np.array((3, 2)))
> array([442450.728,   5806.44 ])
pint.Quantity(3, "in / mm").m_as("") ** np.array((3, 2))
> array([442450.728,   5806.44 ])
pint.Quantity(3, "in / mm") ** 3
> <Quantity(27, 'inch ** 3 / millimeter ** 3')>
```
Incorrect behavior
```
np.power(pint.Quantity(3, "in / mm"), np.array((3, 2)))
> <Quantity([27  9], 'dimensionless')>
pint.Quantity(3, "in / mm") ** np.array((3, 2))
> <Quantity([27  9], 'dimensionless')>
```

Discussion:

Patch:
diff --git a/CHANGES b/CHANGES
index cf50d1e..e3ef610 100644
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,8 @@ Pint Changelog
 0.17 (unreleased)
 -----------------
 
+- Fix issue with reducable dimensionless units when using power (Quantity**ndarray)
+  (Issue #1185)
 - Fix comparisons between Quantities and Measurements.
    (Issue #1134, thanks lewisamarshall)
 - Implemented benchmarks based on airspeed velocity.
@@ -14,6 +16,7 @@ Pint Changelog
 - Add Github Actions CI. (Issue #1236)
 - Fix numpy.linalg.solve unit output. (Issue #1246)
 
+
 0.16.1 (2020-09-22)
 -------------------
 
diff --git a/pint/quantity.py b/pint/quantity.py
index 265e0af..82cc1af 100644
--- a/pint/quantity.py
+++ b/pint/quantity.py
@@ -1385,15 +1385,19 @@ class Quantity(PrettyIPython, SharedRegistryObject):
             if is_duck_array_type(type(getattr(other, "_magnitude", other))):
                 # arrays are refused as exponent, because they would create
                 # len(array) quantities of len(set(array)) different units
-                # unless the base is dimensionless.
+                # unless the base is dimensionless. Ensure dimensionless
+                # units are reduced to "dimensionless".
+                # Note: this will strip Units of degrees or radians from Quantity
                 if self.dimensionless:
                     if getattr(other, "dimensionless", False):
-                        self._magnitude **= other.m_as("")
+                        self._magnitude = self.m_as("") ** other.m_as("")
+                        self._units = self.UnitsContainer()
                         return self
                     elif not getattr(other, "dimensionless", True):
                         raise DimensionalityError(other._units, "dimensionless")
                     else:
-                        self._magnitude **= other
+                        self._magnitude = self.m_as("") ** other
+                        self._units = self.UnitsContainer()
                         return self
                 elif np.size(other) > 1:
                     raise DimensionalityError(
@@ -1443,13 +1447,20 @@ class Quantity(PrettyIPython, SharedRegistryObject):
                 # arrays are refused as exponent, because they would create
                 # len(array) quantities of len(set(array)) different units
                 # unless the base is dimensionless.
+                # Note: this will strip Units of degrees or radians from Quantity
                 if self.dimensionless:
                     if getattr(other, "dimensionless", False):
-                        return self.__class__(self.m ** other.m_as(""))
+                        return self.__class__(
+                            self._convert_magnitude_not_inplace(self.UnitsContainer())
+                            ** other.m_as("")
+                        )
                     elif not getattr(other, "dimensionless", True):
                         raise DimensionalityError(other._units, "dimensionless")
                     else:
-                        return self.__class__(self.m ** other)
+                        return self.__class__(
+                            self._convert_magnitude_not_inplace(self.UnitsContainer())
+                            ** other
+                        )
                 elif np.size(other) > 1:
                     raise DimensionalityError(
                         self._units,


Test patch:
diff --git a/pint/testsuite/test_issues.py b/pint/testsuite/test_issues.py
index 52309f2..5058838 100644
--- a/pint/testsuite/test_issues.py
+++ b/pint/testsuite/test_issues.py
@@ -797,6 +797,26 @@ class TestIssues(QuantityTestCase):
         assert np.sign(q[0].magnitude)
         assert np.sign(q[1].magnitude)
 
+    @helpers.requires_numpy()
+    def test_issue_1185(self):
+        # Test __pow__
+        foo = ureg.Quantity((3, 3), "mm / cm")
+        assert np.allclose(foo ** ureg.Quantity([2, 3], ""), 0.3 ** np.array([2, 3]))
+        assert np.allclose(foo ** np.array([2, 3]), 0.3 ** np.array([2, 3]))
+        assert np.allclose(np.array([2, 3]) ** foo, np.array([2, 3]) ** 0.3)
+        # Test __ipow__
+        foo **= np.array([2, 3])
+        assert np.allclose(foo, 0.3 ** np.array([2, 3]))
+        # Test __rpow__
+        assert np.allclose(
+            np.array((1, 1)).__rpow__(ureg.Quantity((2, 3), "mm / cm")),
+            np.array((0.2, 0.3)),
+        )
+        assert np.allclose(
+            ureg.Quantity((20, 20), "mm / cm").__rpow__(np.array((0.2, 0.3))),
+            np.array((0.04, 0.09)),
+        )
+
 
 if np is not None: