pyopencl 2025.1__cp310-cp310-win_amd64.whl → 2025.2.2__cp310-cp310-win_amd64.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.

Potentially problematic release.


This version of pyopencl might be problematic. Click here for more details.

pyopencl/array.py CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  # NOTE: for elwise_kernel_runner which adds keyword arguments
4
4
  # pylint:disable=unexpected-keyword-arg
5
+ from __future__ import annotations
6
+
5
7
 
6
8
  __copyright__ = "Copyright (C) 2009 Andreas Kloeckner"
7
9
 
@@ -32,10 +34,19 @@ import builtins
32
34
  from dataclasses import dataclass
33
35
  from functools import reduce
34
36
  from numbers import Number
35
- from typing import Any, Dict, List, Optional, Tuple, Union
37
+ from typing import (
38
+ TYPE_CHECKING,
39
+ Any,
40
+ ClassVar,
41
+ Concatenate,
42
+ Literal,
43
+ ParamSpec,
44
+ cast,
45
+ )
36
46
  from warnings import warn
37
47
 
38
48
  import numpy as np
49
+ from typing_extensions import Self, override
39
50
 
40
51
  import pyopencl as cl
41
52
  import pyopencl.elementwise as elementwise
@@ -50,6 +61,14 @@ from pyopencl.compyte.array import (
50
61
  )
51
62
 
52
63
 
64
+ if TYPE_CHECKING:
65
+ from collections.abc import Callable, Hashable
66
+
67
+ from numpy.typing import DTypeLike, NDArray
68
+
69
+ from pyopencl.typing import Allocator
70
+
71
+
53
72
  SCALAR_CLASSES = (Number, np.bool_, bool)
54
73
 
55
74
  if cl.get_cl_header_version() >= (2, 0):
@@ -58,6 +77,10 @@ else:
58
77
  _SVMPointer_or_nothing = ()
59
78
 
60
79
 
80
+ class _NoValue:
81
+ pass
82
+
83
+
61
84
  # {{{ _get_common_dtype
62
85
 
63
86
  class DoubleDowncastWarning(UserWarning):
@@ -160,7 +183,11 @@ vec = VecLookupWarner()
160
183
 
161
184
  # {{{ helper functionality
162
185
 
163
- def _splay(device, n, kernel_specific_max_wg_size=None):
186
+ def _splay(
187
+ device: cl.Device,
188
+ n: int,
189
+ kernel_specific_max_wg_size: int | None = None,
190
+ ):
164
191
  max_work_items = builtins.min(128, device.max_work_group_size)
165
192
 
166
193
  if kernel_specific_max_wg_size is not None:
@@ -195,7 +222,12 @@ def _splay(device, n, kernel_specific_max_wg_size=None):
195
222
  ARRAY_KERNEL_EXEC_HOOK = None
196
223
 
197
224
 
198
- def elwise_kernel_runner(kernel_getter):
225
+ P = ParamSpec("P")
226
+
227
+
228
+ def elwise_kernel_runner(
229
+ kernel_getter: Callable[Concatenate[Array, P], cl.Kernel]
230
+ ) -> Callable[Concatenate[Array, P], cl.Event]:
199
231
  """Take a kernel getter of the same signature as the kernel
200
232
  and return a function that invokes that kernel.
201
233
 
@@ -204,40 +236,31 @@ def elwise_kernel_runner(kernel_getter):
204
236
  from functools import wraps
205
237
 
206
238
  @wraps(kernel_getter)
207
- def kernel_runner(out, *args, **kwargs):
239
+ def kernel_runner(out: Array, *args: P.args, **kwargs: P.kwargs) -> cl.Event:
208
240
  assert isinstance(out, Array)
209
241
 
210
- wait_for = kwargs.pop("wait_for", None)
211
- queue = kwargs.pop("queue", None)
242
+ wait_for = cast("cl.WaitList", kwargs.pop("wait_for", None))
243
+ queue = cast("cl.CommandQueue | None", kwargs.pop("queue", None))
212
244
  if queue is None:
213
245
  queue = out.queue
214
246
 
215
247
  assert queue is not None
216
248
 
217
249
  knl = kernel_getter(out, *args, **kwargs)
218
- work_group_info = knl.get_work_group_info(
250
+ work_group_info = cast("int", knl.get_work_group_info(
219
251
  cl.kernel_work_group_info.WORK_GROUP_SIZE,
220
- queue.device)
252
+ queue.device))
221
253
  gs, ls = out._get_sizes(queue, work_group_info)
222
254
 
223
- args = (out, *args, out.size)
255
+ knl_args = (out, *args, out.size)
224
256
  if ARRAY_KERNEL_EXEC_HOOK is not None:
225
257
  return ARRAY_KERNEL_EXEC_HOOK( # pylint: disable=not-callable
226
- knl, queue, gs, ls, *args, wait_for=wait_for)
258
+ knl, queue, gs, ls, *knl_args, wait_for=wait_for)
227
259
  else:
228
- return knl(queue, gs, ls, *args, wait_for=wait_for)
260
+ return knl(queue, gs, ls, *knl_args, wait_for=wait_for)
229
261
 
230
262
  return kernel_runner
231
263
 
232
-
233
- class DefaultAllocator(cl.tools.DeferredAllocator):
234
- def __init__(self, *args, **kwargs):
235
- warn("pyopencl.array.DefaultAllocator is deprecated. "
236
- "It will be continue to exist throughout the 2013.x "
237
- "versions of PyOpenCL.",
238
- DeprecationWarning, stacklevel=2)
239
- cl.tools.DeferredAllocator.__init__(self, *args, **kwargs)
240
-
241
264
  # }}}
242
265
 
243
266
 
@@ -262,7 +285,8 @@ class _copy_queue: # noqa: N801
262
285
  pass
263
286
 
264
287
 
265
- _ARRAY_GET_SIZES_CACHE: Dict[Tuple[int, int, int], Tuple[int, int]] = {}
288
+ _ARRAY_GET_SIZES_CACHE: \
289
+ dict[Hashable, tuple[tuple[int, ...], tuple[int, ...]]] = {}
266
290
  _BOOL_DTYPE = np.dtype(np.int8)
267
291
  _NOT_PRESENT = object()
268
292
 
@@ -453,29 +477,39 @@ class Array:
453
477
  .. automethod:: finish
454
478
  """
455
479
 
456
- __array_priority__ = 100
480
+ __array_priority__: ClassVar[int] = 100
481
+
482
+ queue: cl.CommandQueue | None
483
+ shape: tuple[int, ...]
484
+ dtype: np.dtype[Any]
485
+ strides: tuple[int, ...]
486
+ events: list[cl.Event]
487
+ nbytes: int
488
+ size: int
489
+ allocator: Allocator | None
490
+ base_data: cl.MemoryObjectHolder | cl.SVMPointer | None
457
491
 
458
492
  def __init__(
459
493
  self,
460
- cq: Optional[Union[cl.Context, cl.CommandQueue]],
461
- shape: Union[Tuple[int, ...], int],
462
- dtype: Any,
494
+ cq: cl.Context | cl.CommandQueue | None,
495
+ shape: tuple[int, ...] | int,
496
+ dtype: DTypeLike,
463
497
  order: str = "C",
464
- allocator: Optional[cl.tools.AllocatorBase] = None,
498
+ allocator: Allocator | None = None,
465
499
  data: Any = None,
466
500
  offset: int = 0,
467
- strides: Optional[Tuple[int, ...]] = None,
468
- events: Optional[List[cl.Event]] = None,
501
+ strides: tuple[int, ...] | None = None,
502
+ events: list[cl.Event] | None = None,
469
503
 
470
504
  # NOTE: following args are used for the fast constructor
471
505
  _flags: Any = None,
472
506
  _fast: bool = False,
473
- _size: Optional[int] = None,
474
- _context: Optional[cl.Context] = None,
475
- _queue: Optional[cl.CommandQueue] = None) -> None:
507
+ _size: int | None = None,
508
+ _context: cl.Context | None = None,
509
+ _queue: cl.CommandQueue | None = None) -> None:
476
510
  if _fast:
477
511
  # Assumptions, should be disabled if not testing
478
- if 0:
512
+ if TYPE_CHECKING:
479
513
  assert cq is None
480
514
  assert isinstance(_context, cl.Context)
481
515
  assert _queue is None or isinstance(_queue, cl.CommandQueue)
@@ -648,8 +682,15 @@ class Array:
648
682
  self._flags = f = _ArrayFlags(self)
649
683
  return f
650
684
 
651
- def _new_with_changes(self, data, offset, shape=None, dtype=None,
652
- strides=None, queue=_copy_queue, allocator=None):
685
+ def _new_with_changes(self,
686
+ data: cl.MemoryObjectHolder | cl.SVMPointer | None,
687
+ offset: int | None,
688
+ shape: tuple[int, ...] | None = None,
689
+ dtype: np.dtype[Any] | None = None,
690
+ strides: tuple[int, ...] | None = None,
691
+ queue: cl.CommandQueue | type[_copy_queue] | None = _copy_queue,
692
+ allocator: Allocator | None = None,
693
+ ) -> Self:
653
694
  """
654
695
  :arg data: *None* means allocate a new array.
655
696
  """
@@ -669,6 +710,8 @@ class Array:
669
710
  queue = self.queue
670
711
  if allocator is None:
671
712
  allocator = self.allocator
713
+ if offset is None:
714
+ offset = self.offset
672
715
 
673
716
  # If we're allocating new data, then there's not likely to be
674
717
  # a data dependency. Otherwise, the two arrays should probably
@@ -684,7 +727,7 @@ class Array:
684
727
  events=events,
685
728
  _fast=fast, _context=self.context, _queue=queue, _size=size)
686
729
 
687
- def with_queue(self, queue):
730
+ def with_queue(self, queue: cl.CommandQueue | None):
688
731
  """Return a copy of *self* with the default queue set to *queue*.
689
732
 
690
733
  *None* is allowed as a value for *queue*.
@@ -698,7 +741,10 @@ class Array:
698
741
  return self._new_with_changes(self.base_data, self.offset,
699
742
  queue=queue)
700
743
 
701
- def _get_sizes(self, queue, kernel_specific_max_wg_size=None):
744
+ def _get_sizes(self,
745
+ queue: cl.CommandQueue,
746
+ kernel_specific_max_wg_size: int | None = None
747
+ ) -> tuple[tuple[int, ...], tuple[int, ...]]:
702
748
  if not self.flags.forc:
703
749
  raise NotImplementedError("cannot operate on non-contiguous array")
704
750
  cache_key = (queue.device.int_ptr, self.size, kernel_specific_max_wg_size)
@@ -710,7 +756,11 @@ class Array:
710
756
  _ARRAY_GET_SIZES_CACHE[cache_key] = sizes
711
757
  return sizes
712
758
 
713
- def set(self, ary, queue=None, async_=None, **kwargs):
759
+ def set(self,
760
+ ary: NDArray[Any],
761
+ queue: cl.CommandQueue | None = None,
762
+ async_: bool = False,
763
+ ):
714
764
  """Transfer the contents the :class:`numpy.ndarray` object *ary*
715
765
  onto the device.
716
766
 
@@ -720,32 +770,8 @@ class Array:
720
770
  *async_* is a Boolean indicating whether the function is allowed
721
771
  to return before the transfer completes. To avoid synchronization
722
772
  bugs, this defaults to *False*.
723
-
724
- .. versionchanged:: 2017.2.1
725
-
726
- Python 3.7 makes ``async`` a reserved keyword. On older Pythons,
727
- we will continue to accept *async* as a parameter, however this
728
- should be considered deprecated. *async_* is the new, official
729
- spelling.
730
773
  """
731
774
 
732
- # {{{ handle 'async' deprecation
733
-
734
- async_arg = kwargs.pop("async", None)
735
- if async_arg is not None:
736
- if async_ is not None:
737
- raise TypeError("may not specify both 'async' and 'async_'")
738
- async_ = async_arg
739
-
740
- if async_ is None:
741
- async_ = False
742
-
743
- if kwargs:
744
- raise TypeError("extra keyword arguments specified: %s"
745
- % ", ".join(kwargs))
746
-
747
- # }}}
748
-
749
775
  assert ary.size == self.size
750
776
  assert ary.dtype == self.dtype
751
777
 
@@ -753,36 +779,23 @@ class Array:
753
779
  raise RuntimeError("cannot set from non-contiguous array")
754
780
 
755
781
  if not _equal_strides(ary.strides, self.strides, self.shape):
756
- warn("Setting array from one with different "
757
- "strides/storage order. This will cease to work "
758
- "in 2013.x.",
759
- stacklevel=2)
782
+ raise RuntimeError("Setting array from one with different "
783
+ "strides/storage order.")
760
784
 
761
785
  if self.size:
786
+ queue = queue or self.queue
787
+ assert queue is not None
762
788
  event1 = cl.enqueue_copy(queue or self.queue, self.base_data, ary,
763
789
  dst_offset=self.offset,
764
790
  is_blocking=not async_)
765
791
 
766
792
  self.add_event(event1)
767
793
 
768
- def _get(self, queue=None, ary=None, async_=None, **kwargs):
769
- # {{{ handle 'async' deprecation
770
-
771
- async_arg = kwargs.pop("async", None)
772
- if async_arg is not None:
773
- if async_ is not None:
774
- raise TypeError("may not specify both 'async' and 'async_'")
775
- async_ = async_arg
776
-
777
- if async_ is None:
778
- async_ = False
779
-
780
- if kwargs:
781
- raise TypeError("extra keyword arguments specified: %s"
782
- % ", ".join(kwargs))
783
-
784
- # }}}
785
-
794
+ def _get(self,
795
+ queue: cl.CommandQueue | None = None,
796
+ ary: NDArray[Any] | None = None,
797
+ async_: bool = False,
798
+ ):
786
799
  if ary is None:
787
800
  ary = np.empty(self.shape, self.dtype)
788
801
 
@@ -809,52 +822,36 @@ class Array:
809
822
  "to associate one.")
810
823
 
811
824
  if self.size:
812
- event1 = cl.enqueue_copy(queue, ary, self.base_data,
825
+ assert self.base_data is not None
826
+ event1 = cast("cl.Event", cl.enqueue_copy(queue, ary, self.base_data,
813
827
  src_offset=self.offset,
814
- wait_for=self.events, is_blocking=not async_)
828
+ wait_for=self.events, is_blocking=not async_))
815
829
 
816
830
  self.add_event(event1)
817
831
  else:
818
- event1 = None
832
+ event1 = cl.enqueue_marker(queue, wait_for=self.events)
833
+ if not async_:
834
+ event1.wait()
819
835
 
820
836
  return ary, event1
821
837
 
822
- def get(self, queue=None, ary=None, async_=None, **kwargs):
838
+ def get(self,
839
+ queue: cl.CommandQueue | None = None,
840
+ ary: NDArray[Any] | None = None,
841
+ ) -> NDArray[Any]:
823
842
  """Transfer the contents of *self* into *ary* or a newly allocated
824
843
  :class:`numpy.ndarray`. If *ary* is given, it must have the same
825
844
  shape and dtype.
826
-
827
- .. versionchanged:: 2019.1.2
828
-
829
- Calling with ``async_=True`` was deprecated and replaced by
830
- :meth:`get_async`.
831
- The event returned by :meth:`pyopencl.enqueue_copy` is now stored into
832
- :attr:`events` to ensure data is not modified before the copy is
833
- complete.
834
-
835
- .. versionchanged:: 2015.2
836
-
837
- *ary* with different shape was deprecated.
838
-
839
- .. versionchanged:: 2017.2.1
840
-
841
- Python 3.7 makes ``async`` a reserved keyword. On older Pythons,
842
- we will continue to accept *async* as a parameter, however this
843
- should be considered deprecated. *async_* is the new, official
844
- spelling.
845
845
  """
846
846
 
847
- if async_:
848
- warn("calling pyopencl.Array.get with 'async_=True' is deprecated. "
849
- "Please use pyopencl.Array.get_async for asynchronous "
850
- "device-to-host transfers",
851
- DeprecationWarning, stacklevel=2)
852
-
853
- ary, _event1 = self._get(queue=queue, ary=ary, async_=async_, **kwargs)
847
+ ary, _event1 = self._get(queue=queue, ary=ary)
854
848
 
855
849
  return ary
856
850
 
857
- def get_async(self, queue=None, ary=None, **kwargs):
851
+ def get_async(self,
852
+ queue: cl.CommandQueue | None = None,
853
+ ary: NDArray[Any] | None = None,
854
+ ) -> tuple[NDArray[Any], cl.Event]:
858
855
  """
859
856
  Asynchronous version of :meth:`get` which returns a tuple ``(ary, event)``
860
857
  containing the host array ``ary``
@@ -864,9 +861,9 @@ class Array:
864
861
  .. versionadded:: 2019.1.2
865
862
  """
866
863
 
867
- return self._get(queue=queue, ary=ary, async_=True, **kwargs)
864
+ return self._get(queue=queue, ary=ary, async_=True)
868
865
 
869
- def copy(self, queue=_copy_queue):
866
+ def copy(self, queue: cl.CommandQueue | type[_copy_queue] | None = _copy_queue):
870
867
  """
871
868
  :arg queue: The :class:`~pyopencl.CommandQueue` for the returned array.
872
869
 
@@ -878,20 +875,24 @@ class Array:
878
875
  """
879
876
 
880
877
  if queue is _copy_queue:
881
- queue = self.queue
878
+ queue_san = self.queue
879
+ else:
880
+ queue_san = cast("cl.CommandQueue | None", queue)
882
881
 
883
- result = self._new_like_me(queue=queue)
882
+ result = self._new_like_me(queue=queue_san)
884
883
 
885
884
  # result.queue won't be the same as queue if queue is None.
886
885
  # We force them to be the same here.
887
886
  if result.queue is not queue:
888
- result = result.with_queue(queue)
887
+ result = result.with_queue(queue_san)
889
888
 
890
889
  if not self.flags.forc:
891
890
  raise RuntimeError("cannot copy non-contiguous array")
892
891
 
893
892
  if self.nbytes:
894
- event1 = cl.enqueue_copy(queue or self.queue,
893
+ queue_san = queue_san or self.queue
894
+ assert queue_san is not None
895
+ event1 = cl.enqueue_copy(queue_san,
895
896
  result.base_data, self.base_data,
896
897
  src_offset=self.offset, byte_count=self.nbytes,
897
898
  wait_for=self.events)
@@ -932,7 +933,7 @@ class Array:
932
933
 
933
934
  @staticmethod
934
935
  @elwise_kernel_runner
935
- def _axpbyz(out, afac, a, bfac, b, queue=None):
936
+ def _axpbyz(out, afac, a, bfac, b, queue: cl.CommandQueue | None = None):
936
937
  """Compute ``out = selffac * self + otherfac*other``,
937
938
  where *other* is an array."""
938
939
  a_shape = a.shape
@@ -948,7 +949,7 @@ class Array:
948
949
 
949
950
  @staticmethod
950
951
  @elwise_kernel_runner
951
- def _axpbz(out, a, x, b, queue=None):
952
+ def _axpbz(out, a, x, b, queue: cl.CommandQueue | None = None):
952
953
  """Compute ``z = a * x + b``, where *b* is a scalar."""
953
954
  a = np.array(a)
954
955
  b = np.array(b)
@@ -958,7 +959,7 @@ class Array:
958
959
 
959
960
  @staticmethod
960
961
  @elwise_kernel_runner
961
- def _elwise_multiply(out, a, b, queue=None):
962
+ def _elwise_multiply(out, a, b, queue: cl.CommandQueue | None = None):
962
963
  a_shape = a.shape
963
964
  b_shape = b.shape
964
965
  out_shape = out.shape
@@ -973,7 +974,7 @@ class Array:
973
974
 
974
975
  @staticmethod
975
976
  @elwise_kernel_runner
976
- def _rdiv_scalar(out, ary, other, queue=None):
977
+ def _rdiv_scalar(out, ary, other, queue: cl.CommandQueue | None = None):
977
978
  other = np.array(other)
978
979
  assert out.shape == ary.shape
979
980
  return elementwise.get_rdivide_elwise_kernel(
@@ -981,7 +982,7 @@ class Array:
981
982
 
982
983
  @staticmethod
983
984
  @elwise_kernel_runner
984
- def _div(out, self, other, queue=None):
985
+ def _div(out, self, other, queue: cl.CommandQueue | None = None):
985
986
  """Divides an array by another array."""
986
987
  assert (self.shape == other.shape == out.shape
987
988
  or (self.shape == () and other.shape == out.shape)
@@ -1071,7 +1072,7 @@ class Array:
1071
1072
  return elementwise.get_copy_kernel(
1072
1073
  dest.context, dest.dtype, src.dtype)
1073
1074
 
1074
- def _new_like_me(self, dtype=None, queue=None):
1075
+ def _new_like_me(self, dtype=None, queue: cl.CommandQueue | None = None):
1075
1076
  if dtype is None:
1076
1077
  dtype = self.dtype
1077
1078
  strides = self.strides
@@ -1095,14 +1096,14 @@ class Array:
1095
1096
 
1096
1097
  @staticmethod
1097
1098
  @elwise_kernel_runner
1098
- def _scalar_binop(out, a, b, queue=None, op=None):
1099
+ def _scalar_binop(out, a, b, queue: cl.CommandQueue | None = None, op=None):
1099
1100
  return elementwise.get_array_scalar_binop_kernel(
1100
1101
  out.context, op, out.dtype, a.dtype,
1101
1102
  np.array(b).dtype)
1102
1103
 
1103
1104
  @staticmethod
1104
1105
  @elwise_kernel_runner
1105
- def _array_binop(out, a, b, queue=None, op=None):
1106
+ def _array_binop(out, a, b, queue: cl.CommandQueue | None = None, op=None):
1106
1107
  a_shape = a.shape
1107
1108
  b_shape = b.shape
1108
1109
  out_shape = out.shape
@@ -1116,7 +1117,7 @@ class Array:
1116
1117
 
1117
1118
  @staticmethod
1118
1119
  @elwise_kernel_runner
1119
- def _unop(out, a, queue=None, op=None):
1120
+ def _unop(out, a, queue: cl.CommandQueue | None = None, op=None):
1120
1121
  if out.shape != a.shape:
1121
1122
  raise ValueError("shapes of arguments do not match")
1122
1123
  return elementwise.get_unop_kernel(
@@ -1126,7 +1127,7 @@ class Array:
1126
1127
 
1127
1128
  # {{{ operators
1128
1129
 
1129
- def mul_add(self, selffac, other, otherfac, queue=None):
1130
+ def mul_add(self, selffac, other, otherfac, queue: cl.CommandQueue | None = None):
1130
1131
  """Return ``selffac * self + otherfac * other``.
1131
1132
  """
1132
1133
  queue = queue or self.queue
@@ -1149,7 +1150,7 @@ class Array:
1149
1150
  else:
1150
1151
  raise NotImplementedError
1151
1152
 
1152
- def __add__(self, other):
1153
+ def __add__(self, other) -> Self:
1153
1154
  """Add an array with an array or an array with a scalar."""
1154
1155
 
1155
1156
  if isinstance(other, Array):
@@ -1175,7 +1176,7 @@ class Array:
1175
1176
 
1176
1177
  __radd__ = __add__
1177
1178
 
1178
- def __sub__(self, other):
1179
+ def __sub__(self, other) -> Self:
1179
1180
  """Subtract an array from an array or a scalar from an array."""
1180
1181
 
1181
1182
  if isinstance(other, Array):
@@ -1198,7 +1199,7 @@ class Array:
1198
1199
  else:
1199
1200
  return NotImplemented
1200
1201
 
1201
- def __rsub__(self, other):
1202
+ def __rsub__(self, other) -> Self:
1202
1203
  """Subtracts an array by a scalar or an array::
1203
1204
 
1204
1205
  x = n - self
@@ -1214,7 +1215,7 @@ class Array:
1214
1215
  else:
1215
1216
  return NotImplemented
1216
1217
 
1217
- def __iadd__(self, other):
1218
+ def __iadd__(self, other) -> Self:
1218
1219
  if isinstance(other, Array):
1219
1220
  if other.shape != self.shape and other.shape != ():
1220
1221
  raise NotImplementedError("Broadcasting binary op with shapes:"
@@ -1232,7 +1233,7 @@ class Array:
1232
1233
  else:
1233
1234
  return NotImplemented
1234
1235
 
1235
- def __isub__(self, other):
1236
+ def __isub__(self, other) -> Self:
1236
1237
  if isinstance(other, Array):
1237
1238
  if other.shape != self.shape and other.shape != ():
1238
1239
  raise NotImplementedError("Broadcasting binary op with shapes:"
@@ -1247,15 +1248,15 @@ class Array:
1247
1248
  else:
1248
1249
  return NotImplemented
1249
1250
 
1250
- def __pos__(self):
1251
+ def __pos__(self) -> Self:
1251
1252
  return self
1252
1253
 
1253
- def __neg__(self):
1254
+ def __neg__(self) -> Self:
1254
1255
  result = self._new_like_me()
1255
1256
  result.add_event(self._axpbz(result, -1, self, 0))
1256
1257
  return result
1257
1258
 
1258
- def __mul__(self, other):
1259
+ def __mul__(self, other) -> Self:
1259
1260
  if isinstance(other, Array):
1260
1261
  result = _get_broadcasted_binary_op_result(self, other, self.queue)
1261
1262
  result.add_event(
@@ -1271,7 +1272,7 @@ class Array:
1271
1272
  else:
1272
1273
  return NotImplemented
1273
1274
 
1274
- def __rmul__(self, other):
1275
+ def __rmul__(self, other) -> Self:
1275
1276
  if np.isscalar(other):
1276
1277
  common_dtype = _get_common_dtype(self, other, self.queue)
1277
1278
  result = self._new_like_me(common_dtype)
@@ -1282,7 +1283,7 @@ class Array:
1282
1283
  else:
1283
1284
  return NotImplemented
1284
1285
 
1285
- def __imul__(self, other):
1286
+ def __imul__(self, other) -> Self:
1286
1287
  if isinstance(other, Array):
1287
1288
  if other.shape != self.shape and other.shape != ():
1288
1289
  raise NotImplementedError("Broadcasting binary op with shapes:"
@@ -1297,7 +1298,7 @@ class Array:
1297
1298
  else:
1298
1299
  return NotImplemented
1299
1300
 
1300
- def __div__(self, other):
1301
+ def __div__(self, other) -> Self:
1301
1302
  """Divides an array by an array or a scalar, i.e. ``self / other``.
1302
1303
  """
1303
1304
  if isinstance(other, Array):
@@ -1323,7 +1324,7 @@ class Array:
1323
1324
 
1324
1325
  __truediv__ = __div__
1325
1326
 
1326
- def __rdiv__(self, other):
1327
+ def __rdiv__(self, other) -> Self:
1327
1328
  """Divides an array by a scalar or an array, i.e. ``other / self``.
1328
1329
  """
1329
1330
  common_dtype = _get_truedivide_dtype(self, other, self.queue)
@@ -1342,7 +1343,7 @@ class Array:
1342
1343
 
1343
1344
  __rtruediv__ = __rdiv__
1344
1345
 
1345
- def __itruediv__(self, other):
1346
+ def __itruediv__(self, other) -> Self:
1346
1347
  # raise an error if the result cannot be cast to self
1347
1348
  common_dtype = _get_truedivide_dtype(self, other, self.queue)
1348
1349
  if not np.can_cast(common_dtype, self.dtype.type, "same_kind"):
@@ -1367,7 +1368,7 @@ class Array:
1367
1368
  else:
1368
1369
  return NotImplemented
1369
1370
 
1370
- def __and__(self, other):
1371
+ def __and__(self, other) -> Self:
1371
1372
  common_dtype = _get_common_dtype(self, other, self.queue)
1372
1373
 
1373
1374
  if not np.issubdtype(common_dtype, np.integer):
@@ -1387,7 +1388,7 @@ class Array:
1387
1388
 
1388
1389
  __rand__ = __and__ # commutes
1389
1390
 
1390
- def __or__(self, other):
1391
+ def __or__(self, other) -> Self:
1391
1392
  common_dtype = _get_common_dtype(self, other, self.queue)
1392
1393
 
1393
1394
  if not np.issubdtype(common_dtype, np.integer):
@@ -1408,7 +1409,7 @@ class Array:
1408
1409
 
1409
1410
  __ror__ = __or__ # commutes
1410
1411
 
1411
- def __xor__(self, other):
1412
+ def __xor__(self, other) -> Self:
1412
1413
  common_dtype = _get_common_dtype(self, other, self.queue)
1413
1414
 
1414
1415
  if not np.issubdtype(common_dtype, np.integer):
@@ -1428,7 +1429,7 @@ class Array:
1428
1429
 
1429
1430
  __rxor__ = __xor__ # commutes
1430
1431
 
1431
- def __iand__(self, other):
1432
+ def __iand__(self, other) -> Self:
1432
1433
  common_dtype = _get_common_dtype(self, other, self.queue)
1433
1434
 
1434
1435
  if not np.issubdtype(common_dtype, np.integer):
@@ -1447,7 +1448,7 @@ class Array:
1447
1448
  else:
1448
1449
  return NotImplemented
1449
1450
 
1450
- def __ior__(self, other):
1451
+ def __ior__(self, other) -> Self:
1451
1452
  common_dtype = _get_common_dtype(self, other, self.queue)
1452
1453
 
1453
1454
  if not np.issubdtype(common_dtype, np.integer):
@@ -1466,7 +1467,7 @@ class Array:
1466
1467
  else:
1467
1468
  return NotImplemented
1468
1469
 
1469
- def __ixor__(self, other):
1470
+ def __ixor__(self, other) -> Self:
1470
1471
  common_dtype = _get_common_dtype(self, other, self.queue)
1471
1472
 
1472
1473
  if not np.issubdtype(common_dtype, np.integer):
@@ -1485,7 +1486,9 @@ class Array:
1485
1486
  else:
1486
1487
  return NotImplemented
1487
1488
 
1488
- def _zero_fill(self, queue=None, wait_for=None):
1489
+ def _zero_fill(self,
1490
+ queue: cl.CommandQueue | None = None,
1491
+ wait_for: cl.WaitList = None) -> None:
1489
1492
  queue = queue or self.queue
1490
1493
 
1491
1494
  if not self.size:
@@ -1507,7 +1510,10 @@ class Array:
1507
1510
  zero = np.zeros((), self.dtype)
1508
1511
  self.fill(zero, queue=queue)
1509
1512
 
1510
- def fill(self, value, queue=None, wait_for=None):
1513
+ def fill(self,
1514
+ value: object,
1515
+ queue: cl.CommandQueue | None = None,
1516
+ wait_for: cl.WaitList = None) -> Self:
1511
1517
  """Fill the array with *scalar*.
1512
1518
 
1513
1519
  :returns: *self*.
@@ -1518,14 +1524,14 @@ class Array:
1518
1524
 
1519
1525
  return self
1520
1526
 
1521
- def __len__(self):
1527
+ def __len__(self) -> int:
1522
1528
  """Returns the size of the leading dimension of *self*."""
1523
1529
  if len(self.shape):
1524
1530
  return self.shape[0]
1525
1531
  else:
1526
1532
  return TypeError("len() of unsized object")
1527
1533
 
1528
- def __abs__(self):
1534
+ def __abs__(self) -> Self:
1529
1535
  """Return an ``Array`` of the absolute values of the elements
1530
1536
  of *self*.
1531
1537
  """
@@ -1534,7 +1540,7 @@ class Array:
1534
1540
  result.add_event(self._abs(result, self))
1535
1541
  return result
1536
1542
 
1537
- def __pow__(self, other):
1543
+ def __pow__(self, other) -> Self:
1538
1544
  """Exponentiation by a scalar or elementwise by another
1539
1545
  :class:`Array`.
1540
1546
  """
@@ -1555,7 +1561,7 @@ class Array:
1555
1561
  else:
1556
1562
  return NotImplemented
1557
1563
 
1558
- def __rpow__(self, other):
1564
+ def __rpow__(self, other) -> Self:
1559
1565
  if np.isscalar(other):
1560
1566
  common_dtype = _get_common_dtype(self, other, self.queue)
1561
1567
  result = self._new_like_me(common_dtype)
@@ -1576,7 +1582,7 @@ class Array:
1576
1582
 
1577
1583
  # }}}
1578
1584
 
1579
- def reverse(self, queue=None):
1585
+ def reverse(self, queue: cl.CommandQueue | None = None) -> Self:
1580
1586
  """Return this array in reversed order. The array is treated
1581
1587
  as one-dimensional.
1582
1588
  """
@@ -1585,7 +1591,7 @@ class Array:
1585
1591
  result.add_event(self._reverse(result, self))
1586
1592
  return result
1587
1593
 
1588
- def astype(self, dtype, queue=None):
1594
+ def astype(self, dtype, queue: cl.CommandQueue | None = None):
1589
1595
  """Return a copy of *self*, cast to *dtype*."""
1590
1596
  if dtype == self.dtype:
1591
1597
  return self.copy()
@@ -1596,48 +1602,55 @@ class Array:
1596
1602
 
1597
1603
  # {{{ rich comparisons, any, all
1598
1604
 
1599
- def __bool__(self):
1605
+ def __bool__(self) -> bool:
1600
1606
  if self.shape == ():
1601
1607
  return bool(self.get())
1602
1608
  else:
1603
1609
  raise ValueError("The truth value of an array with "
1604
1610
  "more than one element is ambiguous. Use a.any() or a.all()")
1605
1611
 
1606
- def any(self, queue=None, wait_for=None):
1612
+ def any(self,
1613
+ queue: cl.CommandQueue | None = None,
1614
+ wait_for: cl.WaitList = None
1615
+ ) -> Self:
1607
1616
  from pyopencl.reduction import get_any_kernel
1608
1617
  krnl = get_any_kernel(self.context, self.dtype)
1609
1618
  if wait_for is None:
1610
1619
  wait_for = []
1611
1620
  result, event1 = krnl(self, queue=queue,
1612
- wait_for=wait_for + self.events, return_event=True)
1621
+ wait_for=[*wait_for, *self.events], return_event=True)
1613
1622
  result.add_event(event1)
1614
1623
  return result
1615
1624
 
1616
- def all(self, queue=None, wait_for=None):
1625
+ def all(self,
1626
+ queue: cl.CommandQueue | None = None,
1627
+ wait_for: cl.WaitList = None
1628
+ ) -> Self:
1617
1629
  from pyopencl.reduction import get_all_kernel
1618
1630
  krnl = get_all_kernel(self.context, self.dtype)
1619
1631
  if wait_for is None:
1620
1632
  wait_for = []
1621
1633
  result, event1 = krnl(self, queue=queue,
1622
- wait_for=wait_for + self.events, return_event=True)
1634
+ wait_for=[*wait_for, *self.events], return_event=True)
1623
1635
  result.add_event(event1)
1624
1636
  return result
1625
1637
 
1626
1638
  @staticmethod
1627
1639
  @elwise_kernel_runner
1628
- def _scalar_comparison(out, a, b, queue=None, op=None):
1640
+ def _scalar_comparison(out, a, b, queue: cl.CommandQueue | None = None, op=None):
1629
1641
  return elementwise.get_array_scalar_comparison_kernel(
1630
1642
  out.context, op, a.dtype)
1631
1643
 
1632
1644
  @staticmethod
1633
1645
  @elwise_kernel_runner
1634
- def _array_comparison(out, a, b, queue=None, op=None):
1646
+ def _array_comparison(out, a, b, queue: cl.CommandQueue | None = None, op=None):
1635
1647
  if a.shape != b.shape:
1636
1648
  raise ValueError("shapes of comparison arguments do not match")
1637
1649
  return elementwise.get_array_comparison_kernel(
1638
1650
  out.context, op, a.dtype, b.dtype)
1639
1651
 
1640
- def __eq__(self, other):
1652
+ @override
1653
+ def __eq__(self, other: object) -> Self: # pyright: ignore[reportIncompatibleMethodOverride]
1641
1654
  if isinstance(other, Array):
1642
1655
  result = self._new_like_me(_BOOL_DTYPE)
1643
1656
  result.add_event(
@@ -1651,7 +1664,8 @@ class Array:
1651
1664
  else:
1652
1665
  return NotImplemented
1653
1666
 
1654
- def __ne__(self, other):
1667
+ @override
1668
+ def __ne__(self, other: object) -> Self: # pyright: ignore[reportIncompatibleMethodOverride]
1655
1669
  if isinstance(other, Array):
1656
1670
  result = self._new_like_me(_BOOL_DTYPE)
1657
1671
  result.add_event(
@@ -1665,7 +1679,7 @@ class Array:
1665
1679
  else:
1666
1680
  return NotImplemented
1667
1681
 
1668
- def __le__(self, other):
1682
+ def __le__(self, other) -> Self:
1669
1683
  if isinstance(other, Array):
1670
1684
  result = self._new_like_me(_BOOL_DTYPE)
1671
1685
  result.add_event(
@@ -1678,7 +1692,7 @@ class Array:
1678
1692
  else:
1679
1693
  return NotImplemented
1680
1694
 
1681
- def __ge__(self, other):
1695
+ def __ge__(self, other) -> Self:
1682
1696
  if isinstance(other, Array):
1683
1697
  result = self._new_like_me(_BOOL_DTYPE)
1684
1698
  result.add_event(
@@ -1692,7 +1706,7 @@ class Array:
1692
1706
  else:
1693
1707
  return NotImplemented
1694
1708
 
1695
- def __lt__(self, other):
1709
+ def __lt__(self, other) -> Self:
1696
1710
  if isinstance(other, Array):
1697
1711
  result = self._new_like_me(_BOOL_DTYPE)
1698
1712
  result.add_event(
@@ -1706,7 +1720,7 @@ class Array:
1706
1720
  else:
1707
1721
  return NotImplemented
1708
1722
 
1709
- def __gt__(self, other):
1723
+ def __gt__(self, other) -> Self:
1710
1724
  if isinstance(other, Array):
1711
1725
  result = self._new_like_me(_BOOL_DTYPE)
1712
1726
  result.add_event(
@@ -1725,7 +1739,7 @@ class Array:
1725
1739
  # {{{ complex-valued business
1726
1740
 
1727
1741
  @property
1728
- def real(self):
1742
+ def real(self) -> Self:
1729
1743
  """
1730
1744
  .. versionadded:: 2012.1
1731
1745
  """
@@ -1738,7 +1752,7 @@ class Array:
1738
1752
  return self
1739
1753
 
1740
1754
  @property
1741
- def imag(self):
1755
+ def imag(self) -> Self:
1742
1756
  """
1743
1757
  .. versionadded:: 2012.1
1744
1758
  """
@@ -1750,7 +1764,7 @@ class Array:
1750
1764
  else:
1751
1765
  return zeros_like(self)
1752
1766
 
1753
- def conj(self):
1767
+ def conj(self) -> Self:
1754
1768
  """
1755
1769
  .. versionadded:: 2012.1
1756
1770
  """
@@ -1767,7 +1781,7 @@ class Array:
1767
1781
 
1768
1782
  # {{{ event management
1769
1783
 
1770
- def add_event(self, evt):
1784
+ def add_event(self, evt: cl.Event) -> None:
1771
1785
  """Add *evt* to :attr:`events`. If :attr:`events` is too long, this method
1772
1786
  may implicitly wait for a subset of :attr:`events` and clear them from the
1773
1787
  list.
@@ -1781,7 +1795,7 @@ class Array:
1781
1795
  cl.wait_for_events(wait_events)
1782
1796
  del self.events[:n_wait]
1783
1797
 
1784
- def finish(self):
1798
+ def finish(self) -> None:
1785
1799
  """Wait for the entire contents of :attr:`events`, clear it."""
1786
1800
 
1787
1801
  if self.events:
@@ -1956,13 +1970,13 @@ class Array:
1956
1970
  raise ValueError("new type not compatible with array")
1957
1971
 
1958
1972
  new_shape = (
1959
- self.shape[:min_stride_axis]
1960
- + (self.shape[min_stride_axis] * old_itemsize // itemsize,)
1961
- + self.shape[min_stride_axis+1:])
1973
+ *self.shape[:min_stride_axis],
1974
+ self.shape[min_stride_axis] * old_itemsize // itemsize,
1975
+ *self.shape[min_stride_axis+1:])
1962
1976
  new_strides = (
1963
- self.strides[:min_stride_axis]
1964
- + (self.strides[min_stride_axis] * itemsize // old_itemsize,)
1965
- + self.strides[min_stride_axis+1:])
1977
+ *self.strides[:min_stride_axis],
1978
+ self.strides[min_stride_axis] * itemsize // old_itemsize,
1979
+ *self.strides[min_stride_axis+1:])
1966
1980
 
1967
1981
  return self._new_with_changes(
1968
1982
  self.base_data, self.offset,
@@ -2019,7 +2033,11 @@ class Array:
2019
2033
 
2020
2034
  # }}}
2021
2035
 
2022
- def map_to_host(self, queue=None, flags=None, is_blocking=True, wait_for=None):
2036
+ def map_to_host(self,
2037
+ queue: cl.CommandQueue | None = None,
2038
+ flags=None,
2039
+ is_blocking: bool = True,
2040
+ wait_for: cl.WaitList = None):
2023
2041
  """If *is_blocking*, return a :class:`numpy.ndarray` corresponding to the
2024
2042
  same memory as *self*.
2025
2043
 
@@ -2043,7 +2061,7 @@ class Array:
2043
2061
  ary, evt = cl.enqueue_map_buffer(
2044
2062
  queue or self.queue, self.base_data, flags, self.offset,
2045
2063
  self.shape, self.dtype, strides=self.strides,
2046
- wait_for=wait_for + self.events, is_blocking=is_blocking)
2064
+ wait_for=[*wait_for, *self.events], is_blocking=is_blocking)
2047
2065
 
2048
2066
  if is_blocking:
2049
2067
  return ary
@@ -2150,7 +2168,12 @@ class Array:
2150
2168
  shape=tuple(new_shape),
2151
2169
  strides=tuple(new_strides))
2152
2170
 
2153
- def setitem(self, subscript, value, queue=None, wait_for=None):
2171
+ def setitem(self,
2172
+ subscript: Array | slice | int,
2173
+ value: object,
2174
+ queue: cl.CommandQueue | None = None,
2175
+ wait_for: cl.WaitList = None
2176
+ ):
2154
2177
  """Like :meth:`__setitem__`, but with the ability to specify
2155
2178
  a *queue* and *wait_for*.
2156
2179
 
@@ -2161,10 +2184,11 @@ class Array:
2161
2184
  Added *wait_for*.
2162
2185
  """
2163
2186
 
2164
- queue = queue or self.queue or value.queue
2187
+ queue = queue or self.queue
2188
+ assert queue is not None
2165
2189
  if wait_for is None:
2166
2190
  wait_for = []
2167
- wait_for = wait_for + self.events
2191
+ wait_for = [*wait_for, *self.events]
2168
2192
 
2169
2193
  if isinstance(subscript, Array):
2170
2194
  if subscript.dtype.kind not in ("i", "u"):
@@ -2190,6 +2214,7 @@ class Array:
2190
2214
 
2191
2215
  if isinstance(value, np.ndarray):
2192
2216
  if subarray.shape == value.shape and subarray.strides == value.strides:
2217
+ assert subarray.base_data is not None
2193
2218
  self.add_event(
2194
2219
  cl.enqueue_copy(queue, subarray.base_data,
2195
2220
  value, dst_offset=subarray.offset, wait_for=wait_for))
@@ -2259,8 +2284,13 @@ class _same_as_transfer: # noqa: N801
2259
2284
  pass
2260
2285
 
2261
2286
 
2262
- def to_device(queue, ary, allocator=None, async_=None,
2263
- array_queue=_same_as_transfer, **kwargs):
2287
+ def to_device(
2288
+ queue: cl.CommandQueue,
2289
+ ary: NDArray[Any],
2290
+ allocator: Allocator | None = None,
2291
+ async_: bool = False,
2292
+ array_queue=_same_as_transfer,
2293
+ ) -> Array:
2264
2294
  """Return a :class:`Array` that is an exact copy of the
2265
2295
  :class:`numpy.ndarray` instance *ary*.
2266
2296
 
@@ -2273,32 +2303,8 @@ def to_device(queue, ary, allocator=None, async_=None,
2273
2303
 
2274
2304
  .. versionchanged:: 2015.2
2275
2305
  *array_queue* argument was added.
2276
-
2277
- .. versionchanged:: 2017.2.1
2278
-
2279
- Python 3.7 makes ``async`` a reserved keyword. On older Pythons,
2280
- we will continue to accept *async* as a parameter, however this
2281
- should be considered deprecated. *async_* is the new, official
2282
- spelling.
2283
2306
  """
2284
2307
 
2285
- # {{{ handle 'async' deprecation
2286
-
2287
- async_arg = kwargs.pop("async", None)
2288
- if async_arg is not None:
2289
- if async_ is not None:
2290
- raise TypeError("may not specify both 'async' and 'async_'")
2291
- async_ = async_arg
2292
-
2293
- if async_ is None:
2294
- async_ = False
2295
-
2296
- if kwargs:
2297
- raise TypeError("extra keyword arguments specified: %s"
2298
- % ", ".join(kwargs))
2299
-
2300
- # }}}
2301
-
2302
2308
  if ary.dtype == object:
2303
2309
  raise RuntimeError("to_device does not work on object arrays.")
2304
2310
 
@@ -2316,7 +2322,13 @@ def to_device(queue, ary, allocator=None, async_=None,
2316
2322
  empty = Array
2317
2323
 
2318
2324
 
2319
- def zeros(queue, shape, dtype, order="C", allocator=None):
2325
+ def zeros(
2326
+ queue: cl.CommandQueue,
2327
+ shape: int | tuple[int, ...],
2328
+ dtype: DTypeLike,
2329
+ order: Literal["C"] | Literal["F"] = "C",
2330
+ allocator: Allocator | None = None,
2331
+ ) -> Array:
2320
2332
  """Same as :func:`empty`, but the :class:`Array` is zero-initialized before
2321
2333
  being returned.
2322
2334
 
@@ -2331,7 +2343,11 @@ def zeros(queue, shape, dtype, order="C", allocator=None):
2331
2343
  return result
2332
2344
 
2333
2345
 
2334
- def empty_like(ary, queue=_copy_queue, allocator=None):
2346
+ def empty_like(
2347
+ ary: Array,
2348
+ queue: cl.CommandQueue | type[_copy_queue] | None = _copy_queue,
2349
+ allocator: Allocator | None = None,
2350
+ ):
2335
2351
  """Make a new, uninitialized :class:`Array` having the same properties
2336
2352
  as *other_ary*.
2337
2353
  """
@@ -2352,11 +2368,11 @@ def zeros_like(ary):
2352
2368
 
2353
2369
  @dataclass
2354
2370
  class _ArangeInfo:
2355
- start: Optional[int] = None
2356
- stop: Optional[int] = None
2357
- step: Optional[int] = None
2358
- dtype: Optional["np.dtype"] = None
2359
- allocator: Optional[Any] = None
2371
+ start: int | None = None
2372
+ stop: int | None = None
2373
+ step: int | None = None
2374
+ dtype: np.dtype | None = None
2375
+ allocator: Any | None = None
2360
2376
 
2361
2377
 
2362
2378
  @elwise_kernel_runner
@@ -2463,7 +2479,13 @@ def _take(result, ary, indices):
2463
2479
  result.context, result.dtype, indices.dtype)
2464
2480
 
2465
2481
 
2466
- def take(a, indices, out=None, queue=None, wait_for=None):
2482
+ def take(
2483
+ a: Array,
2484
+ indices: Array,
2485
+ out: Array | None = None,
2486
+ queue: cl.CommandQueue | None = None,
2487
+ wait_for: cl.WaitList = None
2488
+ ) -> Array:
2467
2489
  """Return the :class:`Array` ``[a[indices[0]], ..., a[indices[n]]]``.
2468
2490
  For the moment, *a* must be a type that can be bound to a texture.
2469
2491
  """
@@ -2478,7 +2500,7 @@ def take(a, indices, out=None, queue=None, wait_for=None):
2478
2500
  return out
2479
2501
 
2480
2502
 
2481
- def multi_take(arrays, indices, out=None, queue=None):
2503
+ def multi_take(arrays, indices, out=None, queue: cl.CommandQueue | None = None):
2482
2504
  if not len(arrays):
2483
2505
  return []
2484
2506
 
@@ -2541,7 +2563,7 @@ def multi_take(arrays, indices, out=None, queue=None):
2541
2563
 
2542
2564
 
2543
2565
  def multi_take_put(arrays, dest_indices, src_indices, dest_shape=None,
2544
- out=None, queue=None, src_offsets=None):
2566
+ out=None, queue: cl.CommandQueue | None = None, src_offsets=None):
2545
2567
  if not len(arrays):
2546
2568
  return []
2547
2569
 
@@ -2623,8 +2645,14 @@ def multi_take_put(arrays, dest_indices, src_indices, dest_shape=None,
2623
2645
  return out
2624
2646
 
2625
2647
 
2626
- def multi_put(arrays, dest_indices, dest_shape=None, out=None, queue=None,
2627
- wait_for=None):
2648
+ def multi_put(
2649
+ arrays,
2650
+ dest_indices: Array,
2651
+ dest_shape=None,
2652
+ out=None,
2653
+ queue: cl.CommandQueue | None = None,
2654
+ wait_for: cl.WaitList = None
2655
+ ):
2628
2656
  if not len(arrays):
2629
2657
  return []
2630
2658
 
@@ -2633,9 +2661,10 @@ def multi_put(arrays, dest_indices, dest_shape=None, out=None, queue=None,
2633
2661
  a_allocator = arrays[0].allocator
2634
2662
  context = dest_indices.context
2635
2663
  queue = queue or dest_indices.queue
2664
+ assert queue is not None
2636
2665
  if wait_for is None:
2637
2666
  wait_for = []
2638
- wait_for = wait_for + dest_indices.events
2667
+ wait_for = [*wait_for, *dest_indices.events]
2639
2668
 
2640
2669
  vec_count = len(arrays)
2641
2670
 
@@ -2702,7 +2731,7 @@ def multi_put(arrays, dest_indices, dest_shape=None, out=None, queue=None,
2702
2731
  return out
2703
2732
 
2704
2733
 
2705
- def concatenate(arrays, axis=0, queue=None, allocator=None):
2734
+ def concatenate(arrays, axis=0, queue: cl.CommandQueue | None = None, allocator=None):
2706
2735
  """
2707
2736
  .. versionadded:: 2013.1
2708
2737
 
@@ -2759,9 +2788,9 @@ def concatenate(arrays, axis=0, queue=None, allocator=None):
2759
2788
  for ary in arrays:
2760
2789
  my_len = ary.shape[axis]
2761
2790
  result.setitem(
2762
- full_slice[:axis]
2763
- + (slice(base_idx, base_idx+my_len),)
2764
- + full_slice[axis+1:],
2791
+ (*full_slice[:axis],
2792
+ slice(base_idx, base_idx+my_len),
2793
+ *full_slice[axis+1:]),
2765
2794
  ary)
2766
2795
 
2767
2796
  base_idx += my_len
@@ -2774,7 +2803,7 @@ def _diff(result, array):
2774
2803
  return elementwise.get_diff_kernel(array.context, array.dtype)
2775
2804
 
2776
2805
 
2777
- def diff(array, queue=None, allocator=None):
2806
+ def diff(array, queue: cl.CommandQueue | None = None, allocator=None):
2778
2807
  """
2779
2808
  .. versionadded:: 2013.2
2780
2809
  """
@@ -2793,7 +2822,7 @@ def diff(array, queue=None, allocator=None):
2793
2822
  return result
2794
2823
 
2795
2824
 
2796
- def hstack(arrays, queue=None):
2825
+ def hstack(arrays, queue: cl.CommandQueue | None = None):
2797
2826
  if len(arrays) == 0:
2798
2827
  raise ValueError("need at least one array to hstack")
2799
2828
 
@@ -2828,7 +2857,7 @@ def hstack(arrays, queue=None):
2828
2857
  return result
2829
2858
 
2830
2859
 
2831
- def stack(arrays, axis=0, queue=None):
2860
+ def stack(arrays, axis=0, queue: cl.CommandQueue | None = None):
2832
2861
  """
2833
2862
  Join a sequence of arrays along a new axis.
2834
2863
 
@@ -2867,7 +2896,7 @@ def stack(arrays, axis=0, queue=None):
2867
2896
  # pyopencl.Array.__setitem__ does not support non-contiguous assignments
2868
2897
  raise NotImplementedError
2869
2898
 
2870
- result_shape = input_shape[:axis] + (len(arrays),) + input_shape[axis:]
2899
+ result_shape = (*input_shape[:axis], len(arrays), *input_shape[axis:])
2871
2900
 
2872
2901
  if __debug__:
2873
2902
  if builtins.any(type(ary) != type(arrays[0]) # noqa: E721
@@ -2931,7 +2960,12 @@ def _if_positive(result, criterion, then_, else_):
2931
2960
  )
2932
2961
 
2933
2962
 
2934
- def if_positive(criterion, then_, else_, out=None, queue=None):
2963
+ def if_positive(
2964
+ criterion,
2965
+ then_,
2966
+ else_,
2967
+ out=None,
2968
+ queue: cl.CommandQueue | None = None):
2935
2969
  """Return an array like *then_*, which, for the element at index *i*,
2936
2970
  contains *then_[i]* if *criterion[i]>0*, else *else_[i]*.
2937
2971
  """
@@ -3015,7 +3049,7 @@ def _minimum_maximum_backend(out, a, b, minmax):
3015
3049
  elementwise.get_argument_kind(b))
3016
3050
 
3017
3051
 
3018
- def maximum(a, b, out=None, queue=None):
3052
+ def maximum(a, b, out=None, queue: cl.CommandQueue | None = None):
3019
3053
  """Return the elementwise maximum of *a* and *b*."""
3020
3054
 
3021
3055
  a_is_scalar = np.isscalar(a)
@@ -3042,7 +3076,7 @@ def maximum(a, b, out=None, queue=None):
3042
3076
  return out
3043
3077
 
3044
3078
 
3045
- def minimum(a, b, out=None, queue=None):
3079
+ def minimum(a, b, out=None, queue: cl.CommandQueue | None = None):
3046
3080
  """Return the elementwise minimum of *a* and *b*."""
3047
3081
  a_is_scalar = np.isscalar(a)
3048
3082
  b_is_scalar = np.isscalar(b)
@@ -3072,7 +3106,7 @@ def minimum(a, b, out=None, queue=None):
3072
3106
 
3073
3107
  # {{{ logical ops
3074
3108
 
3075
- def _logical_op(x1, x2, out, operator, queue=None):
3109
+ def _logical_op(x1, x2, out, operator, queue: cl.CommandQueue | None = None):
3076
3110
  # NOTE: Copied from pycuda.gpuarray
3077
3111
  assert operator in ["&&", "||"]
3078
3112
 
@@ -3132,21 +3166,21 @@ def _logical_op(x1, x2, out, operator, queue=None):
3132
3166
  return out
3133
3167
 
3134
3168
 
3135
- def logical_and(x1, x2, /, out=None, queue=None):
3169
+ def logical_and(x1, x2, /, out=None, queue: cl.CommandQueue | None = None):
3136
3170
  """
3137
3171
  Returns the element-wise logical AND of *x1* and *x2*.
3138
3172
  """
3139
3173
  return _logical_op(x1, x2, out, "&&", queue=queue)
3140
3174
 
3141
3175
 
3142
- def logical_or(x1, x2, /, out=None, queue=None):
3176
+ def logical_or(x1, x2, /, out=None, queue: cl.CommandQueue | None = None):
3143
3177
  """
3144
3178
  Returns the element-wise logical OR of *x1* and *x2*.
3145
3179
  """
3146
3180
  return _logical_op(x1, x2, out, "||", queue=queue)
3147
3181
 
3148
3182
 
3149
- def logical_not(x, /, out=None, queue=None):
3183
+ def logical_not(x, /, out=None, queue: cl.CommandQueue | None = None):
3150
3184
  """
3151
3185
  Returns the element-wise logical NOT of *x*.
3152
3186
  """
@@ -3168,11 +3202,16 @@ def logical_not(x, /, out=None, queue=None):
3168
3202
 
3169
3203
  # {{{ reductions
3170
3204
 
3171
- def sum(a, dtype=None, queue=None, slice=None, initial=np._NoValue):
3205
+ def sum(
3206
+ a,
3207
+ dtype=None,
3208
+ queue: cl.CommandQueue | None = None,
3209
+ slice=None,
3210
+ initial=_NoValue):
3172
3211
  """
3173
3212
  .. versionadded:: 2011.1
3174
3213
  """
3175
- if initial is not np._NoValue and not isinstance(initial, SCALAR_CLASSES):
3214
+ if initial is not _NoValue and not isinstance(initial, SCALAR_CLASSES):
3176
3215
  raise ValueError("'initial' is not a scalar")
3177
3216
 
3178
3217
  if dtype is not None:
@@ -3185,27 +3224,27 @@ def sum(a, dtype=None, queue=None, slice=None, initial=np._NoValue):
3185
3224
  result.add_event(event1)
3186
3225
 
3187
3226
  # NOTE: neutral element in `get_sum_kernel` is 0 by default
3188
- if initial is not np._NoValue:
3227
+ if initial is not _NoValue:
3189
3228
  result += a.dtype.type(initial)
3190
3229
 
3191
3230
  return result
3192
3231
 
3193
3232
 
3194
- def any(a, queue=None, wait_for=None):
3233
+ def any(a, queue: cl.CommandQueue | None = None, wait_for: cl.WaitList = None):
3195
3234
  if len(a) == 0:
3196
3235
  return _BOOL_DTYPE.type(False)
3197
3236
 
3198
3237
  return a.any(queue=queue, wait_for=wait_for)
3199
3238
 
3200
3239
 
3201
- def all(a, queue=None, wait_for=None):
3240
+ def all(a, queue: cl.CommandQueue | None = None, wait_for: cl.WaitList = None):
3202
3241
  if len(a) == 0:
3203
3242
  return _BOOL_DTYPE.type(True)
3204
3243
 
3205
3244
  return a.all(queue=queue, wait_for=wait_for)
3206
3245
 
3207
3246
 
3208
- def dot(a, b, dtype=None, queue=None, slice=None):
3247
+ def dot(a, b, dtype=None, queue: cl.CommandQueue | None = None, slice=None):
3209
3248
  """
3210
3249
  .. versionadded:: 2011.1
3211
3250
  """
@@ -3222,7 +3261,7 @@ def dot(a, b, dtype=None, queue=None, slice=None):
3222
3261
  return result
3223
3262
 
3224
3263
 
3225
- def vdot(a, b, dtype=None, queue=None, slice=None):
3264
+ def vdot(a, b, dtype=None, queue: cl.CommandQueue | None = None, slice=None):
3226
3265
  """Like :func:`numpy.vdot`.
3227
3266
 
3228
3267
  .. versionadded:: 2013.1
@@ -3241,7 +3280,13 @@ def vdot(a, b, dtype=None, queue=None, slice=None):
3241
3280
  return result
3242
3281
 
3243
3282
 
3244
- def subset_dot(subset, a, b, dtype=None, queue=None, slice=None):
3283
+ def subset_dot(
3284
+ subset,
3285
+ a,
3286
+ b,
3287
+ dtype=None,
3288
+ queue: cl.CommandQueue | None = None,
3289
+ slice=None):
3245
3290
  """
3246
3291
  .. versionadded:: 2011.1
3247
3292
  """
@@ -3260,19 +3305,19 @@ def subset_dot(subset, a, b, dtype=None, queue=None, slice=None):
3260
3305
 
3261
3306
 
3262
3307
  def _make_minmax_kernel(what):
3263
- def f(a, queue=None, initial=np._NoValue):
3308
+ def f(a, queue: cl.CommandQueue | None = None, initial=_NoValue):
3264
3309
  if isinstance(a, SCALAR_CLASSES):
3265
3310
  return np.array(a).dtype.type(a)
3266
3311
 
3267
3312
  if len(a) == 0:
3268
- if initial is np._NoValue:
3313
+ if initial is _NoValue:
3269
3314
  raise ValueError(
3270
3315
  f"zero-size array to reduction '{what}' "
3271
3316
  "which has no identity")
3272
3317
  else:
3273
3318
  return initial
3274
3319
 
3275
- if initial is not np._NoValue and not isinstance(initial, SCALAR_CLASSES):
3320
+ if initial is not _NoValue and not isinstance(initial, SCALAR_CLASSES):
3276
3321
  raise ValueError("'initial' is not a scalar")
3277
3322
 
3278
3323
  from pyopencl.reduction import get_minmax_kernel
@@ -3281,7 +3326,7 @@ def _make_minmax_kernel(what):
3281
3326
  return_event=True)
3282
3327
  result.add_event(event1)
3283
3328
 
3284
- if initial is not np._NoValue:
3329
+ if initial is not _NoValue:
3285
3330
  initial = a.dtype.type(initial)
3286
3331
  if what == "min":
3287
3332
  result = minimum(result, initial, queue=queue)
@@ -3309,7 +3354,7 @@ max.__doc__ = """
3309
3354
 
3310
3355
 
3311
3356
  def _make_subset_minmax_kernel(what):
3312
- def f(subset, a, queue=None, slice=None):
3357
+ def f(subset, a, queue: cl.CommandQueue | None = None, slice=None):
3313
3358
  from pyopencl.reduction import get_subset_minmax_kernel
3314
3359
  krnl = get_subset_minmax_kernel(a.context, what, a.dtype, subset.dtype)
3315
3360
  result, event1 = krnl(subset, a, queue=queue, slice=slice,
@@ -3329,8 +3374,8 @@ subset_max.__doc__ = """.. versionadded:: 2011.1"""
3329
3374
 
3330
3375
  # {{{ scans
3331
3376
 
3332
- def cumsum(a, output_dtype=None, queue=None,
3333
- wait_for=None, return_event=False):
3377
+ def cumsum(a, output_dtype=None, queue: cl.CommandQueue | None = None,
3378
+ wait_for: cl.WaitList = None, return_event=False):
3334
3379
  # undocumented for now
3335
3380
 
3336
3381
  """