array-api-strict 2.3__py3-none-any.whl → 2.4__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.
Files changed (35) hide show
  1. array_api_strict/__init__.py +11 -5
  2. array_api_strict/_array_object.py +226 -200
  3. array_api_strict/_constants.py +1 -1
  4. array_api_strict/_creation_functions.py +97 -119
  5. array_api_strict/_data_type_functions.py +73 -64
  6. array_api_strict/_dtypes.py +35 -24
  7. array_api_strict/_elementwise_functions.py +138 -482
  8. array_api_strict/_fft.py +28 -32
  9. array_api_strict/_flags.py +65 -26
  10. array_api_strict/_helpers.py +23 -14
  11. array_api_strict/_indexing_functions.py +3 -8
  12. array_api_strict/_info.py +64 -69
  13. array_api_strict/_linalg.py +57 -53
  14. array_api_strict/_linear_algebra_functions.py +11 -9
  15. array_api_strict/_manipulation_functions.py +30 -30
  16. array_api_strict/_searching_functions.py +22 -33
  17. array_api_strict/_set_functions.py +4 -6
  18. array_api_strict/_sorting_functions.py +6 -6
  19. array_api_strict/_statistical_functions.py +57 -64
  20. array_api_strict/_typing.py +30 -50
  21. array_api_strict/_utility_functions.py +11 -13
  22. array_api_strict/_version.py +2 -2
  23. array_api_strict/py.typed +0 -0
  24. array_api_strict/tests/test_array_object.py +163 -56
  25. array_api_strict/tests/test_creation_functions.py +14 -12
  26. array_api_strict/tests/test_data_type_functions.py +40 -6
  27. array_api_strict/tests/test_elementwise_functions.py +94 -45
  28. array_api_strict/tests/test_searching_functions.py +79 -1
  29. array_api_strict/tests/test_validation.py +1 -3
  30. {array_api_strict-2.3.dist-info → array_api_strict-2.4.dist-info}/METADATA +5 -4
  31. array_api_strict-2.4.dist-info/RECORD +44 -0
  32. {array_api_strict-2.3.dist-info → array_api_strict-2.4.dist-info}/WHEEL +1 -1
  33. array_api_strict-2.3.dist-info/RECORD +0 -43
  34. {array_api_strict-2.3.dist-info → array_api_strict-2.4.dist-info}/LICENSE +0 -0
  35. {array_api_strict-2.3.dist-info → array_api_strict-2.4.dist-info}/top_level.txt +0 -0
@@ -1,3 +1,4 @@
1
+ import sys
1
2
  import operator
2
3
  from builtins import all as all_
3
4
 
@@ -5,7 +6,7 @@ from numpy.testing import assert_raises, suppress_warnings
5
6
  import numpy as np
6
7
  import pytest
7
8
 
8
- from .. import ones, arange, reshape, asarray, result_type, all, equal
9
+ from .. import ones, arange, reshape, asarray, result_type, all, equal, stack
9
10
  from .._array_object import Array, CPU_DEVICE, Device
10
11
  from .._dtypes import (
11
12
  _all_dtypes,
@@ -100,34 +101,71 @@ def test_validate_index():
100
101
  assert_raises(IndexError, lambda: a[:])
101
102
  assert_raises(IndexError, lambda: a[idx])
102
103
 
104
+ class DummyIndex:
105
+ def __init__(self, x):
106
+ self.x = x
107
+ def __index__(self):
108
+ return self.x
103
109
 
104
- def test_indexing_arrays():
110
+
111
+ @pytest.mark.parametrize("device", [None, "CPU_DEVICE", "device1", "device2"])
112
+ @pytest.mark.parametrize(
113
+ "integer_index",
114
+ [
115
+ 0,
116
+ np.int8(0),
117
+ np.uint8(0),
118
+ np.int16(0),
119
+ np.uint16(0),
120
+ np.int32(0),
121
+ np.uint32(0),
122
+ np.int64(0),
123
+ np.uint64(0),
124
+ DummyIndex(0),
125
+ ],
126
+ )
127
+ def test_indexing_ints(integer_index, device):
128
+ # Ensure indexing with different integer types works on all Devices.
129
+ device = None if device is None else Device(device)
130
+
131
+ a = arange(5, device=device)
132
+ assert a[(integer_index,)] == a[integer_index] == a[0]
133
+
134
+
135
+ @pytest.mark.parametrize("device", [None, "CPU_DEVICE", "device1", "device2"])
136
+ def test_indexing_arrays(device):
105
137
  # indexing with 1D integer arrays and mixes of integers and 1D integer are allowed
138
+ device = None if device is None else Device(device)
106
139
 
107
140
  # 1D array
108
- a = arange(5)
109
- idx = asarray([1, 0, 1, 2, -1])
141
+ a = arange(5, device=device)
142
+ idx = asarray([1, 0, 1, 2, -1], device=device)
110
143
  a_idx = a[idx]
111
144
 
112
- a_idx_loop = asarray([a[idx[i]] for i in range(idx.shape[0])])
145
+ a_idx_loop = stack([a[idx[i]] for i in range(idx.shape[0])])
113
146
  assert all(a_idx == a_idx_loop)
147
+ assert a_idx.shape == idx.shape
148
+ assert a.device == idx.device == a_idx.device
114
149
 
115
150
  # setitem with arrays is not allowed
116
151
  with assert_raises(IndexError):
117
152
  a[idx] = 42
118
153
 
119
154
  # mixed array and integer indexing
120
- a = reshape(arange(3*4), (3, 4))
121
- idx = asarray([1, 0, 1, 2, -1])
155
+ a = reshape(arange(3*4, device=device), (3, 4))
156
+ idx = asarray([1, 0, 1, 2, -1], device=device)
122
157
  a_idx = a[idx, 1]
123
-
124
- a_idx_loop = asarray([a[idx[i], 1] for i in range(idx.shape[0])])
158
+ a_idx_loop = stack([a[idx[i], 1] for i in range(idx.shape[0])])
125
159
  assert all(a_idx == a_idx_loop)
160
+ assert a_idx.shape == idx.shape
161
+ assert a.device == idx.device == a_idx.device
126
162
 
127
163
  # index with two arrays
128
164
  a_idx = a[idx, idx]
129
- a_idx_loop = asarray([a[idx[i], idx[i]] for i in range(idx.shape[0])])
165
+ a_idx_loop = stack([a[idx[i], idx[i]] for i in range(idx.shape[0])])
130
166
  assert all(a_idx == a_idx_loop)
167
+ assert a_idx.shape == a_idx.shape
168
+ assert a.device == idx.device == a_idx.device
131
169
 
132
170
  # setitem with arrays is not allowed
133
171
  with assert_raises(IndexError):
@@ -135,7 +173,24 @@ def test_indexing_arrays():
135
173
 
136
174
  # smoke test indexing with ndim > 1 arrays
137
175
  idx = idx[..., None]
138
- a[idx, idx]
176
+ a_idx = a[idx, idx]
177
+ assert a.device == idx.device == a_idx.device
178
+
179
+
180
+ def test_indexing_arrays_different_devices():
181
+ # Ensure indexing via array on different device errors
182
+ device1 = Device("CPU_DEVICE")
183
+ device2 = Device("device1")
184
+
185
+ a = arange(5, device=device1)
186
+ idx1 = asarray([1, 0, 1, 2, -1], device=device2)
187
+ idx2 = asarray([1, 0, 1, 2, -1], device=device1)
188
+
189
+ with pytest.raises(ValueError, match="Array indexing is only allowed when"):
190
+ a[idx1]
191
+
192
+ with pytest.raises(ValueError, match="Array indexing is only allowed when"):
193
+ a[idx1, idx2]
139
194
 
140
195
 
141
196
  def test_promoted_scalar_inherits_device():
@@ -201,30 +256,37 @@ def _check_op_array_scalar(dtypes, a, s, func, func_name, BIG_INT=BIG_INT):
201
256
  func(s)
202
257
  return False
203
258
 
259
+ binary_op_dtypes = {
260
+ "__add__": "numeric",
261
+ "__and__": "integer or boolean",
262
+ "__eq__": "all",
263
+ "__floordiv__": "real numeric",
264
+ "__ge__": "real numeric",
265
+ "__gt__": "real numeric",
266
+ "__le__": "real numeric",
267
+ "__lshift__": "integer",
268
+ "__lt__": "real numeric",
269
+ "__mod__": "real numeric",
270
+ "__mul__": "numeric",
271
+ "__ne__": "all",
272
+ "__or__": "integer or boolean",
273
+ "__pow__": "numeric",
274
+ "__rshift__": "integer",
275
+ "__sub__": "numeric",
276
+ "__truediv__": "floating-point",
277
+ "__xor__": "integer or boolean",
278
+ }
279
+ unary_op_dtypes = {
280
+ "__abs__": "numeric",
281
+ "__invert__": "integer or boolean",
282
+ "__neg__": "numeric",
283
+ "__pos__": "numeric",
284
+ }
204
285
 
205
286
  def test_operators():
206
287
  # For every operator, we test that it works for the required type
207
288
  # combinations and raises TypeError otherwise
208
- binary_op_dtypes = {
209
- "__add__": "numeric",
210
- "__and__": "integer or boolean",
211
- "__eq__": "all",
212
- "__floordiv__": "real numeric",
213
- "__ge__": "real numeric",
214
- "__gt__": "real numeric",
215
- "__le__": "real numeric",
216
- "__lshift__": "integer",
217
- "__lt__": "real numeric",
218
- "__mod__": "real numeric",
219
- "__mul__": "numeric",
220
- "__ne__": "all",
221
- "__or__": "integer or boolean",
222
- "__pow__": "numeric",
223
- "__rshift__": "integer",
224
- "__sub__": "numeric",
225
- "__truediv__": "floating-point",
226
- "__xor__": "integer or boolean",
227
- }
289
+
228
290
  # Recompute each time because of in-place ops
229
291
  def _array_vals():
230
292
  for d in _integer_dtypes:
@@ -283,12 +345,6 @@ def test_operators():
283
345
  else:
284
346
  assert_raises(TypeError, lambda: getattr(x, _op)(y))
285
347
 
286
- unary_op_dtypes = {
287
- "__abs__": "numeric",
288
- "__invert__": "integer or boolean",
289
- "__neg__": "numeric",
290
- "__pos__": "numeric",
291
- }
292
348
  for op, dtypes in unary_op_dtypes.items():
293
349
  for a in _array_vals():
294
350
  if (
@@ -356,6 +412,55 @@ def test_operators():
356
412
  x.__imatmul__(y)
357
413
 
358
414
 
415
+ @pytest.mark.parametrize("op,dtypes", binary_op_dtypes.items())
416
+ def test_binary_operators_numpy_scalars(op, dtypes):
417
+ """
418
+ Test that NumPy scalars (np.generic) are explicitly disallowed.
419
+
420
+ This must notably include np.float64 and np.complex128, which are
421
+ subclasses of float and complex respectively, so they need
422
+ special treatment in order to be rejected.
423
+ """
424
+ match = "Expected Array or Python scalar"
425
+
426
+ if dtypes not in ("numeric", "integer", "real numeric", "floating-point"):
427
+ a = asarray(True)
428
+ func = getattr(a, op)
429
+ with pytest.raises(TypeError, match=match):
430
+ func(np.bool_(True))
431
+
432
+ if dtypes != "floating-point":
433
+ a = asarray(1)
434
+ func = getattr(a, op)
435
+ with pytest.raises(TypeError, match=match):
436
+ func(np.int64(1))
437
+
438
+ if dtypes not in ("integer", "integer or boolean"):
439
+ a = asarray(1.,)
440
+ func = getattr(a, op)
441
+ with pytest.raises(TypeError, match=match):
442
+ func(np.float32(1.))
443
+ with pytest.raises(TypeError, match=match):
444
+ func(np.float64(1.))
445
+
446
+ if dtypes not in ("integer", "integer or boolean", "real numeric"):
447
+ a = asarray(1.,)
448
+ func = getattr(a, op)
449
+ with pytest.raises(TypeError, match=match):
450
+ func(np.complex64(1.))
451
+ with pytest.raises(TypeError, match=match):
452
+ func(np.complex128(1.))
453
+
454
+
455
+ @pytest.mark.parametrize("op,dtypes", binary_op_dtypes.items())
456
+ def test_binary_operators_device_mismatch(op, dtypes):
457
+ dtype = float64 if dtypes == "floating-point" else int64
458
+ a = asarray(1, dtype=dtype, device=CPU_DEVICE)
459
+ b = asarray(1, dtype=dtype, device=Device("device1"))
460
+ with pytest.raises(ValueError, match="different devices"):
461
+ getattr(a, op)(b)
462
+
463
+
359
464
  def test_python_scalar_construtors():
360
465
  b = asarray(False)
361
466
  i = asarray(0)
@@ -422,35 +527,37 @@ def test_array_properties():
422
527
  assert b.mT.shape == (3, 2)
423
528
 
424
529
 
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
+ )
425
534
  def test_array_conversion():
426
535
  # Check that arrays on the CPU device can be converted to NumPy
427
536
  # but arrays on other devices can't. Note this is testing the logic in
428
537
  # __array__, which is only used in asarray when converting lists of
429
538
  # arrays.
430
539
  a = ones((2, 3))
431
- asarray([a])
540
+ np.asarray(a)
432
541
 
433
542
  for device in ("device1", "device2"):
434
543
  a = ones((2, 3), device=array_api_strict.Device(device))
435
- with pytest.raises(RuntimeError, match="Can not convert array"):
436
- asarray([a])
544
+ with pytest.raises((RuntimeError, ValueError)):
545
+ np.asarray(a)
546
+
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
437
552
 
438
- def test__array__():
439
- # __array__ should work for now
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"
555
+ )
556
+ def test_array_conversion_2():
440
557
  a = ones((2, 3))
441
- np.array(a)
442
-
443
- # Test the _allow_array private global flag for disabling it in the
444
- # future.
445
- from .. import _array_object
446
- original_value = _array_object._allow_array
447
- try:
448
- _array_object._allow_array = False
449
- a = ones((2, 3))
450
- with pytest.raises(ValueError, match="Conversion from an array_api_strict array to a NumPy ndarray is not supported"):
451
- np.array(a)
452
- finally:
453
- _array_object._allow_array = original_value
558
+ with pytest.raises(TypeError):
559
+ np.array(a)
560
+
454
561
 
455
562
  def test_allow_newaxis():
456
563
  a = ones(5)
@@ -533,7 +640,7 @@ def test_array_namespace():
533
640
  pytest.raises(ValueError, lambda: a.__array_namespace__(api_version="2026.12"))
534
641
 
535
642
  def test_iter():
536
- pytest.raises(TypeError, lambda: iter(asarray(3)))
643
+ pytest.raises(TypeError, lambda: next(iter(asarray(3))))
537
644
  assert list(ones(3)) == [asarray(1.), asarray(1.), asarray(1.)]
538
645
  assert all_(isinstance(a, Array) for a in iter(ones(3)))
539
646
  assert all_(a.shape == () for a in iter(ones(3)))
@@ -22,7 +22,7 @@ from .._creation_functions import (
22
22
  zeros,
23
23
  zeros_like,
24
24
  )
25
- from .._dtypes import int16, float32, float64
25
+ from .._dtypes import float32, float64
26
26
  from .._array_object import Array, CPU_DEVICE, Device
27
27
  from .._flags import set_array_api_strict_flags
28
28
 
@@ -97,18 +97,20 @@ def test_asarray_copy():
97
97
  a[0] = 0
98
98
  assert all(b[0] == 0)
99
99
 
100
+
100
101
  def test_asarray_list_of_lists():
101
- a = asarray(1, dtype=int16)
102
- b = asarray([1], dtype=int16)
103
- res = asarray([a, a])
104
- assert res.shape == (2,)
105
- assert res.dtype == int16
106
- assert all(res == asarray([1, 1]))
107
-
108
- res = asarray([b, b])
109
- assert res.shape == (2, 1)
110
- assert res.dtype == int16
111
- assert all(res == asarray([[1], [1]]))
102
+ lst = [[1, 2, 3], [4, 5, 6]]
103
+ res = asarray(lst)
104
+ assert res.shape == (2, 3)
105
+
106
+
107
+ def test_asarray_nested_arrays():
108
+ # do not allow arrays in nested sequences
109
+ with pytest.raises(TypeError):
110
+ asarray([[1, 2, 3], asarray([4, 5, 6])])
111
+
112
+ with pytest.raises(TypeError):
113
+ asarray([1, asarray(1)])
112
114
 
113
115
 
114
116
  def test_asarray_device_inference():
@@ -1,15 +1,12 @@
1
1
  import warnings
2
2
 
3
+ import numpy as np
3
4
  import pytest
4
-
5
5
  from numpy.testing import assert_raises
6
- import numpy as np
7
6
 
8
7
  from .._creation_functions import asarray
9
- from .._data_type_functions import astype, can_cast, isdtype, result_type
10
- from .._dtypes import (
11
- bool, int8, int16, uint8, float64, int64
12
- )
8
+ from .._data_type_functions import astype, can_cast, finfo, iinfo, isdtype, result_type
9
+ from .._dtypes import bool, float64, int8, int16, int64, uint8
13
10
  from .._flags import set_array_api_strict_flags
14
11
 
15
12
 
@@ -88,3 +85,40 @@ def test_result_type_py_scalars(api_version):
88
85
 
89
86
  with pytest.raises(TypeError):
90
87
  result_type(int64, True)
88
+
89
+
90
+ def test_finfo_iinfo_dtypelike():
91
+ """np.finfo() and np.iinfo() accept any DTypeLike.
92
+ Array API only accepts Array | DType.
93
+ """
94
+ match = "must be a dtype or array"
95
+ with pytest.raises(TypeError, match=match):
96
+ finfo("float64")
97
+ with pytest.raises(TypeError, match=match):
98
+ finfo(float)
99
+ with pytest.raises(TypeError, match=match):
100
+ iinfo("int8")
101
+ with pytest.raises(TypeError, match=match):
102
+ iinfo(int)
103
+
104
+
105
+ def test_finfo_iinfo_wrap_output():
106
+ """Test that the finfo(...).dtype and iinfo(...).dtype
107
+ are array-api-strict.DType objects; not numpy.dtype.
108
+ """
109
+ # Note: array_api_strict.DType objects are not singletons
110
+ assert finfo(float64).dtype == float64
111
+ assert iinfo(int8).dtype == int8
112
+
113
+
114
+ @pytest.mark.parametrize("func,arg", [(finfo, float64), (iinfo, int8)])
115
+ def test_finfo_iinfo_output_assumptions(func, arg):
116
+ """There should be no expectation for the output of finfo()/iinfo()
117
+ to be comparable, hashable, or writeable.
118
+ """
119
+ obj = func(arg)
120
+ assert obj != func(arg) # Defaut behaviour for custom classes
121
+ with pytest.raises(TypeError):
122
+ hash(obj)
123
+ with pytest.raises(Exception, match="cannot assign"):
124
+ obj.min = 0
@@ -1,24 +1,26 @@
1
1
  from inspect import signature, getmodule
2
2
 
3
- from pytest import raises as assert_raises
3
+ import numpy as np
4
+ import pytest
4
5
  from numpy.testing import suppress_warnings
5
6
 
6
7
 
7
8
  from .. import asarray, _elementwise_functions
9
+ from .._array_object import ALL_DEVICES, CPU_DEVICE, Device
8
10
  from .._elementwise_functions import bitwise_left_shift, bitwise_right_shift
9
11
  from .._dtypes import (
10
12
  _dtype_categories,
11
13
  _boolean_dtypes,
12
14
  _floating_dtypes,
13
15
  _integer_dtypes,
16
+ bool as xp_bool,
17
+ float64,
14
18
  int8,
15
19
  int16,
16
20
  int32,
17
21
  int64,
18
22
  uint64,
19
23
  )
20
- from .._flags import set_array_api_strict_flags
21
-
22
24
  from .test_array_object import _check_op_array_scalar, BIG_INT
23
25
 
24
26
  import array_api_strict
@@ -104,6 +106,13 @@ elementwise_function_input_types = {
104
106
  }
105
107
 
106
108
 
109
+ elementwise_binary_function_names = [
110
+ func_name
111
+ for func_name in elementwise_function_input_types
112
+ if nargs(getattr(_elementwise_functions, func_name)) == 2
113
+ ]
114
+
115
+
107
116
  def test_nargs():
108
117
  # Explicitly check number of arguments for a few functions
109
118
  assert nargs(array_api_strict.logaddexp) == 2
@@ -126,33 +135,81 @@ def test_missing_functions():
126
135
  assert set(mod_funcs) == set(elementwise_function_input_types)
127
136
 
128
137
 
129
- def test_function_device_persists():
130
- # Test that the device of the input and output array are the same
138
+ @pytest.mark.parametrize("device", ALL_DEVICES)
139
+ @pytest.mark.parametrize("func_name,types", elementwise_function_input_types.items())
140
+ def test_elementwise_function_device_persists(func_name, types, device):
141
+ """Test that the device of the input and output array are the same"""
131
142
  def _array_vals(dtypes):
132
- for d in dtypes:
133
- yield asarray(1., dtype=d)
134
-
135
- # Use the latest version of the standard so all functions are included
136
- set_array_api_strict_flags(api_version="2024.12")
137
-
138
- for func_name, types in elementwise_function_input_types.items():
139
- dtypes = _dtype_categories[types]
140
- func = getattr(_elementwise_functions, func_name)
143
+ for dtype in dtypes:
144
+ yield asarray(1., dtype=dtype, device=device)
145
+
146
+ dtypes = _dtype_categories[types]
147
+ func = getattr(_elementwise_functions, func_name)
148
+
149
+ for x in _array_vals(dtypes):
150
+ if nargs(func) == 2:
151
+ # This way we don't have to deal with incompatible
152
+ # types of the two arguments.
153
+ r = func(x, x)
154
+ assert r.device == x.device
155
+
156
+ else:
157
+ # `atanh` needs a slightly different input value from
158
+ # everyone else
159
+ if func_name == "atanh":
160
+ x -= 0.1
161
+ r = func(x)
162
+ assert r.device == x.device
163
+
164
+
165
+ @pytest.mark.parametrize("func_name", elementwise_binary_function_names)
166
+ def test_elementwise_function_device_mismatch(func_name):
167
+ func = getattr(_elementwise_functions, func_name)
168
+ dtypes = elementwise_function_input_types[func_name]
169
+ if dtypes in ("floating-point", "real floating-point"):
170
+ dtype = float64
171
+ elif dtypes == "boolean":
172
+ dtype = xp_bool
173
+ else:
174
+ dtype = int64
175
+
176
+ a = asarray(1, dtype=dtype, device=CPU_DEVICE)
177
+ b = asarray(1, dtype=dtype, device=Device("device1"))
178
+ _ = func(a, a)
179
+ with pytest.raises(ValueError, match="different devices"):
180
+ func(a, b)
181
+
182
+
183
+ @pytest.mark.parametrize("func_name", elementwise_function_input_types)
184
+ def test_elementwise_function_numpy_scalars(func_name):
185
+ """
186
+ Test that NumPy scalars (np.generic) are explicitly disallowed.
187
+
188
+ This must notably include np.float64 and np.complex128, which are
189
+ subclasses of float and complex respectively, so they need
190
+ special treatment in order to be rejected.
191
+ """
192
+ func = getattr(_elementwise_functions, func_name)
193
+ dtypes = elementwise_function_input_types[func_name]
194
+ xp_dtypes = _dtype_categories[dtypes]
195
+ np_dtypes = [dtype._np_dtype for dtype in xp_dtypes]
196
+
197
+ value = 0.5 if func_name == "atanh" else 1
198
+ for xp_dtype in xp_dtypes:
199
+ for np_dtype in np_dtypes:
200
+ a = asarray(value, dtype=xp_dtype, device=CPU_DEVICE)
201
+ b = np.asarray(value, dtype=np_dtype)[()]
141
202
 
142
- for x in _array_vals(dtypes):
143
203
  if nargs(func) == 2:
144
- # This way we don't have to deal with incompatible
145
- # types of the two arguments.
146
- r = func(x, x)
147
- assert r.device == x.device
148
-
204
+ _ = func(a, a)
205
+ with pytest.raises(TypeError, match="neither Array nor Python scalars"):
206
+ func(a, b)
207
+ with pytest.raises(TypeError, match="neither Array nor Python scalars"):
208
+ func(b, a)
149
209
  else:
150
- # `atanh` needs a slightly different input value from
151
- # everyone else
152
- if func_name == "atanh":
153
- x -= 0.1
154
- r = func(x)
155
- assert r.device == x.device
210
+ _ = func(a)
211
+ with pytest.raises(TypeError, match="allowed"):
212
+ func(b)
156
213
 
157
214
 
158
215
  def test_function_types():
@@ -168,9 +225,6 @@ def test_function_types():
168
225
  for d in _floating_dtypes:
169
226
  yield asarray(1.0, dtype=d)
170
227
 
171
- # Use the latest version of the standard so all functions are included
172
- set_array_api_strict_flags(api_version="2024.12")
173
-
174
228
  for x in _array_vals():
175
229
  for func_name, types in elementwise_function_input_types.items():
176
230
  dtypes = _dtype_categories[types]
@@ -187,23 +241,23 @@ def test_function_types():
187
241
  or x.dtype in _floating_dtypes and y.dtype not in _floating_dtypes
188
242
  or y.dtype in _floating_dtypes and x.dtype not in _floating_dtypes
189
243
  ):
190
- assert_raises(TypeError, func, x, y)
244
+ with pytest.raises(TypeError):
245
+ func(x, y)
191
246
  if x.dtype not in dtypes or y.dtype not in dtypes:
192
- assert_raises(TypeError, func, x, y)
247
+ with pytest.raises(TypeError):
248
+ func(x, y)
193
249
  else:
194
250
  if x.dtype not in dtypes:
195
- assert_raises(TypeError, func, x)
251
+ with pytest.raises(TypeError):
252
+ func(x)
196
253
 
197
254
 
198
255
  def test_bitwise_shift_error():
199
256
  # bitwise shift functions should raise when the second argument is negative
200
- assert_raises(
201
- ValueError, lambda: bitwise_left_shift(asarray([1, 1]), asarray([1, -1]))
202
- )
203
- assert_raises(
204
- ValueError, lambda: bitwise_right_shift(asarray([1, 1]), asarray([1, -1]))
205
- )
206
-
257
+ with pytest.raises(ValueError):
258
+ bitwise_left_shift(asarray([1, 1]), asarray([1, -1]))
259
+ with pytest.raises(ValueError):
260
+ bitwise_right_shift(asarray([1, 1]), asarray([1, -1]))
207
261
 
208
262
 
209
263
  def test_scalars():
@@ -212,9 +266,6 @@ def test_scalars():
212
266
  # Also check that binary functions accept (array, scalar) and (scalar, array)
213
267
  # arguments, and reject (scalar, scalar) arguments.
214
268
 
215
- # Use the latest version of the standard so that scalars are actually allowed
216
- set_array_api_strict_flags(api_version="2024.12")
217
-
218
269
  def _array_vals():
219
270
  for d in _integer_dtypes:
220
271
  yield asarray(1, dtype=d)
@@ -256,7 +307,5 @@ def test_scalars():
256
307
  assert func(s, a) == func(conv_scalar, a)
257
308
  assert func(a, s) == func(a, conv_scalar)
258
309
 
259
- with assert_raises(TypeError):
310
+ with pytest.raises(TypeError):
260
311
  func(s, s)
261
-
262
-