Repository: yt-project/unyt
Pull request #492 (2024-03-12 08:16:36)

BUG: fix compatibility with numpy 2.0 copy semantics
In numpy 2.0, passing `copy=False` to `np.array` raises an error if copying cannot be avoided.
xref https://github.com/astropy/astropy/pull/16142


Patch:
diff --git a/unyt/array.py b/unyt/array.py
index 2161faf..bce1cf7 100644
--- a/unyt/array.py
+++ b/unyt/array.py
@@ -10,6 +10,7 @@ import re
 import sys
 import warnings
 from functools import lru_cache
+from importlib.metadata import version
 from numbers import Number as numeric_type
 
 import numpy as np
@@ -26,7 +27,6 @@ from numpy import (
     bitwise_and,
     bitwise_or,
     bitwise_xor,
-    cbrt,
     ceil,
     clip,
     conj,
@@ -102,6 +102,7 @@ from numpy import (
     true_divide,
     trunc,
 )
+from packaging.version import Version
 from sympy import Rational
 
 from unyt._on_demand_imports import _astropy, _dask, _pint
@@ -146,6 +147,8 @@ __doctest_requires__ = {
     ("unyt_array.from_astropy", "unyt_array.to_astropy"): ["astropy"],
 }
 
+_COPY_IF_NEEDED = None if Version(version("numpy")) >= Version("2.0.0dev0") else False
+
 # This is partially adapted from the following SO thread
 # https://stackoverflow.com/questions/41668588/regex-to-match-scientific-notation
 _NUMB_PATTERN = (
@@ -173,11 +176,6 @@ def _sqrt_unit(unit):
     return 1, unit**0.5
 
 
-@lru_cache(maxsize=128, typed=False)
-def _cbrt_unit(unit):
-    return 1, unit ** (1.0 / 3.0)
-
-
 @lru_cache(maxsize=128, typed=False)
 def _multiply_units(unit1, unit2):
     try:
@@ -345,7 +343,6 @@ unary_operators = (
     expm1,
     log1p,
     sqrt,
-    cbrt,
     square,
     reciprocal,
     sin,
@@ -511,7 +508,6 @@ class unyt_array(np.ndarray):
         expm1: _return_without_unit,
         log1p: _return_without_unit,
         sqrt: _sqrt_unit,
-        cbrt: _cbrt_unit,
         square: _square_unit,
         reciprocal: _reciprocal_unit,
         sin: _return_without_unit,
@@ -1985,7 +1981,7 @@ class unyt_array(np.ndarray):
                     "added to unyt_array." % (str(ufunc), len(inputs))
                 )
         if unit is None:
-            out_arr = np.array(out_arr, copy=False)
+            out_arr = np.array(out_arr, copy=_COPY_IF_NEEDED)
         elif ufunc in (modf, divmod_):
             out_arr = tuple(ret_class(o, unit) for o in out_arr)
         elif out_arr.shape == ():


Test patch:
diff --git a/unyt/tests/test_unyt_array.py b/unyt/tests/test_unyt_array.py
index 52b881b..9828dd3 100644
--- a/unyt/tests/test_unyt_array.py
+++ b/unyt/tests/test_unyt_array.py
@@ -973,9 +973,7 @@ def unary_ufunc_comparison(ufunc, a):
         assert_array_equal(ret, out)
         assert_array_equal(ret.to_ndarray(), ufunc(a_array))
         assert ret.units == out.units
-    elif ufunc in yield_np_ufuncs(
-        ["ones_like", "square", "sqrt", "cbrt", "reciprocal"]
-    ):
+    elif ufunc in yield_np_ufuncs(["ones_like", "square", "sqrt", "reciprocal"]):
         if ufunc is np.ones_like:
             ret = ufunc(a)
         else:
@@ -991,9 +989,6 @@ def unary_ufunc_comparison(ufunc, a):
         elif ufunc is np.sqrt:
             assert out.units == a.units**0.5
             assert ret.units == a.units**0.5
-        elif ufunc is np.cbrt:
-            assert out.units == a.units ** (1.0 / 3.0)
-            assert ret.units == a.units ** (1.0 / 3.0)
         elif ufunc is np.reciprocal:
             assert out.units == a.units**-1
             assert ret.units == a.units**-1
@@ -1061,7 +1056,6 @@ def unary_ufunc_comparison(ufunc, a):
             "ones_like",
             "square",
             "sqrt",
-            "cbrt",
             "reciprocal",
             "invert",
             "isnat",