Skip to content

Commit ed43021

Browse files
committed
Add support for NumPy 2.0
1 parent b47419a commit ed43021

5 files changed

Lines changed: 22 additions & 35 deletions

File tree

.github/workflows/test.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ jobs:
3434
- python-version: "3.12"
3535
numpy-version: "1.26"
3636
os: ubuntu-latest
37+
- python-version: "3.12"
38+
numpy-version: "2.0"
39+
os: ubuntu-latest
3740
steps:
3841
- uses: actions/checkout@v2
3942

@@ -128,4 +131,4 @@ jobs:
128131
129132
- name: Check type information
130133
run: |
131-
mypy quantities
134+
mypy quantities

quantities/quantity.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -120,9 +120,9 @@ def __new__(cls, data, units='', dtype=None, copy=True):
120120
data = data.rescale(units)
121121
if isinstance(data, unit_registry['UnitQuantity']):
122122
return 1*data
123-
return np.array(data, dtype=dtype, copy=copy, subok=True).view(cls)
123+
return np.asanyarray(data, dtype=dtype).view(cls)
124124

125-
ret = np.array(data, dtype=dtype, copy=copy).view(cls)
125+
ret = np.asarray(data, dtype=dtype).view(cls)
126126
ret._dimensionality.update(validate_dimensionality(units))
127127
return ret
128128

@@ -210,15 +210,17 @@ def rescale(self, units=None, dtype=None):
210210
dtype = self.dtype
211211
if self.dimensionality == to_dims:
212212
return self.astype(dtype)
213-
to_u = Quantity(1.0, to_dims)
214-
from_u = Quantity(1.0, self.dimensionality)
213+
to_u = Quantity(1.0, to_dims, dtype=dtype)
214+
from_u = Quantity(1.0, self.dimensionality, dtype=dtype)
215215
try:
216216
cf = get_conversion_factor(from_u, to_u)
217217
except AssertionError:
218218
raise ValueError(
219219
'Unable to convert between units of "%s" and "%s"'
220220
%(from_u._dimensionality, to_u._dimensionality)
221221
)
222+
if np.dtype(dtype).kind in 'fc':
223+
cf = np.array(cf, dtype=dtype)
222224
new_magnitude = cf*self.magnitude
223225
dtype = np.result_type(dtype, new_magnitude)
224226
return Quantity(new_magnitude, to_u, dtype=dtype)
@@ -272,7 +274,7 @@ def __array_prepare__(self, obj, context=None):
272274
uf, objs, huh = context
273275
if uf.__name__.startswith('is'):
274276
return obj
275-
#print self, obj, res, uf, objs
277+
276278
try:
277279
res._dimensionality = p_dict[uf](*objs)
278280
except KeyError:
@@ -590,7 +592,7 @@ def nanargmax(self,axis=None, out=None):
590592

591593
@with_doc(np.ndarray.ptp)
592594
def ptp(self, axis=None, out=None):
593-
ret = self.magnitude.ptp(axis, None if out is None else out.magnitude)
595+
ret = np.ptp(self.magnitude, axis, None if out is None else out.magnitude)
594596
dim = self.dimensionality
595597
if out is None:
596598
return Quantity(ret, dim, copy=False)

quantities/tests/common.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@ def assertQuantityEqual(self, q1, q2, msg=None, delta=None):
1919
Make sure q1 and q2 are the same quantities to within the given
2020
precision.
2121
"""
22-
delta = 1e-5 if delta is None else delta
22+
if delta is None:
23+
# NumPy 2 introduced float16, so we base tolerance on machine epsilon
24+
delta1 = np.finfo(q1.dtype).eps if isinstance(q1, np.ndarray) and q1.dtype.kind in 'fc' else 1e-15
25+
delta2 = np.finfo(q2.dtype).eps if isinstance(q2, np.ndarray) and q2.dtype.kind in 'fc' else 1e-15
26+
delta = max(delta1, delta2)**0.3
2327
msg = '' if msg is None else ' (%s)' % msg
2428

2529
q1 = Quantity(q1)
@@ -28,6 +32,7 @@ def assertQuantityEqual(self, q1, q2, msg=None, delta=None):
2832
raise self.failureException(
2933
f"Shape mismatch ({q1.shape} vs {q2.shape}){msg}"
3034
)
35+
3136
if not np.all(np.abs(q1.magnitude - q2.magnitude) < delta):
3237
raise self.failureException(
3338
"Magnitudes differ by more than %g (%s vs %s)%s"

quantities/tests/test_arithmetic.py

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -48,32 +48,9 @@ def check(f, *args, **kwargs):
4848
return (new, )
4949

5050

51-
class iter_dtypes:
52-
53-
def __init__(self):
54-
self._i = 1
55-
self._typeDict = np.sctypeDict.copy()
56-
self._typeDict[17] = int
57-
self._typeDict[18] = long
58-
self._typeDict[19] = float
59-
self._typeDict[20] = complex
60-
61-
def __iter__(self):
62-
return self
63-
64-
def __next__(self):
65-
if self._i > 20:
66-
raise StopIteration
67-
68-
i = self._i
69-
self._i += 1
70-
return self._typeDict[i]
71-
72-
def next(self):
73-
return self.__next__()
74-
7551
def get_dtypes():
76-
return list(iter_dtypes())
52+
numeric_dtypes = 'iufc' # https://numpy.org/doc/stable/reference/generated/numpy.dtype.kind.html
53+
return [v for v in np.sctypeDict.values() if np.dtype(v).kind in numeric_dtypes] + [int, long, float, complex]
7754

7855

7956
class iter_types:

quantities/uncertainquantity.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ def __mul__(self, other):
118118
ru = (sru**2+oru**2)**0.5
119119
u = res.view(Quantity) * ru
120120
except AttributeError:
121-
other = np.array(other, copy=False, subok=True)
121+
other = np.asanyarray(other)
122122
u = (self.uncertainty**2*other**2)**0.5
123123

124124
res._uncertainty = u
@@ -140,7 +140,7 @@ def __truediv__(self, other):
140140
ru = (sru**2+oru**2)**0.5
141141
u = res.view(Quantity) * ru
142142
except AttributeError:
143-
other = np.array(other, copy=False, subok=True)
143+
other = np.asanyarray(other)
144144
u = (self.uncertainty**2/other**2)**0.5
145145

146146
res._uncertainty = u

0 commit comments

Comments
 (0)