Skip to content

Commit df7baba

Browse files
committed
✨ embed the NEP-50 inter-promotion rules
1 parent 73f5065 commit df7baba

File tree

4 files changed

+152
-123
lines changed

4 files changed

+152
-123
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: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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,

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)