array-api-strict 2.4__py3-none-any.whl → 2.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -73,6 +73,7 @@ __all__ += [
73
73
  from ._data_type_functions import (
74
74
  astype,
75
75
  broadcast_arrays,
76
+ broadcast_shapes,
76
77
  broadcast_to,
77
78
  can_cast,
78
79
  finfo,
@@ -84,6 +85,7 @@ from ._data_type_functions import (
84
85
  __all__ += [
85
86
  "astype",
86
87
  "broadcast_arrays",
88
+ "broadcast_shapes",
87
89
  "broadcast_to",
88
90
  "can_cast",
89
91
  "finfo",
@@ -299,9 +301,9 @@ from ._searching_functions import argmax, argmin, nonzero, count_nonzero, search
299
301
 
300
302
  __all__ += ["argmax", "argmin", "nonzero", "count_nonzero", "searchsorted", "where"]
301
303
 
302
- from ._set_functions import unique_all, unique_counts, unique_inverse, unique_values
304
+ from ._set_functions import unique_all, unique_counts, unique_inverse, unique_values, isin
303
305
 
304
- __all__ += ["unique_all", "unique_counts", "unique_inverse", "unique_values"]
306
+ __all__ += ["unique_all", "unique_counts", "unique_inverse", "unique_values", "isin"]
305
307
 
306
308
  from ._sorting_functions import argsort, sort
307
309
 
@@ -16,10 +16,11 @@ of ndarray.
16
16
  from __future__ import annotations
17
17
 
18
18
  import operator
19
+ import sys
19
20
  from collections.abc import Iterator
20
21
  from enum import IntEnum
21
22
  from types import EllipsisType, ModuleType
22
- from typing import Any, Final, Literal, SupportsIndex
23
+ from typing import Any, Final, Literal, SupportsIndex, Callable
23
24
 
24
25
  import numpy as np
25
26
  import numpy.typing as npt
@@ -67,8 +68,6 @@ class Device:
67
68
  CPU_DEVICE = Device()
68
69
  ALL_DEVICES = (CPU_DEVICE, Device("device1"), Device("device2"))
69
70
 
70
- _default = object()
71
-
72
71
 
73
72
  class Array:
74
73
  """
@@ -126,6 +125,9 @@ class Array:
126
125
  raise TypeError(
127
126
  "The array_api_strict Array object should not be instantiated directly. Use an array creation function, such as asarray(), instead."
128
127
  )
128
+
129
+ def __reduce__(self) -> tuple[Callable, tuple[npt.NDArray[Any], Device]]:
130
+ return (self._new, (self._array, self._device))
129
131
 
130
132
  # These functions are not required by the spec, but are implemented for
131
133
  # the sake of usability.
@@ -149,29 +151,40 @@ class Array:
149
151
 
150
152
  __str__ = __repr__
151
153
 
152
- # `__array__` was implemented historically for compatibility, and removing it has
153
- # caused issues for some libraries (see
154
- # https://github.com/data-apis/array-api-strict/issues/67).
155
-
156
- # Instead of `__array__` we now implement the buffer protocol.
157
- # Note that it makes array-apis-strict requiring python>=3.12
158
154
  def __buffer__(self, flags):
159
155
  if self._device != CPU_DEVICE:
160
- raise RuntimeError(f"Can not convert array on the '{self._device}' device to a Numpy array.")
156
+ raise RuntimeError(
157
+ # NumPy swallows this exception and falls back to __array__.
158
+ f"Can't extract host buffer from array on the '{self._device}' device."
159
+ )
161
160
  return self._array.__buffer__(flags)
162
161
 
163
- # We do not define __release_buffer__, per the discussion at
164
- # https://github.com/data-apis/array-api-strict/pull/115#pullrequestreview-2917178729
165
-
166
- def __array__(self, *args, **kwds):
167
- # a stub for python < 3.12; otherwise numpy silently produces object arrays
168
- import sys
169
- minor, major = sys.version_info.minor, sys.version_info.major
170
- if major < 3 or minor < 12:
162
+ # `__array__` is not part of the Array API. Ideally we want to support
163
+ # `xp.asarray(Array)` exclusively through the __buffer__ protocol; however this is
164
+ # only possible on Python >=3.12. Additionally, when __buffer__ raises (e.g. because
165
+ # the array is not on the CPU device, NumPy will try to fall back on __array__ but,
166
+ # if that doesn't exist, create a scalar numpy array of objects which contains the
167
+ # array_api_strict.Array. So we can't get rid of __array__ entirely.
168
+ def __array__(
169
+ self, dtype: None | np.dtype[Any] = None, copy: None | bool = None
170
+ ) -> npt.NDArray[Any]:
171
+ if self._device != CPU_DEVICE:
172
+ # We arrive here from np.asarray() on Python >=3.12 when __buffer__ raises.
173
+ raise RuntimeError(
174
+ f"Can't convert array on the '{self._device}' device to a "
175
+ "NumPy array."
176
+ )
177
+ if sys.version_info >= (3, 12):
171
178
  raise TypeError(
172
- "Interoperation with NumPy requires python >= 3.12. Please upgrade."
179
+ "The __array__ method is not supported by the Array API. "
180
+ "Please use the __buffer__ interface instead."
173
181
  )
174
182
 
183
+ # copy keyword is new in 2.0
184
+ if np.__version__[0] < '2':
185
+ return np.asarray(self._array, dtype=dtype)
186
+ return np.asarray(self._array, dtype=dtype, copy=copy)
187
+
175
188
  # These are various helper functions to make the array behavior match the
176
189
  # spec in places where it either deviates from or is more strict than
177
190
  # NumPy behavior
@@ -942,6 +955,15 @@ class Array:
942
955
  self._validate_index(key, op="setitem")
943
956
  # Indexing self._array with array_api_strict arrays can be erroneous
944
957
  np_key = key._array if isinstance(key, Array) else key
958
+
959
+ # sanitize the value
960
+ other = value
961
+ if isinstance(value, (bool, int, float, complex)):
962
+ other = self._promote_scalar(value)
963
+ dt = _result_type(self.dtype, other.dtype)
964
+ if dt != self.dtype:
965
+ raise TypeError(f"mismatched dtypes: {self.dtype = } and {other.dtype = }")
966
+
945
967
  self._array.__setitem__(np_key, asarray(value)._array)
946
968
 
947
969
  def __sub__(self, other: Array | complex, /) -> Array:
@@ -1104,6 +1126,7 @@ class Array:
1104
1126
  """
1105
1127
  Performs the operation __imod__.
1106
1128
  """
1129
+ self._check_type_device(other)
1107
1130
  other = self._check_allowed_dtypes(other, "real numeric", "__imod__")
1108
1131
  if other is NotImplemented:
1109
1132
  return other
@@ -1126,6 +1149,7 @@ class Array:
1126
1149
  """
1127
1150
  Performs the operation __imul__.
1128
1151
  """
1152
+ self._check_type_device(other)
1129
1153
  other = self._check_allowed_dtypes(other, "numeric", "__imul__")
1130
1154
  if other is NotImplemented:
1131
1155
  return other
@@ -1148,6 +1172,7 @@ class Array:
1148
1172
  """
1149
1173
  Performs the operation __ior__.
1150
1174
  """
1175
+ self._check_type_device(other)
1151
1176
  other = self._check_allowed_dtypes(other, "integer or boolean", "__ior__")
1152
1177
  if other is NotImplemented:
1153
1178
  return other
@@ -1170,6 +1195,7 @@ class Array:
1170
1195
  """
1171
1196
  Performs the operation __ipow__.
1172
1197
  """
1198
+ self._check_type_device(other)
1173
1199
  other = self._check_allowed_dtypes(other, "numeric", "__ipow__")
1174
1200
  if other is NotImplemented:
1175
1201
  return other
@@ -1182,6 +1208,7 @@ class Array:
1182
1208
  """
1183
1209
  from ._elementwise_functions import pow # type: ignore[attr-defined]
1184
1210
 
1211
+ self._check_type_device(other)
1185
1212
  other = self._check_allowed_dtypes(other, "numeric", "__rpow__")
1186
1213
  if other is NotImplemented:
1187
1214
  return other
@@ -1193,6 +1220,7 @@ class Array:
1193
1220
  """
1194
1221
  Performs the operation __irshift__.
1195
1222
  """
1223
+ self._check_type_device(other)
1196
1224
  other = self._check_allowed_dtypes(other, "integer", "__irshift__")
1197
1225
  if other is NotImplemented:
1198
1226
  return other
@@ -1215,6 +1243,7 @@ class Array:
1215
1243
  """
1216
1244
  Performs the operation __isub__.
1217
1245
  """
1246
+ self._check_type_device(other)
1218
1247
  other = self._check_allowed_dtypes(other, "numeric", "__isub__")
1219
1248
  if other is NotImplemented:
1220
1249
  return other
@@ -1237,6 +1266,7 @@ class Array:
1237
1266
  """
1238
1267
  Performs the operation __itruediv__.
1239
1268
  """
1269
+ self._check_type_device(other)
1240
1270
  other = self._check_allowed_dtypes(other, "floating-point", "__itruediv__")
1241
1271
  if other is NotImplemented:
1242
1272
  return other
@@ -1259,6 +1289,7 @@ class Array:
1259
1289
  """
1260
1290
  Performs the operation __ixor__.
1261
1291
  """
1292
+ self._check_type_device(other)
1262
1293
  other = self._check_allowed_dtypes(other, "integer or boolean", "__ixor__")
1263
1294
  if other is NotImplemented:
1264
1295
  return other
@@ -240,8 +240,9 @@ def full(
240
240
  _check_valid_dtype(dtype)
241
241
  _check_device(device)
242
242
 
243
- if isinstance(fill_value, Array) and fill_value.ndim == 0:
244
- fill_value = fill_value._array
243
+ if not isinstance(fill_value, bool | int | float | complex):
244
+ msg = f"Expected Python scalar fill_value, got type {type(fill_value)}"
245
+ raise TypeError(msg)
245
246
  res = np.full(shape, fill_value, dtype=_np_dtype(dtype))
246
247
  if DType(res.dtype) not in _all_dtypes:
247
248
  # This will happen if the fill value is not something that NumPy
@@ -270,6 +271,10 @@ def full_like(
270
271
  if device is None:
271
272
  device = x.device
272
273
 
274
+ if not isinstance(fill_value, bool | int | float | complex):
275
+ msg = f"Expected Python scalar fill_value, got type {type(fill_value)}"
276
+ raise TypeError(msg)
277
+
273
278
  res = np.full_like(x._array, fill_value, dtype=_np_dtype(dtype))
274
279
  if DType(res.dtype) not in _all_dtypes:
275
280
  # This will happen if the fill value is not something that NumPy
@@ -304,7 +309,7 @@ def linspace(
304
309
  )
305
310
 
306
311
 
307
- def meshgrid(*arrays: Array, indexing: Literal["xy", "ij"] = "xy") -> list[Array]:
312
+ def meshgrid(*arrays: Array, indexing: Literal["xy", "ij"] = "xy") -> tuple[Array, ...]:
308
313
  """
309
314
  Array API compatible wrapper for :py:func:`np.meshgrid <numpy.meshgrid>`.
310
315
 
@@ -327,10 +332,12 @@ def meshgrid(*arrays: Array, indexing: Literal["xy", "ij"] = "xy") -> list[Array
327
332
  else:
328
333
  device = None
329
334
 
330
- return [
335
+ typ = list if get_array_api_strict_flags()['api_version'] < '2025.12' else tuple
336
+
337
+ return typ(
331
338
  Array._new(array, device=device)
332
339
  for array in np.meshgrid(*[a._array for a in arrays], indexing=indexing)
333
- ]
340
+ )
334
341
 
335
342
 
336
343
  def ones(
@@ -16,7 +16,7 @@ from ._dtypes import (
16
16
  _signed_integer_dtypes,
17
17
  _unsigned_integer_dtypes,
18
18
  )
19
- from ._flags import get_array_api_strict_flags
19
+ from ._flags import get_array_api_strict_flags, requires_api_version
20
20
 
21
21
 
22
22
  # Note: astype is a function, not an array method as in NumPy.
@@ -49,7 +49,7 @@ def astype(
49
49
  return Array._new(x._array.astype(dtype=dtype._np_dtype, copy=copy), device=device)
50
50
 
51
51
 
52
- def broadcast_arrays(*arrays: Array) -> list[Array]:
52
+ def broadcast_arrays(*arrays: Array) -> tuple[Array, ...]:
53
53
  """
54
54
  Array API compatible wrapper for :py:func:`np.broadcast_arrays <numpy.broadcast_arrays>`.
55
55
 
@@ -57,9 +57,21 @@ def broadcast_arrays(*arrays: Array) -> list[Array]:
57
57
  """
58
58
  from ._array_object import Array
59
59
 
60
- return [
60
+ typ = list if get_array_api_strict_flags()['api_version'] < '2025.12' else tuple
61
+
62
+ return typ(
61
63
  Array._new(array, device=arrays[0].device) for array in np.broadcast_arrays(*[a._array for a in arrays])
62
- ]
64
+ )
65
+
66
+
67
+ @requires_api_version("2025.12")
68
+ def broadcast_shapes(*shapes: tuple[int, ...]) -> tuple[int, ...]:
69
+ """
70
+ Array API compatible wrapper for :py:func:`np.broadcast_shapes <numpy.broadcast_shapes>`.
71
+
72
+ See its docstring for more information.
73
+ """
74
+ return np.broadcast_shapes(*shapes)
63
75
 
64
76
 
65
77
  def broadcast_to(x: Array, /, shape: tuple[int, ...]) -> Array:
@@ -257,7 +257,7 @@ def clip(
257
257
  raise TypeError("Only real numeric dtypes are allowed in clip")
258
258
 
259
259
  if min is max is None:
260
- return x
260
+ return Array._new(x._array.copy(), device=x.device)
261
261
 
262
262
  for argname, arg in ("min", min), ("max", max):
263
263
  if isinstance(arg, Array):
@@ -278,8 +278,8 @@ def clip(
278
278
  isinstance(arg, Array) and arg.dtype in _real_floating_dtypes)):
279
279
  raise TypeError(f"{argname} must be integral when x is integral")
280
280
  if (x.dtype in _real_floating_dtypes
281
- and (isinstance(arg, int) or
282
- isinstance(arg, Array) and arg.dtype in _integer_dtypes)):
281
+ and (isinstance(arg, Array) and arg.dtype in _integer_dtypes)
282
+ ):
283
283
  raise TypeError(f"{arg} must be floating-point when x is floating-point")
284
284
 
285
285
  # Normalize to make the below logic simpler
@@ -352,5 +352,7 @@ def sign(x: Array, /) -> Array:
352
352
  raise TypeError("Only numeric dtypes are allowed in sign")
353
353
  # Special treatment to work around non-compliant NumPy 1.x behaviour
354
354
  if x.dtype in _complex_floating_dtypes:
355
- return x/abs(x)
355
+ _x = x._array
356
+ _result = _x / np.abs(np.where(_x != 0, _x, np.asarray(1.0, dtype=_x.dtype)))
357
+ return Array._new(_result, device=x.device)
356
358
  return Array._new(np.sign(x._array), device=x.device)
@@ -30,11 +30,12 @@ supported_versions = (
30
30
  "2022.12",
31
31
  "2023.12",
32
32
  "2024.12",
33
+ "2025.12",
33
34
  )
34
35
 
35
- draft_version = "2025.12"
36
+ draft_version = "2026.12"
36
37
 
37
- API_VERSION = default_version = "2024.12"
38
+ API_VERSION = default_version = "2025.12"
38
39
 
39
40
  BOOLEAN_INDEXING = True
40
41
 
array_api_strict/_info.py CHANGED
@@ -130,5 +130,8 @@ class __array_namespace_info__:
130
130
  raise ValueError(f"unsupported kind: {kind!r}")
131
131
 
132
132
  @requires_api_version('2023.12')
133
- def devices(self) -> list[Device]:
134
- return list(ALL_DEVICES)
133
+ def devices(self) -> tuple[Device]:
134
+ if get_array_api_strict_flags()['api_version'] < '2025.12':
135
+ return list(ALL_DEVICES)
136
+ else:
137
+ return tuple(ALL_DEVICES)
@@ -9,7 +9,7 @@ from ._array_object import Array
9
9
  from ._data_type_functions import finfo
10
10
  from ._dtypes import DType, _floating_dtypes, _numeric_dtypes, complex64, complex128
11
11
  from ._elementwise_functions import conj
12
- from ._flags import get_array_api_strict_flags, requires_extension
12
+ from ._flags import get_array_api_strict_flags, requires_extension, requires_api_version
13
13
  from ._manipulation_functions import reshape
14
14
  from ._statistical_functions import _np_dtype_sumprod
15
15
 
@@ -23,6 +23,10 @@ class EighResult(NamedTuple):
23
23
  eigenvalues: Array
24
24
  eigenvectors: Array
25
25
 
26
+ class EigResult(NamedTuple):
27
+ eigenvalues: Array
28
+ eigenvectors: Array
29
+
26
30
  class QRResult(NamedTuple):
27
31
  Q: Array
28
32
  R: Array
@@ -144,6 +148,63 @@ def eigvalsh(x: Array, /) -> Array:
144
148
 
145
149
  return Array._new(np.linalg.eigvalsh(x._array), device=x.device)
146
150
 
151
+ @requires_extension('linalg')
152
+ @requires_api_version('2025.12')
153
+ def eigvals(x: Array, /) -> Array:
154
+ """
155
+ Array API compatible wrapper for :py:func:`np.linalg.eigvals <numpy.linalg.eigvals>`.
156
+
157
+ See its docstring for more information.
158
+ """
159
+ # Note: the restriction to floating-point dtypes only is different from
160
+ # np.linalg.eigvals.
161
+ if x.dtype not in _floating_dtypes:
162
+ raise TypeError('Only floating-point dtypes are allowed in eigvals')
163
+
164
+ res = np.linalg.eigvals(x._array)
165
+
166
+ # numpy return reals for real inputs
167
+ res_dtype = res.dtype
168
+ if res.dtype == np.float32:
169
+ res_dtype = np.complex64
170
+ elif res.dtype == np.float64:
171
+ res_dtype = np.complex128
172
+
173
+ if res_dtype != res.dtype:
174
+ res = res.astype(res_dtype)
175
+
176
+ return Array._new(res, device=x.device)
177
+
178
+
179
+ @requires_extension('linalg')
180
+ @requires_api_version('2025.12')
181
+ def eig(x: Array, /) -> EigResult:
182
+ """
183
+ Array API compatible wrapper for :py:func:`np.linalg.eig <numpy.linalg.eig>`.
184
+
185
+ See its docstring for more information.
186
+ """
187
+ # Note: the restriction to floating-point dtypes only is different from
188
+ # np.linalg.eig.
189
+ if x.dtype not in _floating_dtypes:
190
+ raise TypeError('Only floating-point dtypes are allowed in eig')
191
+
192
+ w, vr = np.linalg.eig(x._array)
193
+
194
+ # numpy return reals for real inputs
195
+ res_dtype = w.dtype
196
+ if w.dtype == np.float32:
197
+ res_dtype = np.complex64
198
+ elif w.dtype == np.float64:
199
+ res_dtype = np.complex128
200
+
201
+ if res_dtype != w.dtype:
202
+ w = w.astype(res_dtype)
203
+ vr = vr.astype(res_dtype)
204
+
205
+ return EigResult(Array._new(w, device=x.device), Array._new(vr, device=x.device))
206
+
207
+
147
208
  @requires_extension('linalg')
148
209
  def inv(x: Array, /) -> Array:
149
210
  """
@@ -30,7 +30,7 @@ def concat(
30
30
  )
31
31
 
32
32
 
33
- def expand_dims(x: Array, /, *, axis: int) -> Array:
33
+ def expand_dims(x: Array, /, axis: int) -> Array:
34
34
  """
35
35
  Array API compatible wrapper for :py:func:`np.expand_dims <numpy.expand_dims>`.
36
36
 
@@ -5,7 +5,7 @@ import numpy as np
5
5
  from ._array_object import Array
6
6
  from ._dtypes import _real_numeric_dtypes, _result_type
7
7
  from ._dtypes import bool as _bool
8
- from ._flags import requires_api_version, requires_data_dependent_shapes
8
+ from ._flags import requires_api_version, requires_data_dependent_shapes, get_array_api_strict_flags
9
9
  from ._helpers import _maybe_normalize_py_scalars
10
10
 
11
11
 
@@ -64,7 +64,7 @@ def count_nonzero(
64
64
  @requires_api_version('2023.12')
65
65
  def searchsorted(
66
66
  x1: Array,
67
- x2: Array,
67
+ x2: Array | int | float,
68
68
  /,
69
69
  *,
70
70
  side: Literal["left", "right"] = "left",
@@ -75,6 +75,12 @@ def searchsorted(
75
75
 
76
76
  See its docstring for more information.
77
77
  """
78
+ flags = get_array_api_strict_flags()
79
+ if flags["api_version"] >= "2025.12":
80
+ # scalar x2 support is new in 2025.12
81
+ if isinstance(x2, bool | int | float | complex):
82
+ x2 = x1._promote_scalar(x2)
83
+
78
84
  if x1.dtype not in _real_numeric_dtypes or x2.dtype not in _real_numeric_dtypes:
79
85
  raise TypeError("Only real numeric dtypes are allowed in searchsorted")
80
86
 
@@ -3,7 +3,9 @@ from typing import NamedTuple
3
3
  import numpy as np
4
4
 
5
5
  from ._array_object import Array
6
- from ._flags import requires_data_dependent_shapes
6
+ from ._flags import requires_data_dependent_shapes, requires_api_version
7
+ from ._helpers import _maybe_normalize_py_scalars
8
+ from ._dtypes import _result_type
7
9
 
8
10
  # Note: np.unique() is split into four functions in the array API:
9
11
  # unique_all, unique_counts, unique_inverse, and unique_values (this is done
@@ -109,3 +111,23 @@ def unique_values(x: Array, /) -> Array:
109
111
  equal_nan=False,
110
112
  )
111
113
  return Array._new(res, device=x.device)
114
+
115
+
116
+ @requires_api_version('2025.12')
117
+ def isin(x1: Array | int, x2: Array | int, /, *, invert: bool = False) -> Array:
118
+ """
119
+ Array API compatible wrapper for :py:func:`np.isin <numpy.isin>`.
120
+
121
+ See its docstring for more information.
122
+ """
123
+ # implementation here is from _elementwise_functions.py::_binary_ufunc_proto
124
+ x1, x2 = _maybe_normalize_py_scalars(x1, x2, "integer", "isin")
125
+
126
+ if x1.device != x2.device:
127
+ raise ValueError(
128
+ f"Arrays from two different devices ({x1.device} and {x2.device}) can not be combined."
129
+ )
130
+ # Call result type here just to raise on disallowed type combinations
131
+ _result_type(x1.dtype, x2.dtype)
132
+ # x1, x2 = Array._normalize_two_args(x1, x2) # no need to change 0D -> 1D here
133
+ return Array._new(np.isin(x1._array, x2._array), device=x1.device)
@@ -1,7 +1,14 @@
1
1
  # file generated by setuptools-scm
2
2
  # don't change, don't track in version control
3
3
 
4
- __all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
4
+ __all__ = [
5
+ "__version__",
6
+ "__version_tuple__",
7
+ "version",
8
+ "version_tuple",
9
+ "__commit_id__",
10
+ "commit_id",
11
+ ]
5
12
 
6
13
  TYPE_CHECKING = False
7
14
  if TYPE_CHECKING:
@@ -9,13 +16,19 @@ if TYPE_CHECKING:
9
16
  from typing import Union
10
17
 
11
18
  VERSION_TUPLE = Tuple[Union[int, str], ...]
19
+ COMMIT_ID = Union[str, None]
12
20
  else:
13
21
  VERSION_TUPLE = object
22
+ COMMIT_ID = object
14
23
 
15
24
  version: str
16
25
  __version__: str
17
26
  __version_tuple__: VERSION_TUPLE
18
27
  version_tuple: VERSION_TUPLE
28
+ commit_id: COMMIT_ID
29
+ __commit_id__: COMMIT_ID
19
30
 
20
- __version__ = version = '2.4'
21
- __version_tuple__ = version_tuple = (2, 4)
31
+ __version__ = version = '2.5'
32
+ __version_tuple__ = version_tuple = (2, 5)
33
+
34
+ __commit_id__ = commit_id = None
@@ -1,8 +1,10 @@
1
1
  import sys
2
+ import warnings
2
3
  import operator
4
+ import pickle
3
5
  from builtins import all as all_
4
6
 
5
- from numpy.testing import assert_raises, suppress_warnings
7
+ from numpy.testing import assert_raises
6
8
  import numpy as np
7
9
  import pytest
8
10
 
@@ -18,12 +20,14 @@ from .._dtypes import (
18
20
  _integer_or_boolean_dtypes,
19
21
  _real_numeric_dtypes,
20
22
  _numeric_dtypes,
23
+ uint8,
21
24
  int8,
22
25
  int16,
23
26
  int32,
24
27
  int64,
25
28
  uint64,
26
29
  float64,
30
+ complex128,
27
31
  bool as bool_,
28
32
  )
29
33
  from .._flags import set_array_api_strict_flags
@@ -193,6 +197,29 @@ def test_indexing_arrays_different_devices():
193
197
  a[idx1, idx2]
194
198
 
195
199
 
200
+ def test_setitem_invalid_promotions():
201
+ # Check that violating these two raises:
202
+ # Setting array values must not affect the data type of self, and
203
+ # Behavior must otherwise follow Type Promotion Rules.
204
+ a = asarray([1, 2, 3])
205
+ with pytest.raises(TypeError):
206
+ a[0] = 3.5
207
+
208
+ with pytest.raises(TypeError):
209
+ a[0] = asarray(3.5)
210
+
211
+ a = asarray([1, 2, 3], dtype=uint8)
212
+ with pytest.raises(TypeError):
213
+ a[0] = asarray(42, dtype=uint64)
214
+
215
+ a = asarray([1, 2, 3], dtype=float64)
216
+ with pytest.raises(TypeError):
217
+ a[0] = 3.5j
218
+
219
+ with pytest.raises(TypeError):
220
+ a[0] = asarray(3.5j, dtype=complex128)
221
+
222
+
196
223
  def test_promoted_scalar_inherits_device():
197
224
  device1 = Device("device1")
198
225
  x = asarray([1., 2, 3], device=device1)
@@ -244,10 +271,12 @@ def _check_op_array_scalar(dtypes, a, s, func, func_name, BIG_INT=BIG_INT):
244
271
 
245
272
  else:
246
273
  # Only test for no error
247
- with suppress_warnings() as sup:
274
+ with warnings.catch_warnings():
248
275
  # ignore warnings from pow(BIG_INT)
249
- sup.filter(RuntimeWarning,
250
- "invalid value encountered in power")
276
+ warnings.filterwarnings(
277
+ "ignore", category=RuntimeWarning,
278
+ message="invalid value encountered in power"
279
+ )
251
280
  func(s)
252
281
  return True
253
282
 
@@ -344,6 +373,13 @@ def test_operators():
344
373
  getattr(x, _op)(y)
345
374
  else:
346
375
  assert_raises(TypeError, lambda: getattr(x, _op)(y))
376
+ # finally, test that array op ndarray raises
377
+ # XXX: as long as there is __array__ or __buffer__, __rop__s
378
+ # still return ndarrays
379
+ if not _op.startswith("__r"):
380
+ with assert_raises(TypeError):
381
+ getattr(x, _op)(y._array)
382
+
347
383
 
348
384
  for op, dtypes in unary_op_dtypes.items():
349
385
  for a in _array_vals():
@@ -527,36 +563,54 @@ def test_array_properties():
527
563
  assert b.mT.shape == (3, 2)
528
564
 
529
565
 
530
- @pytest.mark.xfail(sys.version_info.major*100 + sys.version_info.minor < 312,
531
- reason="array conversion relies on buffer protocol, and "
532
- "requires python >= 3.12"
533
- )
534
566
  def test_array_conversion():
535
567
  # Check that arrays on the CPU device can be converted to NumPy
536
568
  # but arrays on other devices can't. Note this is testing the logic in
537
- # __array__, which is only used in asarray when converting lists of
538
- # arrays.
569
+ # __array__ on Python 3.10~3.11 and in __buffer__ on Python >=3.12.
539
570
  a = ones((2, 3))
540
- np.asarray(a)
571
+ na = np.asarray(a)
572
+ assert na.shape == (2, 3)
573
+ assert na.dtype == np.float64
574
+ na[0, 0] = 10
575
+ assert a[0, 0] == 10 # return view when possible
576
+
577
+ a = arange(5, dtype=uint8)
578
+ na = np.asarray(a)
579
+ assert na.dtype == np.uint8
541
580
 
542
581
  for device in ("device1", "device2"):
543
582
  a = ones((2, 3), device=array_api_strict.Device(device))
544
- with pytest.raises((RuntimeError, ValueError)):
583
+ with pytest.raises(RuntimeError, match=device):
545
584
  np.asarray(a)
546
585
 
547
- # __buffer__ should work for now for conversion to numpy
548
- a = ones((2, 3))
549
- na = np.array(a)
550
- assert na.shape == (2, 3)
551
- assert na.dtype == np.float64
552
586
 
553
- @pytest.mark.skipif(not sys.version_info.major*100 + sys.version_info.minor < 312,
554
- reason="conversion to numpy errors out unless python >= 3.12"
587
+ @pytest.mark.skipif(np.__version__ < "2", reason="np.asarray has no copy kwarg")
588
+ def test_array_conversion_copy():
589
+ a = arange(5)
590
+ na = np.asarray(a, copy=False)
591
+ na[0] = 10
592
+ assert a[0] == 10
593
+
594
+ a = arange(5)
595
+ na = np.asarray(a, copy=True)
596
+ na[0] = 10
597
+ assert a[0] == 0
598
+
599
+ a = arange(5)
600
+ with pytest.raises(ValueError):
601
+ np.asarray(a, dtype=np.uint8, copy=False)
602
+
603
+
604
+ @pytest.mark.skipif(
605
+ sys.version_info < (3, 12), reason="Python <3.12 has no __buffer__ interface"
555
606
  )
556
- def test_array_conversion_2():
607
+ def test_no_array_interface():
608
+ """When the __buffer__ interface is available, the __array__ interface is not."""
557
609
  a = ones((2, 3))
558
- with pytest.raises(TypeError):
559
- np.array(a)
610
+ with pytest.raises(TypeError, match="not supported"):
611
+ # Because NumPy prefers __buffer__ when available, we can't trigger this
612
+ # exception from np.asarray().
613
+ a.__array__()
560
614
 
561
615
 
562
616
  def test_allow_newaxis():
@@ -616,10 +670,10 @@ def test_array_keys_use_private_array():
616
670
  def test_array_namespace():
617
671
  a = ones((3, 3))
618
672
  assert a.__array_namespace__() == array_api_strict
619
- assert array_api_strict.__array_api_version__ == "2024.12"
673
+ assert array_api_strict.__array_api_version__ == "2025.12"
620
674
 
621
675
  assert a.__array_namespace__(api_version=None) is array_api_strict
622
- assert array_api_strict.__array_api_version__ == "2024.12"
676
+ assert array_api_strict.__array_api_version__ == "2025.12"
623
677
 
624
678
  assert a.__array_namespace__(api_version="2022.12") is array_api_strict
625
679
  assert array_api_strict.__array_api_version__ == "2022.12"
@@ -632,12 +686,12 @@ def test_array_namespace():
632
686
  assert array_api_strict.__array_api_version__ == "2021.12"
633
687
 
634
688
  with pytest.warns(UserWarning):
635
- assert a.__array_namespace__(api_version="2025.12") is array_api_strict
636
- assert array_api_strict.__array_api_version__ == "2025.12"
689
+ assert a.__array_namespace__(api_version="2026.12") is array_api_strict
690
+ assert array_api_strict.__array_api_version__ == "2026.12"
637
691
 
638
692
 
639
693
  pytest.raises(ValueError, lambda: a.__array_namespace__(api_version="2021.11"))
640
- pytest.raises(ValueError, lambda: a.__array_namespace__(api_version="2026.12"))
694
+ pytest.raises(ValueError, lambda: a.__array_namespace__(api_version="2027.12"))
641
695
 
642
696
  def test_iter():
643
697
  pytest.raises(TypeError, lambda: next(iter(asarray(3))))
@@ -694,3 +748,15 @@ def test_dlpack_2023_12(api_version):
694
748
  a.__dlpack__(copy=False)
695
749
  a.__dlpack__(copy=True)
696
750
  a.__dlpack__(copy=None)
751
+
752
+ def test_pickle():
753
+ """Check that arrays are pickleable (despite raising on `__new__`)"""
754
+ a = ones(2)
755
+ min_supported_protocol = 2
756
+ for protocol in range(min_supported_protocol, pickle.HIGHEST_PROTOCOL + 1):
757
+ bytes = pickle.dumps(a, protocol=protocol)
758
+ a_from_pickle = pickle.loads(bytes)
759
+ assert a_from_pickle.device == a.device
760
+ assert a_from_pickle.dtype == a.dtype
761
+ assert a_from_pickle.shape == a.shape
762
+ assert all(a_from_pickle == a)
@@ -161,6 +161,7 @@ def test_full_errors():
161
161
  assert_raises(ValueError, lambda: full((1,), 0, device="gpu"))
162
162
  assert_raises(ValueError, lambda: full((1,), 0, dtype=int))
163
163
  assert_raises(ValueError, lambda: full((1,), 0, dtype="i"))
164
+ assert_raises(TypeError, lambda: full((1,), asarray(0)))
164
165
 
165
166
 
166
167
  def test_full_like_errors():
@@ -169,6 +170,7 @@ def test_full_like_errors():
169
170
  assert_raises(ValueError, lambda: full_like(asarray(1), 0, device="gpu"))
170
171
  assert_raises(ValueError, lambda: full_like(asarray(1), 0, dtype=int))
171
172
  assert_raises(ValueError, lambda: full_like(asarray(1), 0, dtype="i"))
173
+ assert_raises(TypeError, lambda: full(asarray(1), asarray(0)))
172
174
 
173
175
 
174
176
  def test_linspace_errors():
@@ -1,8 +1,8 @@
1
+ import warnings
1
2
  from inspect import signature, getmodule
2
3
 
3
4
  import numpy as np
4
5
  import pytest
5
- from numpy.testing import suppress_warnings
6
6
 
7
7
 
8
8
  from .. import asarray, _elementwise_functions
@@ -300,12 +300,24 @@ def test_scalars():
300
300
  if allowed:
301
301
  conv_scalar = a._promote_scalar(s)
302
302
 
303
- with suppress_warnings() as sup:
303
+ with warnings.catch_warnings():
304
304
  # ignore warnings from pow(BIG_INT)
305
- sup.filter(RuntimeWarning,
306
- "invalid value encountered in power")
305
+ warnings.filterwarnings(
306
+ "ignore", category=RuntimeWarning,
307
+ message="invalid value encountered in power"
308
+ )
309
+
307
310
  assert func(s, a) == func(conv_scalar, a)
308
311
  assert func(a, s) == func(a, conv_scalar)
309
312
 
310
313
  with pytest.raises(TypeError):
311
314
  func(s, s)
315
+
316
+
317
+ def test_clip_none():
318
+ # regression test: clip(x) is a copy of x, not a view
319
+ x = asarray([1, 2, 3])
320
+ y = array_api_strict.clip(x)
321
+
322
+ y[1] = 42
323
+ assert x[1] == 2
@@ -19,7 +19,7 @@ import pytest
19
19
  def test_flag_defaults():
20
20
  flags = get_array_api_strict_flags()
21
21
  assert flags == {
22
- 'api_version': '2024.12',
22
+ 'api_version': '2025.12',
23
23
  'boolean_indexing': True,
24
24
  'data_dependent_shapes': True,
25
25
  'enabled_extensions': ('linalg', 'fft'),
@@ -36,7 +36,7 @@ def test_reset_flags():
36
36
  reset_array_api_strict_flags()
37
37
  flags = get_array_api_strict_flags()
38
38
  assert flags == {
39
- 'api_version': '2024.12',
39
+ 'api_version': '2025.12',
40
40
  'boolean_indexing': True,
41
41
  'data_dependent_shapes': True,
42
42
  'enabled_extensions': ('linalg', 'fft'),
@@ -47,7 +47,7 @@ def test_setting_flags():
47
47
  set_array_api_strict_flags(data_dependent_shapes=False)
48
48
  flags = get_array_api_strict_flags()
49
49
  assert flags == {
50
- 'api_version': '2024.12',
50
+ 'api_version': '2025.12',
51
51
  'boolean_indexing': True,
52
52
  'data_dependent_shapes': False,
53
53
  'enabled_extensions': ('linalg', 'fft'),
@@ -55,7 +55,7 @@ def test_setting_flags():
55
55
  set_array_api_strict_flags(enabled_extensions=('fft',))
56
56
  flags = get_array_api_strict_flags()
57
57
  assert flags == {
58
- 'api_version': '2024.12',
58
+ 'api_version': '2025.12',
59
59
  'boolean_indexing': True,
60
60
  'data_dependent_shapes': False,
61
61
  'enabled_extensions': ('fft',),
@@ -109,15 +109,15 @@ def test_flags_api_version_2024_12():
109
109
 
110
110
 
111
111
  def test_flags_api_version_2025_12():
112
- # Make sure setting the version to 2025.12 issues a warning.
112
+ # Make sure setting the version to 2026.12 issues a warning.
113
113
  with pytest.warns(UserWarning) as record:
114
- set_array_api_strict_flags(api_version='2025.12')
114
+ set_array_api_strict_flags(api_version='2026.12')
115
115
  assert len(record) == 1
116
- assert '2025.12' in str(record[0].message)
116
+ assert '2026.12' in str(record[0].message)
117
117
  assert 'draft' in str(record[0].message)
118
118
  flags = get_array_api_strict_flags()
119
119
  assert flags == {
120
- 'api_version': '2025.12',
120
+ 'api_version': '2026.12',
121
121
  'boolean_indexing': True,
122
122
  'data_dependent_shapes': True,
123
123
  'enabled_extensions': ('linalg', 'fft'),
@@ -136,7 +136,7 @@ def test_setting_flags_invalid():
136
136
 
137
137
  def test_api_version():
138
138
  # Test defaults
139
- assert xp.__array_api_version__ == '2024.12'
139
+ assert xp.__array_api_version__ == '2025.12'
140
140
 
141
141
  # Test setting the version
142
142
  set_array_api_strict_flags(api_version='2023.12')
@@ -444,9 +444,9 @@ def test_environment_variables():
444
444
  # ARRAY_API_STRICT_API_VERSION
445
445
  ('''\
446
446
  import array_api_strict as xp
447
- assert xp.__array_api_version__ == '2024.12'
447
+ assert xp.__array_api_version__ == '2025.12'
448
448
 
449
- assert xp.get_array_api_strict_flags()['api_version'] == '2024.12'
449
+ assert xp.get_array_api_strict_flags()['api_version'] == '2025.12'
450
450
 
451
451
  ''', {}),
452
452
  *[
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: array_api_strict
3
- Version: 2.4
3
+ Version: 2.5
4
4
  Summary: A strict, minimal implementation of the Python array API standard.
5
5
  Author: Consortium for Python Data API Standards
6
6
  License: Copyright (c) 2021-2024, NumPy Developers, Consortium for Python Data API Standards
@@ -48,6 +48,9 @@ Requires-Python: >=3.10
48
48
  Description-Content-Type: text/markdown
49
49
  License-File: LICENSE
50
50
  Requires-Dist: numpy
51
+ Provides-Extra: test
52
+ Requires-Dist: pytest ; extra == 'test'
53
+ Requires-Dist: hypothesis ; extra == 'test'
51
54
 
52
55
  # array-api-strict
53
56
 
@@ -1,34 +1,34 @@
1
- array_api_strict/__init__.py,sha256=ej0VGyz6OCxIDCyBsLRzj1w9B4Z6-BAHUOaaZRZ7Xn4,7113
2
- array_api_strict/_array_object.py,sha256=y3OPuGTl7roe5UYjEgFQuGwGzvvvUqgxeRe_erNo3CE,53017
1
+ array_api_strict/__init__.py,sha256=kexXRJ7WHgMTeMi80H6XiObC3ePtUEr5gf92dnwyPGE,7173
2
+ array_api_strict/_array_object.py,sha256=m5197OW2aW778dGDMjQI4Zxaw5BfIqXWQ6sJK_DpgaA,54393
3
3
  array_api_strict/_constants.py,sha256=ilkAGjIceZxT4zPywIoWbl3Xv8k19UOI4SSF6EPegpg,93
4
- array_api_strict/_creation_functions.py,sha256=6_KZsI64t3pXTxLhjCye82T7aPPUcmCxC6ZcIliqF3E,12316
5
- array_api_strict/_data_type_functions.py,sha256=gr7pZiMDMIKpZJjmiXzLbsGfk8SA0ltomcI05Wf9Ykk,8351
4
+ array_api_strict/_creation_functions.py,sha256=TXookrcG1zeUBMvgFdbiwXxZJ1aMvViSef24tqVo53s,12658
5
+ array_api_strict/_data_type_functions.py,sha256=5OPnsIj4QafrSlnizUZcO4DHO5u0ap9OyDNovV4qrns,8765
6
6
  array_api_strict/_dtypes.py,sha256=PNSd4LpGdnRiEGoB2uqxi93d0dmtiyFp_awUzUcdHJE,6597
7
- array_api_strict/_elementwise_functions.py,sha256=YLk_sNTTJmF7jXCjOlBvtOvuj486sDK7x8JJv9zfHM4,13050
7
+ array_api_strict/_elementwise_functions.py,sha256=D3jOalyR5-kDSzeGTZLKnGPVwjKBuPihkwn23YSxcUc,13198
8
8
  array_api_strict/_fft.py,sha256=DVw7KK4Xvyf3_0rJuWdskggGRCSxS4OrguYNVBf9fH0,10189
9
- array_api_strict/_flags.py,sha256=JJGDGRq06p-D0GOBAzv58SBUrzmOuBqcNOKxmEvrVrU,14743
9
+ array_api_strict/_flags.py,sha256=JaaGahMa-yQjz9fq2E_cFQvhh5B5rVJKms9pMcwdKAg,14758
10
10
  array_api_strict/_helpers.py,sha256=St8M41s5pdhdPdn1-BcdZCrNtRID4X9z5F28fBD3GNg,1915
11
11
  array_api_strict/_indexing_functions.py,sha256=BHPtoyRUIoEMe28MkwUrHRSz5X71i8w_WkTuWQljrpI,1398
12
- array_api_strict/_info.py,sha256=r9HC12AoBb7mg2NcPamWRPs7qR3uL75sQDBUPm7MAjM,4407
13
- array_api_strict/_linalg.py,sha256=N-ynKeoR4lvI3aNhEfXNzig6IeyJ9e7MfDsqpb-3eUM,19706
12
+ array_api_strict/_info.py,sha256=nGLPkobKqDuLlLD4yOxG4y3JVO98o9UNEImXu6YeKH8,4532
13
+ array_api_strict/_linalg.py,sha256=HQjpkVPB0R59mOQBR4cqlZTUKOQTEjGEXbkwk3KNa2Y,21495
14
14
  array_api_strict/_linear_algebra_functions.py,sha256=j8fSBharI31ugZHsUvm74Nv3SHxRrxqtmouK3AOH038,3800
15
- array_api_strict/_manipulation_functions.py,sha256=QhtVv5bGr3fFRlcjLuKZJlyA7r6PdYhmgi_JII3RVVE,6938
16
- array_api_strict/_searching_functions.py,sha256=gO-JRdAbaiZutwiN9pEQ1UAeH_OFw1fBdR2t7_GEuY8,3994
17
- array_api_strict/_set_functions.py,sha256=E3roHcUKzWVGIIxahGt6vc83PzCOva_rbT6Nm9hJQl4,3259
15
+ array_api_strict/_manipulation_functions.py,sha256=KR0O7bMulglaX0DoqEWpiNK3V25D12mFdsqeq-vm8mg,6935
16
+ array_api_strict/_searching_functions.py,sha256=X7pT_kuGBpJltpo4MvVYiZdnKr7jgnH1DNtHiHTKdgw,4263
17
+ array_api_strict/_set_functions.py,sha256=yTKA2OqueeKwk8tp_XcpcsWliL02kgzT3NBzot5zuQ8,4196
18
18
  array_api_strict/_sorting_functions.py,sha256=kw_ns3NajcA8ekpHikNhZxvVePXa3gjdZ7oTwFnBOmk,2074
19
19
  array_api_strict/_statistical_functions.py,sha256=XR9PoZmxJWTsAbzYj05ytDn2D2YDf2YTzWNApdmJBIM,5642
20
20
  array_api_strict/_typing.py,sha256=FVM2m6ZTZYDnznCo0SlMRpcXxGR49y6k4ejNEiuGUtc,1486
21
21
  array_api_strict/_utility_functions.py,sha256=L7FJM-RT90gqkAqvMEfQ6FkzurTziHByROk_5R8a5fY,1938
22
- array_api_strict/_version.py,sha256=y6CMfyyHwwbY96E29GddO9odxAQSle0U0iPOGFS5v2k,506
22
+ array_api_strict/_version.py,sha256=hJiFMfUPM_IAKDdGwMOVrwsdi46DfhTA5ZGiPklON8o,699
23
23
  array_api_strict/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
24
  array_api_strict/tests/__init__.py,sha256=t_2GZ3lKcsu4ec4GMKPUDYaeMUJyDquBlQAcPgj7kFE,282
25
25
  array_api_strict/tests/conftest.py,sha256=-wIDryl2MdRLdSonU1G1xWssNq2TFKiWuHquNasXYA8,468
26
- array_api_strict/tests/test_array_object.py,sha256=gBfAsp_1luPIhftdSEwshRwZmkCbyDYdnQ-istodTx0,27114
27
- array_api_strict/tests/test_creation_functions.py,sha256=JGXO_-cwxTrQGF9LkirGp6zmpq0IiOzffVtKvz1mJgw,8510
26
+ array_api_strict/tests/test_array_object.py,sha256=PZj2Ekw6sY1pbNBrjs2Ll3COkGRVXNsROxirpHfXHJ4,29186
27
+ array_api_strict/tests/test_creation_functions.py,sha256=KeBxgG65ZnKBwclNFZBjyoSwov3j-E3f9iMnXfUsmA8,8638
28
28
  array_api_strict/tests/test_data_type_functions.py,sha256=6V7YeJavgsBmKtR1gvY1GTTlKzGyzPAHki1WtKFeVdU,4098
29
29
  array_api_strict/tests/test_device_support.py,sha256=zpfhHxeRREoXfp0qZTlilm2ZceBc71uCKea1GMVe-ZU,855
30
- array_api_strict/tests/test_elementwise_functions.py,sha256=R8QFP3k57T-xC3J0s56Cwtw_KsRJxJgNDf2N1cTPokI,11151
31
- array_api_strict/tests/test_flags.py,sha256=kcBbFB4aq3XY_9HM1j3wKmq8MVNfU4YxwK21mARM0iw,18982
30
+ array_api_strict/tests/test_elementwise_functions.py,sha256=ZZOfPaCNIug026zv9IdhV2164jZZkRSwmteAnefFBGw,11396
31
+ array_api_strict/tests/test_flags.py,sha256=g7Tajftvmc2ih0a6U57FxcpmleEiDoMgCvzUt2S7MF4,18982
32
32
  array_api_strict/tests/test_indexing_functions.py,sha256=C23FnuowVDC1OBuDH06pvsd61qM2dTpTwzw6UgC4BoY,1281
33
33
  array_api_strict/tests/test_linalg.py,sha256=CJ4JnCkWyysMUAih3PI-ZZeOH-X39H0p-RKBoEwk6Jw,5675
34
34
  array_api_strict/tests/test_manipulation_functions.py,sha256=Yc92IvA3FaTZueqAUOFMkx3MH4PXCHDof7ckrJxudQs,1078
@@ -37,8 +37,8 @@ array_api_strict/tests/test_set_functions.py,sha256=ikzab1j3SXxGf0OqwHrOAM13HwQe
37
37
  array_api_strict/tests/test_sorting_functions.py,sha256=1xvQBKts5KTKYc-puMITX9iR_KTbzzVB8fY-SObad_Y,899
38
38
  array_api_strict/tests/test_statistical_functions.py,sha256=0ihnw4W9vOqU6RMBOUw29Fg-xumXpfz0h05v0E0RsMQ,1814
39
39
  array_api_strict/tests/test_validation.py,sha256=VDci4SgcAhxzSFVnFYBvJWXEsWRxHARnq9TwTfH02xg,635
40
- array_api_strict-2.4.dist-info/LICENSE,sha256=djDm4UfHAJmycwFUNyUmrTdRkrFF9Ac8uqIlbxH7j5Y,1585
41
- array_api_strict-2.4.dist-info/METADATA,sha256=wNNJkgnrMq9hYSpcL2rTf5lH6lg25hmhrG_RrLc3QVM,3508
42
- array_api_strict-2.4.dist-info/WHEEL,sha256=5Mi1sN9lKoFv_gxcPtisEVrJZihrm_beibeg5R6xb4I,91
43
- array_api_strict-2.4.dist-info/top_level.txt,sha256=M4cE8VLgRHp_d9TPkbk7_I4JriELFdEJz-NKJJqAkAE,17
44
- array_api_strict-2.4.dist-info/RECORD,,
40
+ array_api_strict-2.5.dist-info/LICENSE,sha256=djDm4UfHAJmycwFUNyUmrTdRkrFF9Ac8uqIlbxH7j5Y,1585
41
+ array_api_strict-2.5.dist-info/METADATA,sha256=0sP5kLahxH406PSNEXzGLED-PAWJEWZ9QV1EUg6asr4,3613
42
+ array_api_strict-2.5.dist-info/WHEEL,sha256=5Mi1sN9lKoFv_gxcPtisEVrJZihrm_beibeg5R6xb4I,91
43
+ array_api_strict-2.5.dist-info/top_level.txt,sha256=M4cE8VLgRHp_d9TPkbk7_I4JriELFdEJz-NKJJqAkAE,17
44
+ array_api_strict-2.5.dist-info/RECORD,,