Skip to content

Commit 013b056

Browse files
committed
implement DataArray.pint.to
1 parent b37bdd4 commit 013b056

File tree

1 file changed

+42
-17
lines changed

1 file changed

+42
-17
lines changed

pintxarray/accessors.py

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
# TODO is it possible to import pint-xarray from within xarray if pint is present?
2+
import numpy as np
3+
import pint
4+
from pint.quantity import Quantity
5+
from pint.unit import Unit
26
from xarray import (
3-
register_dataarray_accessor,
4-
register_dataset_accessor,
57
DataArray,
68
Dataset,
79
Variable,
10+
register_dataarray_accessor,
11+
register_dataset_accessor,
812
)
913
from xarray.core.npcompat import IS_NEP18_ACTIVE
1014

11-
import numpy as np
12-
13-
import pint
14-
from pint.quantity import Quantity
15-
from pint.unit import Unit
16-
15+
from . import conversion
1716

1817
if not hasattr(Quantity, "__array_function__"):
1918
raise ImportError(
@@ -32,6 +31,28 @@
3231
# TODO type hints
3332

3433

34+
def is_dict_like(obj):
35+
return hasattr(obj, "keys") and hasattr(obj, "__getitem__")
36+
37+
38+
def either_dict_or_kwargs(positional, keywords, method_name):
39+
if positional is not None:
40+
if not is_dict_like(positional):
41+
raise ValueError(
42+
f"the first argument to .{method_name} must be a dictionary"
43+
)
44+
if keywords:
45+
raise ValueError(
46+
"cannot specify both keyword and positional "
47+
f"arguments to .{method_name}"
48+
)
49+
return positional
50+
else:
51+
# Need an explicit cast to appease mypy due to invariance; see
52+
# https://github.com/python/mypy/issues/6228
53+
return keywords
54+
55+
3556
def _array_attach_units(data, unit, convert_from=None):
3657
"""
3758
Internal utility function for attaching units to a numpy-like array,
@@ -233,15 +254,19 @@ def registry(self):
233254
def registry(self, _):
234255
raise AttributeError("Don't try to change the registry once created")
235256

236-
def to(self, units):
237-
quantity = self.da.data.to(units)
238-
return DataArray(
239-
dim=self.da.dims,
240-
data=quantity,
241-
coords=self.da.coords,
242-
attrs=self.da.attrs,
243-
encoding=self.da.encoding,
244-
)
257+
def to(self, units=None, *, registry=None, **unit_kwargs):
258+
if isinstance(units, (str, pint.Unit)):
259+
unit_kwargs[self.da.name] = units
260+
units = None
261+
elif not is_dict_like(units):
262+
raise ValueError(
263+
"units must be either a string, a pint.Unit object or a dict-like,"
264+
f" but got {units!r}"
265+
)
266+
267+
units = either_dict_or_kwargs(units, unit_kwargs, "to")
268+
269+
return conversion.convert_units(self.da, units)
245270

246271
def to_base_units(self):
247272
quantity = self.da.data.to_base_units()

0 commit comments

Comments
 (0)