Repository: hgrecco/pint-pandas

Issue:
`PintArray` should accept Quantity arrays directly
Given a Quantity array `q`, the correct way to create a `PintArrray` currently is to call `PintArray(q.magnitude, q.units)`.
One may be tempted to instead call `PintArray(q, q.units)` instead, which gives the correct result, but causes a `UnitsStrippedWarning` to be raised. Either way, it would be much more convenient to simply call `PintArray(q)`.

Furthermore, one may instead expect `PintArray(q, some_unit)` to do the right thing(TM) (convert to `some_unit` if possible, otherwise fail loudly) - however, the units are just silently being replaced.

Discussion:

Patch:
diff --git a/CHANGES b/CHANGES
index 02d0c86..c53f686 100644
--- a/CHANGES
+++ b/CHANGES
@@ -8,6 +8,8 @@ pint-pandas Changelog
   to convert input arrays to lists of Quantity, thereby causing a huge slowdown. #80
 - Fixed a bug where listlike operands in binary operations were not correctly converted to Quantity arrays. #86
 - Fixed pickling of `PintArray` instances. #71
+- Fixed a bug where units of a quantity where ignored when creating a PintArray. #104
+- Quantity arrays may be used to initialise PintArrays without specifying the dtype. #104
 
 0.2 (2021-03-23)
 ----------------
diff --git a/pint_pandas/pint_array.py b/pint_pandas/pint_array.py
index 9c418ca..a707580 100644
--- a/pint_pandas/pint_array.py
+++ b/pint_pandas/pint_array.py
@@ -179,17 +179,40 @@ class PintType(ExtensionDtype):
 
 
 class PintArray(ExtensionArray, ExtensionOpsMixin):
+    """Implements a class to describe an array of physical quantities:
+    the product of an array of numerical values and a unit of measurement.
+
+    Parameters
+    ----------
+    values : pint.Quantity or array-like
+        Array of physical quantity values to be created.
+    dtype : PintType, str, or pint.Unit
+        Units of the physical quantity to be created. (Default value = None)
+        When values is a pint.Quantity, passing None as the dtype will use
+        the units from the pint.Quantity.
+    copy: bool
+        Whether to copy the values.
+    Returns
+    -------
+
+    """
+
     _data = np.array([])
     context_name = None
     context_units = None
 
     def __init__(self, values, dtype=None, copy=False):
+        if dtype is None and isinstance(values, _Quantity):
+            dtype = values.units
         if dtype is None:
             raise NotImplementedError
 
         if not isinstance(dtype, PintType):
             dtype = PintType(dtype)
         self._dtype = dtype
+
+        if isinstance(values, _Quantity):
+            values = values.to(dtype.units).magnitude
         if not isinstance(values, np.ndarray):
             values = np.array(values, copy=copy)
             copy = False


Test patch:
diff --git a/pint_pandas/testsuite/test_issues.py b/pint_pandas/testsuite/test_issues.py
index 787e24e..d059314 100644
--- a/pint_pandas/testsuite/test_issues.py
+++ b/pint_pandas/testsuite/test_issues.py
@@ -4,6 +4,7 @@ import time
 import numpy as np
 import pandas as pd
 import pytest
+from pint.testsuite import helpers
 
 import pint_pandas as ppi
 from pint_pandas import PintArray
@@ -79,3 +80,13 @@ def test_issue_71():
     s = pickle.dumps(a)
     b = pickle.loads(s)
     assert np.all(a == b)
+
+
+def test_issue_88():
+    q_m = ureg.Quantity([1, 2], "m")
+    a = PintArray(q_m)
+    helpers.assert_quantity_almost_equal(q_m, a.quantity)
+
+    q_mm = ureg.Quantity([1000, 2000], "mm")
+    b = PintArray(q_mm, "m")
+    helpers.assert_quantity_almost_equal(q_m, b.quantity)