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
@@ -16,50 +16,51 @@ of ndarray.
16
16
  from __future__ import annotations
17
17
 
18
18
  import operator
19
+ from collections.abc import Iterator
19
20
  from enum import IntEnum
21
+ from types import EllipsisType, ModuleType
22
+ from typing import Any, Final, Literal, SupportsIndex
20
23
 
21
- from ._creation_functions import asarray
24
+ import numpy as np
25
+ import numpy.typing as npt
26
+
27
+ from ._creation_functions import Undef, _undef, asarray
22
28
  from ._dtypes import (
23
- _DType,
29
+ DType,
24
30
  _all_dtypes,
25
31
  _boolean_dtypes,
32
+ _complex_floating_dtypes,
33
+ _dtype_categories,
34
+ _floating_dtypes,
26
35
  _integer_dtypes,
27
36
  _integer_or_boolean_dtypes,
28
- _floating_dtypes,
29
- _real_floating_dtypes,
30
- _complex_floating_dtypes,
31
37
  _numeric_dtypes,
32
- _result_type,
33
- _dtype_categories,
38
+ _real_floating_dtypes,
34
39
  _real_to_complex_map,
40
+ _result_type,
35
41
  )
36
42
  from ._flags import get_array_api_strict_flags, set_array_api_strict_flags
43
+ from ._typing import PyCapsule
37
44
 
38
- from typing import TYPE_CHECKING, SupportsIndex
39
- import types
40
-
41
- if TYPE_CHECKING:
42
- from typing import Optional, Tuple, Union, Any
43
- from ._typing import PyCapsule, Dtype
44
- import numpy.typing as npt
45
-
46
- import numpy as np
47
45
 
48
46
  class Device:
49
- def __init__(self, device="CPU_DEVICE"):
47
+ _device: Final[str]
48
+ __slots__ = ("_device", "__weakref__")
49
+
50
+ def __init__(self, device: str = "CPU_DEVICE"):
50
51
  if device not in ("CPU_DEVICE", "device1", "device2"):
51
52
  raise ValueError(f"The device '{device}' is not a valid choice.")
52
53
  self._device = device
53
54
 
54
- def __repr__(self):
55
+ def __repr__(self) -> str:
55
56
  return f"array_api_strict.Device('{self._device}')"
56
57
 
57
- def __eq__(self, other):
58
+ def __eq__(self, other: object) -> bool:
58
59
  if not isinstance(other, Device):
59
60
  return False
60
61
  return self._device == other._device
61
62
 
62
- def __hash__(self):
63
+ def __hash__(self) -> int:
63
64
  return hash(("Device", self._device))
64
65
 
65
66
 
@@ -68,9 +69,6 @@ ALL_DEVICES = (CPU_DEVICE, Device("device1"), Device("device2"))
68
69
 
69
70
  _default = object()
70
71
 
71
- # See https://github.com/data-apis/array-api-strict/issues/67 and the comment
72
- # on __array__ below.
73
- _allow_array = True
74
72
 
75
73
  class Array:
76
74
  """
@@ -87,12 +85,16 @@ class Array:
87
85
  functions, such as asarray().
88
86
 
89
87
  """
88
+
90
89
  _array: npt.NDArray[Any]
90
+ _dtype: DType
91
+ _device: Device
92
+ __slots__ = ("_array", "_dtype", "_device", "__weakref__")
91
93
 
92
94
  # Use a custom constructor instead of __init__, as manually initializing
93
95
  # this class is not supported API.
94
96
  @classmethod
95
- def _new(cls, x, /, device):
97
+ def _new(cls, x: npt.NDArray[Any] | np.generic, /, device: Device | None) -> Array:
96
98
  """
97
99
  This is a private method for initializing the array API Array
98
100
  object.
@@ -107,7 +109,7 @@ class Array:
107
109
  if isinstance(x, np.generic):
108
110
  # Convert the array scalar to a 0-D array
109
111
  x = np.asarray(x)
110
- _dtype = _DType(x.dtype)
112
+ _dtype = DType(x.dtype)
111
113
  if _dtype not in _all_dtypes:
112
114
  raise TypeError(
113
115
  f"The array_api_strict namespace does not support the dtype '{x.dtype}'"
@@ -120,7 +122,7 @@ class Array:
120
122
  return obj
121
123
 
122
124
  # Prevent Array() from working
123
- def __new__(cls, *args, **kwargs):
125
+ def __new__(cls, *args: object, **kwargs: object) -> Array:
124
126
  raise TypeError(
125
127
  "The array_api_strict Array object should not be instantiated directly. Use an array creation function, such as asarray(), instead."
126
128
  )
@@ -128,7 +130,7 @@ class Array:
128
130
  # These functions are not required by the spec, but are implemented for
129
131
  # the sake of usability.
130
132
 
131
- def __repr__(self: Array, /) -> str:
133
+ def __repr__(self) -> str:
132
134
  """
133
135
  Performs the operation __repr__.
134
136
  """
@@ -147,44 +149,36 @@ class Array:
147
149
 
148
150
  __str__ = __repr__
149
151
 
150
- # In the future, _allow_array will be set to False, which will disallow
151
- # __array__. This means calling `np.func()` on an array_api_strict array
152
- # will give an error. If we don't explicitly disallow it, NumPy defaults
153
- # to creating an object dtype array, which would lead to confusing error
154
- # messages at best and surprising bugs at worst. The reason for doing this
155
- # is that __array__ is not actually supported by the standard, so it can
156
- # lead to code assuming np.asarray(other_array) would always work in the
157
- # standard.
158
- #
159
- # This was implemented historically for compatibility, and removing it has
152
+ # `__array__` was implemented historically for compatibility, and removing it has
160
153
  # caused issues for some libraries (see
161
154
  # https://github.com/data-apis/array-api-strict/issues/67).
162
- def __array__(self, dtype: None | np.dtype[Any] = None, copy: None | bool = None) -> npt.NDArray[Any]:
163
- # We have to allow this to be internally enabled as there's no other
164
- # easy way to parse a list of Array objects in asarray().
165
- if _allow_array:
166
- if self._device != CPU_DEVICE:
167
- raise RuntimeError(f"Can not convert array on the '{self._device}' device to a Numpy array.")
168
- # copy keyword is new in 2.0.0; for older versions don't use it
169
- # retry without that keyword.
170
- if np.__version__[0] < '2':
171
- return np.asarray(self._array, dtype=dtype)
172
- elif np.__version__.startswith('2.0.0-dev0'):
173
- # Handle dev version for which we can't know based on version
174
- # number whether or not the copy keyword is supported.
175
- try:
176
- return np.asarray(self._array, dtype=dtype, copy=copy)
177
- except TypeError:
178
- return np.asarray(self._array, dtype=dtype)
179
- else:
180
- return np.asarray(self._array, dtype=dtype, copy=copy)
181
- raise ValueError("Conversion from an array_api_strict array to a NumPy ndarray is not supported")
155
+
156
+ # Instead of `__array__` we now implement the buffer protocol.
157
+ # Note that it makes array-apis-strict requiring python>=3.12
158
+ def __buffer__(self, flags):
159
+ if self._device != CPU_DEVICE:
160
+ raise RuntimeError(f"Can not convert array on the '{self._device}' device to a Numpy array.")
161
+ return self._array.__buffer__(flags)
162
+
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:
171
+ raise TypeError(
172
+ "Interoperation with NumPy requires python >= 3.12. Please upgrade."
173
+ )
182
174
 
183
175
  # These are various helper functions to make the array behavior match the
184
176
  # spec in places where it either deviates from or is more strict than
185
177
  # NumPy behavior
186
178
 
187
- def _check_allowed_dtypes(self, other: bool | int | float | Array, dtype_category: str, op: str) -> Array:
179
+ def _check_allowed_dtypes(
180
+ self, other: Array | complex, dtype_category: str, op: str
181
+ ) -> Array:
188
182
  """
189
183
  Helper function for operators to only allow specific input dtypes
190
184
 
@@ -197,7 +191,7 @@ class Array:
197
191
 
198
192
  if self.dtype not in _dtype_categories[dtype_category]:
199
193
  raise TypeError(f"Only {dtype_category} dtypes are allowed in {op}")
200
- if isinstance(other, (int, complex, float, bool)):
194
+ if isinstance(other, (bool, int, float, complex)):
201
195
  other = self._promote_scalar(other)
202
196
  elif isinstance(other, Array):
203
197
  if other.dtype not in _dtype_categories[dtype_category]:
@@ -225,16 +219,19 @@ class Array:
225
219
 
226
220
  return other
227
221
 
228
- def _check_device(self, other):
229
- """Check that other is on a device compatible with the current array"""
230
- if isinstance(other, (int, complex, float, bool)):
231
- return
232
- elif isinstance(other, Array):
222
+ def _check_type_device(self, other: Array | complex) -> None:
223
+ """Check that other is either a Python scalar or an array on a device
224
+ compatible with the current array.
225
+ """
226
+ if isinstance(other, Array):
233
227
  if self.device != other.device:
234
228
  raise ValueError(f"Arrays from two different devices ({self.device} and {other.device}) can not be combined.")
229
+ # Disallow subclasses of Python scalars, such as np.float64 and np.complex128
230
+ elif type(other) not in (bool, int, float, complex):
231
+ raise TypeError(f"Expected Array or Python scalar; got {type(other)}")
235
232
 
236
233
  # Helper function to match the type promotion rules in the spec
237
- def _promote_scalar(self, scalar):
234
+ def _promote_scalar(self, scalar: complex) -> Array:
238
235
  """
239
236
  Returns a promoted version of a Python scalar appropriate for use with
240
237
  operations on self.
@@ -291,7 +288,7 @@ class Array:
291
288
  return Array._new(np.array(scalar, dtype=target_dtype._np_dtype), device=self.device)
292
289
 
293
290
  @staticmethod
294
- def _normalize_two_args(x1, x2) -> Tuple[Array, Array]:
291
+ def _normalize_two_args(x1: Array, x2: Array) -> tuple[Array, Array]:
295
292
  """
296
293
  Normalize inputs to two arg functions to fix type promotion rules
297
294
 
@@ -327,7 +324,17 @@ class Array:
327
324
 
328
325
  # Note: A large fraction of allowed indices are disallowed here (see the
329
326
  # docstring below)
330
- def _validate_index(self, key, op="getitem"):
327
+ def _validate_index(
328
+ self,
329
+ key: (
330
+ int
331
+ | slice
332
+ | EllipsisType
333
+ | Array
334
+ | tuple[int | slice | EllipsisType | Array | None, ...]
335
+ ),
336
+ op: Literal["getitem", "setitem"] = "getitem",
337
+ ) -> None:
331
338
  """
332
339
  Validate an index according to the array API.
333
340
 
@@ -509,7 +516,7 @@ class Array:
509
516
 
510
517
  # Everything below this line is required by the spec.
511
518
 
512
- def __abs__(self: Array, /) -> Array:
519
+ def __abs__(self) -> Array:
513
520
  """
514
521
  Performs the operation __abs__.
515
522
  """
@@ -518,11 +525,11 @@ class Array:
518
525
  res = self._array.__abs__()
519
526
  return self.__class__._new(res, device=self.device)
520
527
 
521
- def __add__(self: Array, other: Union[int, float, Array], /) -> Array:
528
+ def __add__(self, other: Array | complex, /) -> Array:
522
529
  """
523
530
  Performs the operation __add__.
524
531
  """
525
- self._check_device(other)
532
+ self._check_type_device(other)
526
533
  other = self._check_allowed_dtypes(other, "numeric", "__add__")
527
534
  if other is NotImplemented:
528
535
  return other
@@ -530,11 +537,11 @@ class Array:
530
537
  res = self._array.__add__(other._array)
531
538
  return self.__class__._new(res, device=self.device)
532
539
 
533
- def __and__(self: Array, other: Union[int, bool, Array], /) -> Array:
540
+ def __and__(self, other: Array | int, /) -> Array:
534
541
  """
535
542
  Performs the operation __and__.
536
543
  """
537
- self._check_device(other)
544
+ self._check_type_device(other)
538
545
  other = self._check_allowed_dtypes(other, "integer or boolean", "__and__")
539
546
  if other is NotImplemented:
540
547
  return other
@@ -542,9 +549,7 @@ class Array:
542
549
  res = self._array.__and__(other._array)
543
550
  return self.__class__._new(res, device=self.device)
544
551
 
545
- def __array_namespace__(
546
- self: Array, /, *, api_version: Optional[str] = None
547
- ) -> types.ModuleType:
552
+ def __array_namespace__(self, /, *, api_version: str | None = None) -> ModuleType:
548
553
  """
549
554
  Return the array_api_strict namespace corresponding to api_version.
550
555
 
@@ -563,7 +568,7 @@ class Array:
563
568
  import array_api_strict
564
569
  return array_api_strict
565
570
 
566
- def __bool__(self: Array, /) -> bool:
571
+ def __bool__(self) -> bool:
567
572
  """
568
573
  Performs the operation __bool__.
569
574
  """
@@ -573,7 +578,7 @@ class Array:
573
578
  res = self._array.__bool__()
574
579
  return res
575
580
 
576
- def __complex__(self: Array, /) -> complex:
581
+ def __complex__(self) -> complex:
577
582
  """
578
583
  Performs the operation __complex__.
579
584
  """
@@ -584,56 +589,56 @@ class Array:
584
589
  return res
585
590
 
586
591
  def __dlpack__(
587
- self: Array,
592
+ self,
588
593
  /,
589
594
  *,
590
- stream: Optional[Union[int, Any]] = None,
591
- max_version: Optional[tuple[int, int]] = _default,
592
- dl_device: Optional[tuple[IntEnum, int]] = _default,
593
- copy: Optional[bool] = _default,
595
+ stream: Any = None,
596
+ max_version: tuple[int, int] | None | Undef = _undef,
597
+ dl_device: tuple[IntEnum, int] | None | Undef = _undef,
598
+ copy: bool | None | Undef = _undef,
594
599
  ) -> PyCapsule:
595
600
  """
596
601
  Performs the operation __dlpack__.
597
602
  """
598
603
  if get_array_api_strict_flags()['api_version'] < '2023.12':
599
- if max_version is not _default:
604
+ if max_version is not _undef:
600
605
  raise ValueError("The max_version argument to __dlpack__ requires at least version 2023.12 of the array API")
601
- if dl_device is not _default:
606
+ if dl_device is not _undef:
602
607
  raise ValueError("The device argument to __dlpack__ requires at least version 2023.12 of the array API")
603
- if copy is not _default:
608
+ if copy is not _undef:
604
609
  raise ValueError("The copy argument to __dlpack__ requires at least version 2023.12 of the array API")
605
610
 
606
611
  if np.lib.NumpyVersion(np.__version__) < '2.1.0':
607
- if max_version not in [_default, None]:
612
+ if max_version not in [_undef, None]:
608
613
  raise NotImplementedError("The max_version argument to __dlpack__ is not yet implemented")
609
- if dl_device not in [_default, None]:
614
+ if dl_device not in [_undef, None]:
610
615
  raise NotImplementedError("The device argument to __dlpack__ is not yet implemented")
611
- if copy not in [_default, None]:
616
+ if copy not in [_undef, None]:
612
617
  raise NotImplementedError("The copy argument to __dlpack__ is not yet implemented")
613
618
 
614
619
  return self._array.__dlpack__(stream=stream)
615
620
  else:
616
621
  kwargs = {'stream': stream}
617
- if max_version is not _default:
622
+ if max_version is not _undef:
618
623
  kwargs['max_version'] = max_version
619
- if dl_device is not _default:
624
+ if dl_device is not _undef:
620
625
  kwargs['dl_device'] = dl_device
621
- if copy is not _default:
626
+ if copy is not _undef:
622
627
  kwargs['copy'] = copy
623
628
  return self._array.__dlpack__(**kwargs)
624
629
 
625
- def __dlpack_device__(self: Array, /) -> Tuple[IntEnum, int]:
630
+ def __dlpack_device__(self) -> tuple[IntEnum, int]:
626
631
  """
627
632
  Performs the operation __dlpack_device__.
628
633
  """
629
634
  # Note: device support is required for this
630
635
  return self._array.__dlpack_device__()
631
636
 
632
- def __eq__(self: Array, other: Union[int, float, bool, Array], /) -> Array:
637
+ def __eq__(self, other: Array | complex, /) -> Array: # type: ignore[override]
633
638
  """
634
639
  Performs the operation __eq__.
635
640
  """
636
- self._check_device(other)
641
+ self._check_type_device(other)
637
642
  # Even though "all" dtypes are allowed, we still require them to be
638
643
  # promotable with each other.
639
644
  other = self._check_allowed_dtypes(other, "all", "__eq__")
@@ -643,7 +648,7 @@ class Array:
643
648
  res = self._array.__eq__(other._array)
644
649
  return self.__class__._new(res, device=self.device)
645
650
 
646
- def __float__(self: Array, /) -> float:
651
+ def __float__(self) -> float:
647
652
  """
648
653
  Performs the operation __float__.
649
654
  """
@@ -655,11 +660,11 @@ class Array:
655
660
  res = self._array.__float__()
656
661
  return res
657
662
 
658
- def __floordiv__(self: Array, other: Union[int, float, Array], /) -> Array:
663
+ def __floordiv__(self, other: Array | float, /) -> Array:
659
664
  """
660
665
  Performs the operation __floordiv__.
661
666
  """
662
- self._check_device(other)
667
+ self._check_type_device(other)
663
668
  other = self._check_allowed_dtypes(other, "real numeric", "__floordiv__")
664
669
  if other is NotImplemented:
665
670
  return other
@@ -667,11 +672,11 @@ class Array:
667
672
  res = self._array.__floordiv__(other._array)
668
673
  return self.__class__._new(res, device=self.device)
669
674
 
670
- def __ge__(self: Array, other: Union[int, float, Array], /) -> Array:
675
+ def __ge__(self, other: Array | float, /) -> Array:
671
676
  """
672
677
  Performs the operation __ge__.
673
678
  """
674
- self._check_device(other)
679
+ self._check_type_device(other)
675
680
  other = self._check_allowed_dtypes(other, "real numeric", "__ge__")
676
681
  if other is NotImplemented:
677
682
  return other
@@ -680,14 +685,15 @@ class Array:
680
685
  return self.__class__._new(res, device=self.device)
681
686
 
682
687
  def __getitem__(
683
- self: Array,
684
- key: Union[
685
- int,
686
- slice,
687
- ellipsis, # noqa: F821
688
- Tuple[Union[int, slice, ellipsis, None], ...], # noqa: F821
689
- Array,
690
- ],
688
+ self,
689
+ key: (
690
+ int
691
+ | slice
692
+ | EllipsisType
693
+ | Array
694
+ | None
695
+ | tuple[int | slice | EllipsisType | Array | None, ...]
696
+ ),
691
697
  /,
692
698
  ) -> Array:
693
699
  """
@@ -696,18 +702,33 @@ class Array:
696
702
  # XXX Does key have to be on the same device? Is there an exception for CPU_DEVICE?
697
703
  # Note: Only indices required by the spec are allowed. See the
698
704
  # docstring of _validate_index
699
- self._validate_index(key)
705
+ self._validate_index(key, op="getitem")
700
706
  if isinstance(key, Array):
707
+ key = (key,)
708
+ np_key = key
709
+ devices = {self.device}
710
+ if isinstance(key, tuple):
711
+ devices.update(
712
+ [subkey.device for subkey in key if isinstance(subkey, Array)]
713
+ )
714
+ if len(devices) > 1:
715
+ raise ValueError(
716
+ "Array indexing is only allowed when array to be indexed and all "
717
+ "indexing arrays are on the same device."
718
+ )
701
719
  # Indexing self._array with array_api_strict arrays can be erroneous
702
- key = key._array
703
- res = self._array.__getitem__(key)
720
+ # e.g., when using non-default device
721
+ np_key = tuple(
722
+ subkey._array if isinstance(subkey, Array) else subkey for subkey in key
723
+ )
724
+ res = self._array.__getitem__(np_key)
704
725
  return self._new(res, device=self.device)
705
726
 
706
- def __gt__(self: Array, other: Union[int, float, Array], /) -> Array:
727
+ def __gt__(self, other: Array | float, /) -> Array:
707
728
  """
708
729
  Performs the operation __gt__.
709
730
  """
710
- self._check_device(other)
731
+ self._check_type_device(other)
711
732
  other = self._check_allowed_dtypes(other, "real numeric", "__gt__")
712
733
  if other is NotImplemented:
713
734
  return other
@@ -715,7 +736,7 @@ class Array:
715
736
  res = self._array.__gt__(other._array)
716
737
  return self.__class__._new(res, device=other.device)
717
738
 
718
- def __int__(self: Array, /) -> int:
739
+ def __int__(self) -> int:
719
740
  """
720
741
  Performs the operation __int__.
721
742
  """
@@ -727,14 +748,14 @@ class Array:
727
748
  res = self._array.__int__()
728
749
  return res
729
750
 
730
- def __index__(self: Array, /) -> int:
751
+ def __index__(self) -> int:
731
752
  """
732
753
  Performs the operation __index__.
733
754
  """
734
755
  res = self._array.__index__()
735
756
  return res
736
757
 
737
- def __invert__(self: Array, /) -> Array:
758
+ def __invert__(self) -> Array:
738
759
  """
739
760
  Performs the operation __invert__.
740
761
  """
@@ -743,7 +764,7 @@ class Array:
743
764
  res = self._array.__invert__()
744
765
  return self.__class__._new(res, device=self.device)
745
766
 
746
- def __iter__(self: Array, /):
767
+ def __iter__(self) -> Iterator[Array]:
747
768
  """
748
769
  Performs the operation __iter__.
749
770
  """
@@ -758,11 +779,11 @@ class Array:
758
779
  # implemented, which implies iteration on 1-D arrays.
759
780
  return (Array._new(i, device=self.device) for i in self._array)
760
781
 
761
- def __le__(self: Array, other: Union[int, float, Array], /) -> Array:
782
+ def __le__(self, other: Array | float, /) -> Array:
762
783
  """
763
784
  Performs the operation __le__.
764
785
  """
765
- self._check_device(other)
786
+ self._check_type_device(other)
766
787
  other = self._check_allowed_dtypes(other, "real numeric", "__le__")
767
788
  if other is NotImplemented:
768
789
  return other
@@ -770,11 +791,11 @@ class Array:
770
791
  res = self._array.__le__(other._array)
771
792
  return self.__class__._new(res, device=self.device)
772
793
 
773
- def __lshift__(self: Array, other: Union[int, Array], /) -> Array:
794
+ def __lshift__(self, other: Array | int, /) -> Array:
774
795
  """
775
796
  Performs the operation __lshift__.
776
797
  """
777
- self._check_device(other)
798
+ self._check_type_device(other)
778
799
  other = self._check_allowed_dtypes(other, "integer", "__lshift__")
779
800
  if other is NotImplemented:
780
801
  return other
@@ -782,11 +803,11 @@ class Array:
782
803
  res = self._array.__lshift__(other._array)
783
804
  return self.__class__._new(res, device=self.device)
784
805
 
785
- def __lt__(self: Array, other: Union[int, float, Array], /) -> Array:
806
+ def __lt__(self, other: Array | float, /) -> Array:
786
807
  """
787
808
  Performs the operation __lt__.
788
809
  """
789
- self._check_device(other)
810
+ self._check_type_device(other)
790
811
  other = self._check_allowed_dtypes(other, "real numeric", "__lt__")
791
812
  if other is NotImplemented:
792
813
  return other
@@ -794,11 +815,11 @@ class Array:
794
815
  res = self._array.__lt__(other._array)
795
816
  return self.__class__._new(res, device=self.device)
796
817
 
797
- def __matmul__(self: Array, other: Array, /) -> Array:
818
+ def __matmul__(self, other: Array, /) -> Array:
798
819
  """
799
820
  Performs the operation __matmul__.
800
821
  """
801
- self._check_device(other)
822
+ self._check_type_device(other)
802
823
  # matmul is not defined for scalars, but without this, we may get
803
824
  # the wrong error message from asarray.
804
825
  other = self._check_allowed_dtypes(other, "numeric", "__matmul__")
@@ -807,11 +828,11 @@ class Array:
807
828
  res = self._array.__matmul__(other._array)
808
829
  return self.__class__._new(res, device=self.device)
809
830
 
810
- def __mod__(self: Array, other: Union[int, float, Array], /) -> Array:
831
+ def __mod__(self, other: Array | float, /) -> Array:
811
832
  """
812
833
  Performs the operation __mod__.
813
834
  """
814
- self._check_device(other)
835
+ self._check_type_device(other)
815
836
  other = self._check_allowed_dtypes(other, "real numeric", "__mod__")
816
837
  if other is NotImplemented:
817
838
  return other
@@ -819,11 +840,11 @@ class Array:
819
840
  res = self._array.__mod__(other._array)
820
841
  return self.__class__._new(res, device=self.device)
821
842
 
822
- def __mul__(self: Array, other: Union[int, float, Array], /) -> Array:
843
+ def __mul__(self, other: Array | complex, /) -> Array:
823
844
  """
824
845
  Performs the operation __mul__.
825
846
  """
826
- self._check_device(other)
847
+ self._check_type_device(other)
827
848
  other = self._check_allowed_dtypes(other, "numeric", "__mul__")
828
849
  if other is NotImplemented:
829
850
  return other
@@ -831,11 +852,11 @@ class Array:
831
852
  res = self._array.__mul__(other._array)
832
853
  return self.__class__._new(res, device=self.device)
833
854
 
834
- def __ne__(self: Array, other: Union[int, float, bool, Array], /) -> Array:
855
+ def __ne__(self, other: Array | complex, /) -> Array: # type: ignore[override]
835
856
  """
836
857
  Performs the operation __ne__.
837
858
  """
838
- self._check_device(other)
859
+ self._check_type_device(other)
839
860
  other = self._check_allowed_dtypes(other, "all", "__ne__")
840
861
  if other is NotImplemented:
841
862
  return other
@@ -843,7 +864,7 @@ class Array:
843
864
  res = self._array.__ne__(other._array)
844
865
  return self.__class__._new(res, device=self.device)
845
866
 
846
- def __neg__(self: Array, /) -> Array:
867
+ def __neg__(self) -> Array:
847
868
  """
848
869
  Performs the operation __neg__.
849
870
  """
@@ -852,11 +873,11 @@ class Array:
852
873
  res = self._array.__neg__()
853
874
  return self.__class__._new(res, device=self.device)
854
875
 
855
- def __or__(self: Array, other: Union[int, bool, Array], /) -> Array:
876
+ def __or__(self, other: Array | int, /) -> Array:
856
877
  """
857
878
  Performs the operation __or__.
858
879
  """
859
- self._check_device(other)
880
+ self._check_type_device(other)
860
881
  other = self._check_allowed_dtypes(other, "integer or boolean", "__or__")
861
882
  if other is NotImplemented:
862
883
  return other
@@ -864,7 +885,7 @@ class Array:
864
885
  res = self._array.__or__(other._array)
865
886
  return self.__class__._new(res, device=self.device)
866
887
 
867
- def __pos__(self: Array, /) -> Array:
888
+ def __pos__(self) -> Array:
868
889
  """
869
890
  Performs the operation __pos__.
870
891
  """
@@ -873,13 +894,13 @@ class Array:
873
894
  res = self._array.__pos__()
874
895
  return self.__class__._new(res, device=self.device)
875
896
 
876
- def __pow__(self: Array, other: Union[int, float, Array], /) -> Array:
897
+ def __pow__(self, other: Array | complex, /) -> Array:
877
898
  """
878
899
  Performs the operation __pow__.
879
900
  """
880
- from ._elementwise_functions import pow
901
+ from ._elementwise_functions import pow # type: ignore[attr-defined]
881
902
 
882
- self._check_device(other)
903
+ self._check_type_device(other)
883
904
  other = self._check_allowed_dtypes(other, "numeric", "__pow__")
884
905
  if other is NotImplemented:
885
906
  return other
@@ -887,11 +908,11 @@ class Array:
887
908
  # arrays, so we use pow() here instead.
888
909
  return pow(self, other)
889
910
 
890
- def __rshift__(self: Array, other: Union[int, Array], /) -> Array:
911
+ def __rshift__(self, other: Array | int, /) -> Array:
891
912
  """
892
913
  Performs the operation __rshift__.
893
914
  """
894
- self._check_device(other)
915
+ self._check_type_device(other)
895
916
  other = self._check_allowed_dtypes(other, "integer", "__rshift__")
896
917
  if other is NotImplemented:
897
918
  return other
@@ -901,10 +922,16 @@ class Array:
901
922
 
902
923
  def __setitem__(
903
924
  self,
904
- key: Union[
905
- int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], Array # noqa: F821
906
- ],
907
- value: Union[int, float, bool, Array],
925
+ # Almost same as __getitem__ key but doesn't accept None
926
+ # or integer arrays
927
+ key: (
928
+ int
929
+ | slice
930
+ | EllipsisType
931
+ | Array
932
+ | tuple[int | slice | EllipsisType, ...]
933
+ ),
934
+ value: Array | complex,
908
935
  /,
909
936
  ) -> None:
910
937
  """
@@ -913,16 +940,15 @@ class Array:
913
940
  # Note: Only indices required by the spec are allowed. See the
914
941
  # docstring of _validate_index
915
942
  self._validate_index(key, op="setitem")
916
- if isinstance(key, Array):
917
- # Indexing self._array with array_api_strict arrays can be erroneous
918
- key = key._array
919
- self._array.__setitem__(key, asarray(value)._array)
943
+ # Indexing self._array with array_api_strict arrays can be erroneous
944
+ np_key = key._array if isinstance(key, Array) else key
945
+ self._array.__setitem__(np_key, asarray(value)._array)
920
946
 
921
- def __sub__(self: Array, other: Union[int, float, Array], /) -> Array:
947
+ def __sub__(self, other: Array | complex, /) -> Array:
922
948
  """
923
949
  Performs the operation __sub__.
924
950
  """
925
- self._check_device(other)
951
+ self._check_type_device(other)
926
952
  other = self._check_allowed_dtypes(other, "numeric", "__sub__")
927
953
  if other is NotImplemented:
928
954
  return other
@@ -932,11 +958,11 @@ class Array:
932
958
 
933
959
  # PEP 484 requires int to be a subtype of float, but __truediv__ should
934
960
  # not accept int.
935
- def __truediv__(self: Array, other: Union[float, Array], /) -> Array:
961
+ def __truediv__(self, other: Array | complex, /) -> Array:
936
962
  """
937
963
  Performs the operation __truediv__.
938
964
  """
939
- self._check_device(other)
965
+ self._check_type_device(other)
940
966
  other = self._check_allowed_dtypes(other, "floating-point", "__truediv__")
941
967
  if other is NotImplemented:
942
968
  return other
@@ -944,11 +970,11 @@ class Array:
944
970
  res = self._array.__truediv__(other._array)
945
971
  return self.__class__._new(res, device=self.device)
946
972
 
947
- def __xor__(self: Array, other: Union[int, bool, Array], /) -> Array:
973
+ def __xor__(self, other: Array | int, /) -> Array:
948
974
  """
949
975
  Performs the operation __xor__.
950
976
  """
951
- self._check_device(other)
977
+ self._check_type_device(other)
952
978
  other = self._check_allowed_dtypes(other, "integer or boolean", "__xor__")
953
979
  if other is NotImplemented:
954
980
  return other
@@ -956,22 +982,22 @@ class Array:
956
982
  res = self._array.__xor__(other._array)
957
983
  return self.__class__._new(res, device=self.device)
958
984
 
959
- def __iadd__(self: Array, other: Union[int, float, Array], /) -> Array:
985
+ def __iadd__(self, other: Array | complex, /) -> Array:
960
986
  """
961
987
  Performs the operation __iadd__.
962
988
  """
963
- self._check_device(other)
989
+ self._check_type_device(other)
964
990
  other = self._check_allowed_dtypes(other, "numeric", "__iadd__")
965
991
  if other is NotImplemented:
966
992
  return other
967
993
  self._array.__iadd__(other._array)
968
994
  return self
969
995
 
970
- def __radd__(self: Array, other: Union[int, float, Array], /) -> Array:
996
+ def __radd__(self, other: Array | complex, /) -> Array:
971
997
  """
972
998
  Performs the operation __radd__.
973
999
  """
974
- self._check_device(other)
1000
+ self._check_type_device(other)
975
1001
  other = self._check_allowed_dtypes(other, "numeric", "__radd__")
976
1002
  if other is NotImplemented:
977
1003
  return other
@@ -979,22 +1005,22 @@ class Array:
979
1005
  res = self._array.__radd__(other._array)
980
1006
  return self.__class__._new(res, device=self.device)
981
1007
 
982
- def __iand__(self: Array, other: Union[int, bool, Array], /) -> Array:
1008
+ def __iand__(self, other: Array | int, /) -> Array:
983
1009
  """
984
1010
  Performs the operation __iand__.
985
1011
  """
986
- self._check_device(other)
1012
+ self._check_type_device(other)
987
1013
  other = self._check_allowed_dtypes(other, "integer or boolean", "__iand__")
988
1014
  if other is NotImplemented:
989
1015
  return other
990
1016
  self._array.__iand__(other._array)
991
1017
  return self
992
1018
 
993
- def __rand__(self: Array, other: Union[int, bool, Array], /) -> Array:
1019
+ def __rand__(self, other: Array | int, /) -> Array:
994
1020
  """
995
1021
  Performs the operation __rand__.
996
1022
  """
997
- self._check_device(other)
1023
+ self._check_type_device(other)
998
1024
  other = self._check_allowed_dtypes(other, "integer or boolean", "__rand__")
999
1025
  if other is NotImplemented:
1000
1026
  return other
@@ -1002,22 +1028,22 @@ class Array:
1002
1028
  res = self._array.__rand__(other._array)
1003
1029
  return self.__class__._new(res, device=self.device)
1004
1030
 
1005
- def __ifloordiv__(self: Array, other: Union[int, float, Array], /) -> Array:
1031
+ def __ifloordiv__(self, other: Array | float, /) -> Array:
1006
1032
  """
1007
1033
  Performs the operation __ifloordiv__.
1008
1034
  """
1009
- self._check_device(other)
1035
+ self._check_type_device(other)
1010
1036
  other = self._check_allowed_dtypes(other, "real numeric", "__ifloordiv__")
1011
1037
  if other is NotImplemented:
1012
1038
  return other
1013
1039
  self._array.__ifloordiv__(other._array)
1014
1040
  return self
1015
1041
 
1016
- def __rfloordiv__(self: Array, other: Union[int, float, Array], /) -> Array:
1042
+ def __rfloordiv__(self, other: Array | float, /) -> Array:
1017
1043
  """
1018
1044
  Performs the operation __rfloordiv__.
1019
1045
  """
1020
- self._check_device(other)
1046
+ self._check_type_device(other)
1021
1047
  other = self._check_allowed_dtypes(other, "real numeric", "__rfloordiv__")
1022
1048
  if other is NotImplemented:
1023
1049
  return other
@@ -1025,22 +1051,22 @@ class Array:
1025
1051
  res = self._array.__rfloordiv__(other._array)
1026
1052
  return self.__class__._new(res, device=self.device)
1027
1053
 
1028
- def __ilshift__(self: Array, other: Union[int, Array], /) -> Array:
1054
+ def __ilshift__(self, other: Array | int, /) -> Array:
1029
1055
  """
1030
1056
  Performs the operation __ilshift__.
1031
1057
  """
1032
- self._check_device(other)
1058
+ self._check_type_device(other)
1033
1059
  other = self._check_allowed_dtypes(other, "integer", "__ilshift__")
1034
1060
  if other is NotImplemented:
1035
1061
  return other
1036
1062
  self._array.__ilshift__(other._array)
1037
1063
  return self
1038
1064
 
1039
- def __rlshift__(self: Array, other: Union[int, Array], /) -> Array:
1065
+ def __rlshift__(self, other: Array | int, /) -> Array:
1040
1066
  """
1041
1067
  Performs the operation __rlshift__.
1042
1068
  """
1043
- self._check_device(other)
1069
+ self._check_type_device(other)
1044
1070
  other = self._check_allowed_dtypes(other, "integer", "__rlshift__")
1045
1071
  if other is NotImplemented:
1046
1072
  return other
@@ -1048,7 +1074,7 @@ class Array:
1048
1074
  res = self._array.__rlshift__(other._array)
1049
1075
  return self.__class__._new(res, device=self.device)
1050
1076
 
1051
- def __imatmul__(self: Array, other: Array, /) -> Array:
1077
+ def __imatmul__(self, other: Array, /) -> Array:
1052
1078
  """
1053
1079
  Performs the operation __imatmul__.
1054
1080
  """
@@ -1057,11 +1083,11 @@ class Array:
1057
1083
  other = self._check_allowed_dtypes(other, "numeric", "__imatmul__")
1058
1084
  if other is NotImplemented:
1059
1085
  return other
1060
- self._check_device(other)
1086
+ self._check_type_device(other)
1061
1087
  res = self._array.__imatmul__(other._array)
1062
1088
  return self.__class__._new(res, device=self.device)
1063
1089
 
1064
- def __rmatmul__(self: Array, other: Array, /) -> Array:
1090
+ def __rmatmul__(self, other: Array, /) -> Array:
1065
1091
  """
1066
1092
  Performs the operation __rmatmul__.
1067
1093
  """
@@ -1070,11 +1096,11 @@ class Array:
1070
1096
  other = self._check_allowed_dtypes(other, "numeric", "__rmatmul__")
1071
1097
  if other is NotImplemented:
1072
1098
  return other
1073
- self._check_device(other)
1099
+ self._check_type_device(other)
1074
1100
  res = self._array.__rmatmul__(other._array)
1075
1101
  return self.__class__._new(res, device=self.device)
1076
1102
 
1077
- def __imod__(self: Array, other: Union[int, float, Array], /) -> Array:
1103
+ def __imod__(self, other: Array | float, /) -> Array:
1078
1104
  """
1079
1105
  Performs the operation __imod__.
1080
1106
  """
@@ -1084,19 +1110,19 @@ class Array:
1084
1110
  self._array.__imod__(other._array)
1085
1111
  return self
1086
1112
 
1087
- def __rmod__(self: Array, other: Union[int, float, Array], /) -> Array:
1113
+ def __rmod__(self, other: Array | float, /) -> Array:
1088
1114
  """
1089
1115
  Performs the operation __rmod__.
1090
1116
  """
1091
1117
  other = self._check_allowed_dtypes(other, "real numeric", "__rmod__")
1092
1118
  if other is NotImplemented:
1093
1119
  return other
1094
- self._check_device(other)
1120
+ self._check_type_device(other)
1095
1121
  self, other = self._normalize_two_args(self, other)
1096
1122
  res = self._array.__rmod__(other._array)
1097
1123
  return self.__class__._new(res, device=self.device)
1098
1124
 
1099
- def __imul__(self: Array, other: Union[int, float, Array], /) -> Array:
1125
+ def __imul__(self, other: Array | complex, /) -> Array:
1100
1126
  """
1101
1127
  Performs the operation __imul__.
1102
1128
  """
@@ -1106,19 +1132,19 @@ class Array:
1106
1132
  self._array.__imul__(other._array)
1107
1133
  return self
1108
1134
 
1109
- def __rmul__(self: Array, other: Union[int, float, Array], /) -> Array:
1135
+ def __rmul__(self, other: Array | complex, /) -> Array:
1110
1136
  """
1111
1137
  Performs the operation __rmul__.
1112
1138
  """
1113
1139
  other = self._check_allowed_dtypes(other, "numeric", "__rmul__")
1114
1140
  if other is NotImplemented:
1115
1141
  return other
1116
- self._check_device(other)
1142
+ self._check_type_device(other)
1117
1143
  self, other = self._normalize_two_args(self, other)
1118
1144
  res = self._array.__rmul__(other._array)
1119
1145
  return self.__class__._new(res, device=self.device)
1120
1146
 
1121
- def __ior__(self: Array, other: Union[int, bool, Array], /) -> Array:
1147
+ def __ior__(self, other: Array | int, /) -> Array:
1122
1148
  """
1123
1149
  Performs the operation __ior__.
1124
1150
  """
@@ -1128,11 +1154,11 @@ class Array:
1128
1154
  self._array.__ior__(other._array)
1129
1155
  return self
1130
1156
 
1131
- def __ror__(self: Array, other: Union[int, bool, Array], /) -> Array:
1157
+ def __ror__(self, other: Array | int, /) -> Array:
1132
1158
  """
1133
1159
  Performs the operation __ror__.
1134
1160
  """
1135
- self._check_device(other)
1161
+ self._check_type_device(other)
1136
1162
  other = self._check_allowed_dtypes(other, "integer or boolean", "__ror__")
1137
1163
  if other is NotImplemented:
1138
1164
  return other
@@ -1140,7 +1166,7 @@ class Array:
1140
1166
  res = self._array.__ror__(other._array)
1141
1167
  return self.__class__._new(res, device=self.device)
1142
1168
 
1143
- def __ipow__(self: Array, other: Union[int, float, Array], /) -> Array:
1169
+ def __ipow__(self, other: Array | complex, /) -> Array:
1144
1170
  """
1145
1171
  Performs the operation __ipow__.
1146
1172
  """
@@ -1150,11 +1176,11 @@ class Array:
1150
1176
  self._array.__ipow__(other._array)
1151
1177
  return self
1152
1178
 
1153
- def __rpow__(self: Array, other: Union[int, float, Array], /) -> Array:
1179
+ def __rpow__(self, other: Array | complex, /) -> Array:
1154
1180
  """
1155
1181
  Performs the operation __rpow__.
1156
1182
  """
1157
- from ._elementwise_functions import pow
1183
+ from ._elementwise_functions import pow # type: ignore[attr-defined]
1158
1184
 
1159
1185
  other = self._check_allowed_dtypes(other, "numeric", "__rpow__")
1160
1186
  if other is NotImplemented:
@@ -1163,7 +1189,7 @@ class Array:
1163
1189
  # for 0-d arrays, so we use pow() here instead.
1164
1190
  return pow(other, self)
1165
1191
 
1166
- def __irshift__(self: Array, other: Union[int, Array], /) -> Array:
1192
+ def __irshift__(self, other: Array | int, /) -> Array:
1167
1193
  """
1168
1194
  Performs the operation __irshift__.
1169
1195
  """
@@ -1173,19 +1199,19 @@ class Array:
1173
1199
  self._array.__irshift__(other._array)
1174
1200
  return self
1175
1201
 
1176
- def __rrshift__(self: Array, other: Union[int, Array], /) -> Array:
1202
+ def __rrshift__(self, other: Array | int, /) -> Array:
1177
1203
  """
1178
1204
  Performs the operation __rrshift__.
1179
1205
  """
1180
1206
  other = self._check_allowed_dtypes(other, "integer", "__rrshift__")
1181
1207
  if other is NotImplemented:
1182
1208
  return other
1183
- self._check_device(other)
1209
+ self._check_type_device(other)
1184
1210
  self, other = self._normalize_two_args(self, other)
1185
1211
  res = self._array.__rrshift__(other._array)
1186
1212
  return self.__class__._new(res, device=self.device)
1187
1213
 
1188
- def __isub__(self: Array, other: Union[int, float, Array], /) -> Array:
1214
+ def __isub__(self, other: Array | complex, /) -> Array:
1189
1215
  """
1190
1216
  Performs the operation __isub__.
1191
1217
  """
@@ -1195,19 +1221,19 @@ class Array:
1195
1221
  self._array.__isub__(other._array)
1196
1222
  return self
1197
1223
 
1198
- def __rsub__(self: Array, other: Union[int, float, Array], /) -> Array:
1224
+ def __rsub__(self, other: Array | complex, /) -> Array:
1199
1225
  """
1200
1226
  Performs the operation __rsub__.
1201
1227
  """
1202
1228
  other = self._check_allowed_dtypes(other, "numeric", "__rsub__")
1203
1229
  if other is NotImplemented:
1204
1230
  return other
1205
- self._check_device(other)
1231
+ self._check_type_device(other)
1206
1232
  self, other = self._normalize_two_args(self, other)
1207
1233
  res = self._array.__rsub__(other._array)
1208
1234
  return self.__class__._new(res, device=self.device)
1209
1235
 
1210
- def __itruediv__(self: Array, other: Union[float, Array], /) -> Array:
1236
+ def __itruediv__(self, other: Array | complex, /) -> Array:
1211
1237
  """
1212
1238
  Performs the operation __itruediv__.
1213
1239
  """
@@ -1217,19 +1243,19 @@ class Array:
1217
1243
  self._array.__itruediv__(other._array)
1218
1244
  return self
1219
1245
 
1220
- def __rtruediv__(self: Array, other: Union[float, Array], /) -> Array:
1246
+ def __rtruediv__(self, other: Array | complex, /) -> Array:
1221
1247
  """
1222
1248
  Performs the operation __rtruediv__.
1223
1249
  """
1224
1250
  other = self._check_allowed_dtypes(other, "floating-point", "__rtruediv__")
1225
1251
  if other is NotImplemented:
1226
1252
  return other
1227
- self._check_device(other)
1253
+ self._check_type_device(other)
1228
1254
  self, other = self._normalize_two_args(self, other)
1229
1255
  res = self._array.__rtruediv__(other._array)
1230
1256
  return self.__class__._new(res, device=self.device)
1231
1257
 
1232
- def __ixor__(self: Array, other: Union[int, bool, Array], /) -> Array:
1258
+ def __ixor__(self, other: Array | int, /) -> Array:
1233
1259
  """
1234
1260
  Performs the operation __ixor__.
1235
1261
  """
@@ -1239,19 +1265,19 @@ class Array:
1239
1265
  self._array.__ixor__(other._array)
1240
1266
  return self
1241
1267
 
1242
- def __rxor__(self: Array, other: Union[int, bool, Array], /) -> Array:
1268
+ def __rxor__(self, other: Array | int, /) -> Array:
1243
1269
  """
1244
1270
  Performs the operation __rxor__.
1245
1271
  """
1246
1272
  other = self._check_allowed_dtypes(other, "integer or boolean", "__rxor__")
1247
1273
  if other is NotImplemented:
1248
1274
  return other
1249
- self._check_device(other)
1275
+ self._check_type_device(other)
1250
1276
  self, other = self._normalize_two_args(self, other)
1251
1277
  res = self._array.__rxor__(other._array)
1252
1278
  return self.__class__._new(res, device=self.device)
1253
1279
 
1254
- def to_device(self: Array, device: Device, /, stream: None = None) -> Array:
1280
+ def to_device(self, device: Device, /, stream: None = None) -> Array:
1255
1281
  if stream is not None:
1256
1282
  raise ValueError("The stream argument to to_device() is not supported")
1257
1283
  if device == self._device:
@@ -1262,7 +1288,7 @@ class Array:
1262
1288
  raise ValueError(f"Unsupported device {device!r}")
1263
1289
 
1264
1290
  @property
1265
- def dtype(self) -> Dtype:
1291
+ def dtype(self) -> DType:
1266
1292
  """
1267
1293
  Array API compatible wrapper for :py:meth:`np.ndarray.dtype <numpy.ndarray.dtype>`.
1268
1294
 
@@ -1290,7 +1316,7 @@ class Array:
1290
1316
  return self._array.ndim
1291
1317
 
1292
1318
  @property
1293
- def shape(self) -> Tuple[int, ...]:
1319
+ def shape(self) -> tuple[int, ...]:
1294
1320
  """
1295
1321
  Array API compatible wrapper for :py:meth:`np.ndarray.shape <numpy.ndarray.shape>`.
1296
1322