Skip to content

Commit 3b13c9b

Browse files
authored
Merge pull request #495 from numpy/fix-ndarray.__add__
2 parents b22f51c + c1bbdaf commit 3b13c9b

File tree

8 files changed

+858
-223
lines changed

8 files changed

+858
-223
lines changed

src/_numtype/@test/test_nep50.pyi

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ i1_from_c16: CanCast0D[np.int8] = c16 # type: ignore[assignment] # pyright: ig
7575
i1_from_cld: CanCast0D[np.int8] = cld # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
7676

7777
i1_to_b1: CanCast0D[Any, np.int8] = b1 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
78-
i1_to_i1: CanCast0D[Any, np.int8] = i1
78+
i1_to_i1: CanCast0D[Any, np.int8] = i1 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
7979
i1_to_u1: CanCast0D[Any, np.int8] = u1 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
8080
i1_to_i2: CanCast0D[Any, np.int8] = i2
8181
i1_to_u2: CanCast0D[Any, np.int8] = u2 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
@@ -110,7 +110,7 @@ u1_from_cld: CanCast0D[np.uint8] = cld # type: ignore[assignment] # pyright: i
110110

111111
u1_to_b1: CanCast0D[Any, np.uint8] = b1 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
112112
u1_to_i1: CanCast0D[Any, np.uint8] = i1 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
113-
u1_to_u1: CanCast0D[Any, np.uint8] = u1
113+
u1_to_u1: CanCast0D[Any, np.uint8] = u1 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
114114
u1_to_i2: CanCast0D[Any, np.uint8] = i2
115115
u1_to_u2: CanCast0D[Any, np.uint8] = u2
116116
u1_to_i4: CanCast0D[Any, np.uint8] = i4
@@ -145,7 +145,7 @@ i2_from_cld: CanCast0D[np.int16] = cld # type: ignore[assignment] # pyright: i
145145
i2_to_b1: CanCast0D[Any, np.int16] = b1 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
146146
i2_to_i1: CanCast0D[Any, np.int16] = i1 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
147147
i2_to_u1: CanCast0D[Any, np.int16] = u1 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
148-
i2_to_i2: CanCast0D[Any, np.int16] = i2
148+
i2_to_i2: CanCast0D[Any, np.int16] = i2 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
149149
i2_to_u2: CanCast0D[Any, np.int16] = u2 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
150150
i2_to_i4: CanCast0D[Any, np.int16] = i4
151151
i2_to_u4: CanCast0D[Any, np.int16] = u4 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
@@ -180,7 +180,7 @@ u2_to_b1: CanCast0D[Any, np.uint16] = b1 # type: ignore[assignment] # pyright:
180180
u2_to_i1: CanCast0D[Any, np.uint16] = i1 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
181181
u2_to_u1: CanCast0D[Any, np.uint16] = u1 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
182182
u2_to_i2: CanCast0D[Any, np.uint16] = i2 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
183-
u2_to_u2: CanCast0D[Any, np.uint16] = u2
183+
u2_to_u2: CanCast0D[Any, np.uint16] = u2 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
184184
u2_to_i4: CanCast0D[Any, np.uint16] = i4
185185
u2_to_u4: CanCast0D[Any, np.uint16] = u4
186186
u2_to_i8: CanCast0D[Any, np.uint16] = i8
@@ -215,7 +215,7 @@ i4_to_i1: CanCast0D[Any, np.int32] = i1 # type: ignore[assignment] # pyright:
215215
i4_to_u1: CanCast0D[Any, np.int32] = u1 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
216216
i4_to_i2: CanCast0D[Any, np.int32] = i2 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
217217
i4_to_u2: CanCast0D[Any, np.int32] = u2 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
218-
i4_to_i4: CanCast0D[Any, np.int32] = i4
218+
i4_to_i4: CanCast0D[Any, np.int32] = i4 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
219219
i4_to_u4: CanCast0D[Any, np.int32] = u4 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
220220
i4_to_i8: CanCast0D[Any, np.int32] = i8
221221
i4_to_u8: CanCast0D[Any, np.int32] = u8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
@@ -250,7 +250,7 @@ u4_to_u1: CanCast0D[Any, np.uint32] = u1 # type: ignore[assignment] # pyright:
250250
u4_to_i2: CanCast0D[Any, np.uint32] = i2 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
251251
u4_to_u2: CanCast0D[Any, np.uint32] = u2 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
252252
u4_to_i4: CanCast0D[Any, np.uint32] = i4 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
253-
u4_to_u4: CanCast0D[Any, np.uint32] = u4
253+
u4_to_u4: CanCast0D[Any, np.uint32] = u4 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
254254
u4_to_i8: CanCast0D[Any, np.uint32] = i8
255255
u4_to_u8: CanCast0D[Any, np.uint32] = u8
256256
u4_to_f2: CanCast0D[Any, np.uint32] = f2 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
@@ -285,7 +285,7 @@ i8_to_i2: CanCast0D[Any, np.int64] = i2 # type: ignore[assignment] # pyright:
285285
i8_to_u2: CanCast0D[Any, np.int64] = u2 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
286286
i8_to_i4: CanCast0D[Any, np.int64] = i4 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
287287
i8_to_u4: CanCast0D[Any, np.int64] = u4 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
288-
i8_to_i8: CanCast0D[Any, np.int64] = i8
288+
i8_to_i8: CanCast0D[Any, np.int64] = i8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
289289
i8_to_u8: CanCast0D[Any, np.int64] = u8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
290290
i8_to_f2: CanCast0D[Any, np.int64] = f2 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
291291
i8_to_f4: CanCast0D[Any, np.int64] = f4 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
@@ -320,7 +320,7 @@ u8_to_u2: CanCast0D[Any, np.uint64] = u2 # type: ignore[assignment] # pyright:
320320
u8_to_i4: CanCast0D[Any, np.uint64] = i4 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
321321
u8_to_u4: CanCast0D[Any, np.uint64] = u4 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
322322
u8_to_i8: CanCast0D[Any, np.uint64] = i8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
323-
u8_to_u8: CanCast0D[Any, np.uint64] = u8
323+
u8_to_u8: CanCast0D[Any, np.uint64] = u8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
324324
u8_to_f2: CanCast0D[Any, np.uint64] = f2 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
325325
u8_to_f4: CanCast0D[Any, np.uint64] = f4 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
326326
u8_to_f8: CanCast0D[Any, np.uint64] = f8
@@ -355,7 +355,7 @@ f2_to_i4: CanCast0D[Any, np.float16] = i4 # type: ignore[assignment] # pyright
355355
f2_to_u4: CanCast0D[Any, np.float16] = u4 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
356356
f2_to_i8: CanCast0D[Any, np.float16] = i8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
357357
f2_to_u8: CanCast0D[Any, np.float16] = u8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
358-
f2_to_f2: CanCast0D[Any, np.float16] = f2
358+
f2_to_f2: CanCast0D[Any, np.float16] = f2 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
359359
f2_to_f4: CanCast0D[Any, np.float16] = f4
360360
f2_to_f8: CanCast0D[Any, np.float16] = f8
361361
f2_to_ld: CanCast0D[Any, np.float16] = ld
@@ -390,7 +390,7 @@ f4_to_u4: CanCast0D[Any, np.float32] = u4 # type: ignore[assignment] # pyright
390390
f4_to_i8: CanCast0D[Any, np.float32] = i8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
391391
f4_to_u8: CanCast0D[Any, np.float32] = u8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
392392
f4_to_f2: CanCast0D[Any, np.float32] = f2 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
393-
f4_to_f4: CanCast0D[Any, np.float32] = f4
393+
f4_to_f4: CanCast0D[Any, np.float32] = f4 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
394394
f4_to_f8: CanCast0D[Any, np.float32] = f8
395395
f4_to_ld: CanCast0D[Any, np.float32] = ld
396396
f4_to_c8: CanCast0D[Any, np.float32] = c8
@@ -425,7 +425,7 @@ f8_to_i8: CanCast0D[Any, np.float64] = i8 # type: ignore[assignment] # pyright
425425
f8_to_u8: CanCast0D[Any, np.float64] = u8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
426426
f8_to_f2: CanCast0D[Any, np.float64] = f2 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
427427
f8_to_f4: CanCast0D[Any, np.float64] = f4 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
428-
f8_to_f8: CanCast0D[Any, np.float64] = f8
428+
f8_to_f8: CanCast0D[Any, np.float64] = f8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
429429
f8_to_ld: CanCast0D[Any, np.float64] = ld
430430
f8_to_c8: CanCast0D[Any, np.float64] = c8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
431431
f8_to_c16: CanCast0D[Any, np.float64] = c16
@@ -460,7 +460,7 @@ ld_to_u8: CanCast0D[Any, np.longdouble] = u8 # type: ignore[assignment] # pyri
460460
ld_to_f2: CanCast0D[Any, np.longdouble] = f2 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
461461
ld_to_f4: CanCast0D[Any, np.longdouble] = f4 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
462462
ld_to_f8: CanCast0D[Any, np.longdouble] = f8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
463-
ld_to_ld: CanCast0D[Any, np.longdouble] = ld
463+
ld_to_ld: CanCast0D[Any, np.longdouble] = ld # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
464464
ld_to_c8: CanCast0D[Any, np.longdouble] = c8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
465465
ld_to_c16: CanCast0D[Any, np.longdouble] = c16 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
466466
ld_to_cld: CanCast0D[Any, np.longdouble] = cld
@@ -495,7 +495,7 @@ c8_to_f2: CanCast0D[Any, np.complex64] = f2 # type: ignore[assignment] # pyrig
495495
c8_to_f4: CanCast0D[Any, np.complex64] = f4 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
496496
c8_to_f8: CanCast0D[Any, np.complex64] = f8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
497497
c8_to_ld: CanCast0D[Any, np.complex64] = ld # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
498-
c8_to_c8: CanCast0D[Any, np.complex64] = c8
498+
c8_to_c8: CanCast0D[Any, np.complex64] = c8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
499499
c8_to_c16: CanCast0D[Any, np.complex64] = c16
500500
c8_to_cld: CanCast0D[Any, np.complex64] = cld
501501

@@ -530,7 +530,7 @@ c16_to_f4: CanCast0D[Any, np.complex128] = f4 # type: ignore[assignment] # pyr
530530
c16_to_f8: CanCast0D[Any, np.complex128] = f8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
531531
c16_to_ld: CanCast0D[Any, np.complex128] = ld # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
532532
c16_to_c8: CanCast0D[Any, np.complex128] = c8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
533-
c16_to_c16: CanCast0D[Any, np.complex128] = c16
533+
c16_to_c16: CanCast0D[Any, np.complex128] = c16 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
534534
c16_to_cld: CanCast0D[Any, np.complex128] = cld
535535

536536
cld_from_b1: CanCast0D[np.clongdouble] = b1
@@ -565,4 +565,4 @@ cld_to_f8: CanCast0D[Any, np.clongdouble] = f8 # type: ignore[assignment] # py
565565
cld_to_ld: CanCast0D[Any, np.clongdouble] = ld # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
566566
cld_to_c8: CanCast0D[Any, np.clongdouble] = c8 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
567567
cld_to_c16: CanCast0D[Any, np.clongdouble] = c16 # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
568-
cld_to_cld: CanCast0D[Any, np.clongdouble] = cld
568+
cld_to_cld: CanCast0D[Any, np.clongdouble] = cld # type: ignore[assignment] # pyright: ignore[reportAssignmentType]

src/_numtype/__init__.pyi

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import decimal
66
import fractions
77
from collections.abc import Sequence
88
from typing import Any, TypeAlias, type_check_only
9-
from typing_extensions import Protocol, TypeAliasType, TypeVar, Unpack
9+
from typing_extensions import Never, Protocol, TypeAliasType, TypeVar, Unpack
1010

1111
import numpy as np
1212
from numpy._typing import _NestedSequence
@@ -48,9 +48,11 @@ from ._just import (
4848
JustStr as JustStr,
4949
)
5050
from ._nep50 import (
51-
CanCast as CanCast,
5251
CanCast0D as CanCast0D,
5352
CanCastND as CanCastND,
53+
CanNEP50 as CanNEP50,
54+
MatchND as MatchND,
55+
PromoteWith as PromoteWith,
5456
)
5557
from ._scalar import (
5658
inexact32 as inexact32,
@@ -97,17 +99,16 @@ from ._scalar_co import (
9799
# Type parameters
98100

99101
_T = TypeVar("_T")
102+
_ShapeT = TypeVar("_ShapeT", bound=tuple[int, ...], default=tuple[int, ...])
100103
_ShapeT_co = TypeVar("_ShapeT_co", bound=tuple[int, ...], covariant=True)
101104
_ScalarT = TypeVar("_ScalarT", bound=np.generic)
102105
_ScalarT_co = TypeVar("_ScalarT_co", bound=np.generic, covariant=True)
103106
_ScalarT0 = TypeVar("_ScalarT0", bound=np.generic, default=Any)
107+
_NaT = TypeVar("_NaT", default=Never)
108+
_NaT0 = TypeVar("_NaT0", default=Any)
109+
_NaT_co = TypeVar("_NaT_co", covariant=True)
104110
_ToT = TypeVar("_ToT")
105111

106-
###
107-
# Type constraints (bijective type mappings)
108-
109-
_ShapeT = TypeVar("_ShapeT", bound=tuple[int, ...], default=tuple[int, ...])
110-
111112
###
112113
# Protocols
113114

@@ -141,6 +142,10 @@ class CanLenArray(Protocol[_ScalarT_co, _ShapeT_co]):
141142
def __len__(self, /) -> int: ...
142143
def __array__(self, /) -> np.ndarray[_ShapeT_co, np.dtype[_ScalarT_co]]: ...
143144

145+
@type_check_only
146+
class _CanStringArray(Protocol[_ShapeT_co, _NaT_co]):
147+
def __array__(self, /) -> np.ndarray[_ShapeT_co, np.dtypes.StringDType[_NaT_co]]: ...
148+
144149
###
145150
# Shape aliases
146151

@@ -158,6 +163,7 @@ Sequence2D: TypeAlias = Sequence[Sequence[_T]]
158163
Sequence3D: TypeAlias = Sequence[Sequence[Sequence[_T]]]
159164

160165
# nested sequences with at least k dims, e.g. `2nd` denotes a dimensionality in the interval [2, n]
166+
SequenceND: TypeAlias = _T | _NestedSequence[_T]
161167
Sequence1ND: TypeAlias = _NestedSequence[_T]
162168
Sequence2ND: TypeAlias = Sequence[_NestedSequence[_T]]
163169
Sequence3ND: TypeAlias = Sequence[Sequence[_NestedSequence[_T]]]
@@ -180,6 +186,37 @@ MArray3D = TypeAliasType("MArray3D", np.ma.MaskedArray[tuple[int, int, int], np.
180186

181187
Matrix = TypeAliasType("Matrix", np.matrix[tuple[int, int], np.dtype[_ScalarT0]], type_params=(_ScalarT0,))
182188

189+
StringArray = TypeAliasType(
190+
"StringArray",
191+
np.ndarray[_ShapeT, np.dtypes.StringDType[_NaT]],
192+
type_params=(_ShapeT, _NaT),
193+
)
194+
StringArray0D = TypeAliasType(
195+
"StringArray0D",
196+
np.ndarray[tuple[()], np.dtypes.StringDType[_NaT]],
197+
type_params=(_NaT,),
198+
)
199+
StringArray1D = TypeAliasType(
200+
"StringArray1D",
201+
np.ndarray[tuple[int], np.dtypes.StringDType[_NaT]],
202+
type_params=(_NaT,),
203+
)
204+
StringArray2D = TypeAliasType(
205+
"StringArray2D",
206+
np.ndarray[tuple[int, int], np.dtypes.StringDType[_NaT]],
207+
type_params=(_NaT,),
208+
)
209+
StringArray3D = TypeAliasType(
210+
"StringArray3D",
211+
np.ndarray[tuple[int, int, int], np.dtypes.StringDType[_NaT]],
212+
type_params=(_NaT,),
213+
)
214+
StringArrayND = TypeAliasType(
215+
"StringArrayND",
216+
np.ndarray[tuple[int, ...], np.dtypes.StringDType[_NaT]],
217+
type_params=(_NaT,),
218+
)
219+
183220
###
184221
# helper aliases
185222

@@ -192,8 +229,8 @@ _PyObject: TypeAlias = decimal.Decimal | fractions.Fraction
192229
_PyScalar: TypeAlias = complex | _PyCharacter | _PyObject
193230

194231
_ToArray2_0d: TypeAlias = CanArray0D[_ScalarT] | _ToT
195-
_ToArray_nd: TypeAlias = CanArrayND[_ScalarT] | Sequence1ND[CanArrayND[_ScalarT]]
196-
_ToArray2_nd: TypeAlias = CanArrayND[_ScalarT] | _ToT | Sequence1ND[_ToT | CanArrayND[_ScalarT]]
232+
_ToArray_nd: TypeAlias = SequenceND[CanArrayND[_ScalarT]]
233+
_ToArray2_nd: TypeAlias = SequenceND[CanArrayND[_ScalarT] | _ToT]
197234

198235
# don't require matching shape-types by default
199236
_ToArray_1d: TypeAlias = CanLenArrayND[_ScalarT] | Sequence[CanArray0D[_ScalarT]]
@@ -636,6 +673,15 @@ ToObject_1nd = TypeAliasType("ToObject_1nd", _ToArray2_1nd[np.object_, _PyObject
636673
ToObject_2nd = TypeAliasType("ToObject_2nd", _ToArray2_2nd[np.object_, _PyObject])
637674
ToObject_3nd = TypeAliasType("ToObject_3nd", _ToArray2_3nd[np.object_, _PyObject])
638675

676+
# StringDType
677+
ToString_nd = TypeAliasType("ToString_nd", _CanStringArray[AtLeast0D, _NaT0], type_params=(_NaT0,))
678+
ToString_1ds = TypeAliasType("ToString_1ds", _CanStringArray[tuple[int], _NaT0], type_params=(_NaT0,))
679+
ToString_2ds = TypeAliasType("ToString_2ds", _CanStringArray[tuple[int, int], _NaT0], type_params=(_NaT0,))
680+
ToString_3ds = TypeAliasType("ToString_3ds", _CanStringArray[tuple[int, int, int], _NaT0], type_params=(_NaT0,))
681+
ToString_1nd = TypeAliasType("ToString_1nd", _CanStringArray[AtLeast1D, _NaT0], type_params=(_NaT0,))
682+
ToString_2nd = TypeAliasType("ToString_2nd", _CanStringArray[AtLeast2D, _NaT0], type_params=(_NaT0,))
683+
ToString_3nd = TypeAliasType("ToString_3nd", _CanStringArray[AtLeast3D, _NaT0], type_params=(_NaT0,))
684+
639685
# any scalar
640686
ToGeneric_nd = TypeAliasType("ToGeneric_nd", _ToArray2_nd[np.generic, _PyScalar])
641687
ToGeneric_0d = TypeAliasType("ToGeneric_0d", _ToArray2_0d[np.generic, _PyScalar])

src/_numtype/_nep50.pyi

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,37 +3,70 @@
33
# https://numpy.org/neps/nep-0050-scalar-promotion.html
44

55
from typing import Any, Protocol, type_check_only
6-
from typing_extensions import TypeVar
6+
from typing_extensions import TypeAliasType, TypeVar
77

88
import numpy as np
99

10-
__all__ = ["CanCast", "CanCast0D", "CanCastND"]
10+
__all__ = ["CanCast0D", "CanCastND", "CanNEP50", "MatchND", "PromoteWith"]
1111

1212
_T_co = TypeVar("_T_co", covariant=True)
13+
_BelowT_contra = TypeVar("_BelowT_contra", bound=np.generic, contravariant=True)
14+
_AboveT_contra = TypeVar("_AboveT_contra", bound=np.generic, contravariant=True, default=Any)
15+
_OtherT_contra = TypeVar("_OtherT_contra", contravariant=True)
16+
_MatchT_co = TypeVar("_MatchT_co", bound=np.generic, covariant=True, default=Any)
1317
_ShapeT_co = TypeVar("_ShapeT_co", bound=tuple[int, ...], covariant=True)
14-
_ToScalarT_contra = TypeVar("_ToScalarT_contra", bound=np.generic, contravariant=True)
15-
_FromScalarT_contra = TypeVar("_FromScalarT_contra", bound=np.generic, contravariant=True, default=Any)
16-
_SelfScalarT_co = TypeVar("_SelfScalarT_co", bound=np.generic, covariant=True, default=Any)
18+
19+
@type_check_only
20+
class CanNEP50(Protocol[_BelowT_contra, _AboveT_contra, _MatchT_co]):
21+
def __nep50__(self, below: _BelowT_contra, above: _AboveT_contra, /) -> _MatchT_co: ...
22+
23+
@type_check_only
24+
class _CanNEP50Int(Protocol[_OtherT_contra, _T_co]):
25+
def __nep50_int__(self, other: _OtherT_contra, /) -> _T_co: ...
26+
27+
@type_check_only
28+
class _CanNEP50Float(Protocol[_OtherT_contra, _T_co]):
29+
def __nep50_float__(self, other: _OtherT_contra, /) -> _T_co: ...
30+
31+
@type_check_only
32+
class _CanNEP50Complex(Protocol[_OtherT_contra, _T_co]):
33+
def __nep50_complex__(self, other: _OtherT_contra, /) -> _T_co: ...
34+
35+
_WithT = TypeVar("_WithT")
36+
_OutT = TypeVar("_OutT", bound=np.generic)
37+
38+
PromoteWith = TypeAliasType(
39+
"PromoteWith",
40+
_CanNEP50Int[_WithT, _OutT] | _CanNEP50Float[_WithT, _OutT] | _CanNEP50Complex[_WithT, _OutT],
41+
type_params=(_WithT, _OutT),
42+
)
43+
44+
###
1745

1846
@type_check_only
1947
class _HasType(Protocol[_T_co]):
2048
@property
2149
def type(self, /) -> type[_T_co]: ...
2250

2351
@type_check_only
24-
class CanCast(Protocol[_ToScalarT_contra, _FromScalarT_contra, _SelfScalarT_co]):
25-
def __nep50__(self, to: _ToScalarT_contra, from_: _FromScalarT_contra, /) -> _SelfScalarT_co: ...
52+
class MatchND(Protocol[_ShapeT_co, _T_co]):
53+
@property
54+
def shape(self, /) -> _ShapeT_co: ...
55+
@property
56+
def dtype(self, /) -> _HasType[_T_co]: ...
57+
58+
# TODO(jorenham): Rename these
2659

2760
@type_check_only
28-
class CanCast0D(Protocol[_ToScalarT_contra, _FromScalarT_contra, _SelfScalarT_co]):
61+
class CanCast0D(Protocol[_BelowT_contra, _AboveT_contra, _MatchT_co]):
2962
@property
3063
def shape(self, /) -> tuple[()]: ...
3164
@property
32-
def dtype(self, /) -> _HasType[CanCast[_ToScalarT_contra, _FromScalarT_contra, _SelfScalarT_co]]: ...
65+
def dtype(self, /) -> _HasType[CanNEP50[_BelowT_contra, _AboveT_contra, _MatchT_co]]: ...
3366

3467
@type_check_only
35-
class CanCastND(Protocol[_ShapeT_co, _ToScalarT_contra, _FromScalarT_contra, _SelfScalarT_co]):
68+
class CanCastND(Protocol[_ShapeT_co, _BelowT_contra, _AboveT_contra, _MatchT_co]):
3669
@property
3770
def shape(self, /) -> _ShapeT_co: ...
3871
@property
39-
def dtype(self, /) -> _HasType[CanCast[_ToScalarT_contra, _FromScalarT_contra, _SelfScalarT_co]]: ...
72+
def dtype(self, /) -> _HasType[CanNEP50[_BelowT_contra, _AboveT_contra, _MatchT_co]]: ...

0 commit comments

Comments
 (0)