Skip to content

Commit c2bee24

Browse files
committed
🐴 work around at least 5 mypy bugs (not even kidding)
1 parent f95b93b commit c2bee24

File tree

19 files changed

+114
-110
lines changed

19 files changed

+114
-110
lines changed

src/_numtype/@test/generated/test_rank.pyi

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# @generated 2025-05-14T01:47:22Z with tool/testgen.py
1+
# @generated 2025-05-19T03:25:34Z with tool/testgen.py
22
from typing import Any
33

44
import _numtype as _nt
@@ -31,7 +31,7 @@ r0n_le_r0n: _nt.HasRankLE[_nt.Rank0N] = r0n
3131

3232
r0_ge_s0: _nt.HasRankGE[_nt.Shape0] = r0
3333
r0_ge_r0: _nt.HasRankGE[_nt.Rank0] = r0
34-
r0_ge_s0n: _nt.HasRankGE[_nt.Shape0N] = r0
34+
r0_ge_s0n: _nt.HasRankGE[_nt.Shape0N] = r0 # type: ignore[assignment]
3535
r0_ge_r0n: _nt.HasRankGE[_nt.Rank0N] = r0
3636
r0n_ge_s0: _nt.HasRankGE[_nt.Shape0] = r0n
3737
r0n_ge_r0: _nt.HasRankGE[_nt.Rank0] = r0n

src/_numtype/@test/test_rank_shape.pyi

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,24 @@ from typing import assert_type
22

33
import _numtype as _nt
44

5+
# TODO: remove the `# type: ignore`s once python/mypy#19110 is fixed
6+
57
a0: _nt.Array0D
68
assert_type(a0.__inner_shape__, _nt.Rank0)
7-
r0: _nt.Rank0 = a0.shape # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
8-
s0: _nt.Shape0 = a0.shape
9+
assert_type(a0.shape, _nt.Shape0) # type: ignore[assert-type]
910

1011
a1: _nt.Array1D
1112
assert_type(a1.__inner_shape__, _nt.Rank1)
12-
r1: _nt.Rank1 = a1.shape # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
13-
s1: _nt.Shape1 = a1.shape
13+
assert_type(a1.shape, _nt.Shape1) # type: ignore[assert-type]
1414

1515
a2: _nt.Array2D
1616
assert_type(a2.__inner_shape__, _nt.Rank2)
17-
r2: _nt.Rank2 = a2.shape # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
18-
s2: _nt.Shape2 = a2.shape
17+
assert_type(a2.shape, _nt.Shape2) # type: ignore[assert-type]
1918

2019
a3: _nt.Array3D
2120
assert_type(a3.__inner_shape__, _nt.Rank3)
22-
r3: _nt.Rank3 = a3.shape # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
23-
s3: _nt.Shape3 = a3.shape
21+
assert_type(a3.shape, _nt.Shape3) # type: ignore[assert-type]
2422

2523
a4: _nt.Array4D
2624
assert_type(a4.__inner_shape__, _nt.Rank4)
27-
r4: _nt.Rank4 = a4.shape # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
28-
s4: _nt.Shape4 = a4.shape
25+
assert_type(a4.shape, _nt.Shape4) # type: ignore[assert-type]

src/_numtype/__init__.pyi

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,11 @@ from ._array import (
1919
Array2D as Array2D,
2020
Array3D as Array3D,
2121
Array4D as Array4D,
22-
ArrayND as ArrayND,
2322
MArray as MArray,
2423
MArray0D as MArray0D,
2524
MArray1D as MArray1D,
2625
MArray2D as MArray2D,
2726
MArray3D as MArray3D,
28-
MArrayND as MArrayND,
2927
Matrix as Matrix,
3028
StringArray as StringArray,
3129
StringArray0D as StringArray0D,
@@ -172,7 +170,8 @@ _ToT = TypeVar("_ToT")
172170

173171
@type_check_only
174172
class CanArray0D(Protocol[_ScalarT_co]):
175-
def __array__(self, /) -> np.ndarray[Shape0, np.dtype[_ScalarT_co]]: ...
173+
# TODO: remove `| Rank0` once python/mypy#19110 is fixed
174+
def __array__(self, /) -> np.ndarray[Shape0 | Rank0, np.dtype[_ScalarT_co]]: ...
176175

177176
@type_check_only
178177
class CanArray1D(Protocol[_ScalarT_co]):
@@ -188,11 +187,13 @@ class CanArray3D(Protocol[_ScalarT_co]):
188187

189188
@type_check_only
190189
class CanArrayND(Protocol[_ScalarT_co]):
191-
def __array__(self, /) -> np.ndarray[Shape, np.dtype[_ScalarT_co]]: ...
190+
# TODO: remove `| Rank0` once python/mypy#19110 is fixed
191+
def __array__(self, /) -> np.ndarray[Shape | Rank0, np.dtype[_ScalarT_co]]: ...
192192

193193
@type_check_only
194194
class CanLenArrayND(Protocol[_ScalarT_co]):
195195
def __len__(self, /) -> int: ...
196+
# TODO: remove `| Rank0` once python/mypy#19110 is fixed
196197
def __array__(self, /) -> np.ndarray[Shape, np.dtype[_ScalarT_co]]: ...
197198

198199
@type_check_only

src/_numtype/_array.pyi

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ from typing_extensions import TypeAliasType, TypeVar
55

66
import numpy as np
77

8-
from ._rank import Rank, Rank0, Rank1, Rank2, Rank3, Rank4
9-
from ._shape import Shape
8+
from ._rank import Rank0, Rank1, Rank2, Rank3, Rank4
9+
from ._shape import AnyShape, Shape
1010

1111
__all__ = [
1212
"Array",
@@ -15,13 +15,11 @@ __all__ = [
1515
"Array2D",
1616
"Array3D",
1717
"Array4D",
18-
"ArrayND",
1918
"MArray",
2019
"MArray0D",
2120
"MArray1D",
2221
"MArray2D",
2322
"MArray3D",
24-
"MArrayND",
2523
"Matrix",
2624
"StringArray",
2725
"StringArray0D",
@@ -33,7 +31,8 @@ __all__ = [
3331

3432
###
3533

36-
_RankT = TypeVar("_RankT", bound=Shape, default=Shape)
34+
# TODO: use `Shape` instead of `AnyShape` once python/mypy#19110 is fixed
35+
_RankT = TypeVar("_RankT", bound=AnyShape, default=Shape)
3736
_ScalarT = TypeVar("_ScalarT", bound=np.generic, default=Any)
3837
_NaT = TypeVar("_NaT", default=Never)
3938

@@ -45,7 +44,6 @@ Array1D = TypeAliasType("Array1D", np.ndarray[Rank1, np.dtype[_ScalarT]], type_p
4544
Array2D = TypeAliasType("Array2D", np.ndarray[Rank2, np.dtype[_ScalarT]], type_params=(_ScalarT,))
4645
Array3D = TypeAliasType("Array3D", np.ndarray[Rank3, np.dtype[_ScalarT]], type_params=(_ScalarT,))
4746
Array4D = TypeAliasType("Array4D", np.ndarray[Rank4, np.dtype[_ScalarT]], type_params=(_ScalarT,))
48-
ArrayND = TypeAliasType("ArrayND", np.ndarray[Rank, np.dtype[_ScalarT]], type_params=(_ScalarT,))
4947

5048
###
5149

@@ -58,7 +56,6 @@ MArray0D = TypeAliasType("MArray0D", np.ma.MaskedArray[Rank0, np.dtype[_ScalarT]
5856
MArray1D = TypeAliasType("MArray1D", np.ma.MaskedArray[Rank1, np.dtype[_ScalarT]], type_params=(_ScalarT,))
5957
MArray2D = TypeAliasType("MArray2D", np.ma.MaskedArray[Rank2, np.dtype[_ScalarT]], type_params=(_ScalarT,))
6058
MArray3D = TypeAliasType("MArray3D", np.ma.MaskedArray[Rank3, np.dtype[_ScalarT]], type_params=(_ScalarT,))
61-
MArrayND = TypeAliasType("MArrayND", np.ma.MaskedArray[Rank, np.dtype[_ScalarT]], type_params=(_ScalarT, _RankT))
6259

6360
###
6461

@@ -89,6 +86,6 @@ StringArray3D = TypeAliasType(
8986
)
9087
StringArrayND = TypeAliasType(
9188
"StringArrayND",
92-
np.ndarray[Rank, np.dtypes.StringDType[_NaT]],
89+
np.ndarray[Shape, np.dtypes.StringDType[_NaT]],
9390
type_params=(_NaT,),
9491
)

src/_numtype/_rank.pyi

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from typing import Any, Generic, Protocol, Self, TypeAlias, final, type_check_only
22
from typing_extensions import TypeAliasType, TypeVar, TypeVarTuple, override
33

4-
from ._shape import Shape, Shape0, Shape0N, Shape1, Shape1N, Shape2, Shape2N, Shape3, Shape3N, Shape4, Shape4N
4+
from ._shape import AnyShape, Shape, Shape0, Shape1, Shape1N, Shape2, Shape2N, Shape3, Shape3N, Shape4, Shape4N
55

66
__all__ = [
77
"HasInnerShape",
@@ -29,21 +29,24 @@ _Shape04: TypeAlias = _Shape03 | Shape4
2929

3030
###
3131

32-
_UpperT = TypeVar("_UpperT", bound=Shape)
33-
_LowerT = TypeVar("_LowerT", bound=Shape)
32+
# TODO(jorenham): remove `| Rank0 | Rank` once python/mypy#19110 is fixed
33+
_UpperT = TypeVar("_UpperT", bound=Shape | Rank0 | Rank)
34+
_LowerT = TypeVar("_LowerT", bound=Shape | Rank0 | Rank)
3435
_RankT = TypeVar("_RankT", bound=Shape, default=Any)
3536

36-
_RankLE: TypeAlias = _CanBroadcast[Any, _UpperT, _RankT]
37-
_RankGE: TypeAlias = _CanBroadcast[_LowerT, Any, _RankT]
37+
# TODO(jorenham): remove `| Rank0 | Rank` once python/mypy#19110 is fixed
38+
_RankLE: TypeAlias = _CanBroadcast[Any, _UpperT, _RankT] | Shape0 | Rank0 | Rank
39+
# TODO(jorenham): remove `| Rank` once python/mypy#19110 is fixed
40+
_RankGE: TypeAlias = _CanBroadcast[_LowerT, Any, _RankT] | _LowerT | Rank
3841

3942
HasRankLE = TypeAliasType(
4043
"HasRankLE",
41-
_HasInnerShape[Shape0 | _RankLE[_UpperT, _RankT]],
44+
_HasInnerShape[_RankLE[_UpperT, _RankT]],
4245
type_params=(_UpperT, _RankT),
4346
)
4447
HasRankGE = TypeAliasType(
4548
"HasRankGE",
46-
_HasInnerShape[_LowerT | _RankGE[_LowerT, _RankT]],
49+
_HasInnerShape[_RankGE[_LowerT, _RankT]],
4750
type_params=(_LowerT, _RankT),
4851
)
4952

@@ -136,30 +139,30 @@ class Rank4(BaseRank[int, int, int, int]):
136139
@type_check_only
137140
class Rank(BaseRank[*tuple[int, ...]]):
138141
@override
139-
def __broadcast__(self, from_: Shape0N, to: tuple[*_Ts], /) -> Self: ...
142+
def __broadcast__(self, from_: AnyShape, to: tuple[*_Ts], /) -> Self: ...
140143

141144
@final
142145
@type_check_only
143146
class Rank1N(BaseRank[int, *tuple[int, ...]]):
144147
@override
145-
def __broadcast__(self, from_: Shape0N, to: Shape1N, /) -> Self: ...
148+
def __broadcast__(self, from_: AnyShape, to: Shape1N, /) -> Self: ...
146149

147150
@final
148151
@type_check_only
149152
class Rank2N(BaseRank[int, int, *tuple[int, ...]]):
150153
@override
151-
def __broadcast__(self, from_: Shape0N, to: Shape2N, /) -> Self: ...
154+
def __broadcast__(self, from_: AnyShape, to: Shape2N, /) -> Self: ...
152155

153156
@final
154157
@type_check_only
155158
class Rank3N(BaseRank[int, int, int, *tuple[int, ...]]):
156159
@override
157-
def __broadcast__(self, from_: Shape0N, to: Shape3N, /) -> Self: ...
160+
def __broadcast__(self, from_: AnyShape, to: Shape3N, /) -> Self: ...
158161

159162
@final
160163
@type_check_only
161164
class Rank4N(BaseRank[int, int, int, int, *tuple[int, ...]]):
162165
@override
163-
def __broadcast__(self, from_: Shape0N, to: Shape4N, /) -> Self: ...
166+
def __broadcast__(self, from_: AnyShape, to: Shape4N, /) -> Self: ...
164167

165168
Rank0N: TypeAlias = Rank

src/_numtype/_shape.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ __all__ = [
2020
AnyShape = TypeAliasType("AnyShape", tuple[Any, ...])
2121
Shape = TypeAliasType("Shape", tuple[int, ...])
2222

23+
# TODO: remove `| Rank0` once python/mypy#19110 is fixed
2324
Shape0 = TypeAliasType("Shape0", tuple[()])
2425
Shape1 = TypeAliasType("Shape1", tuple[int])
2526
Shape2 = TypeAliasType("Shape2", tuple[int, int])

src/numpy-stubs/@test/static/accept/fromnumeric.pyi

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ from typing import Any, assert_type
33
import _numtype as _nt
44
import numpy as np
55

6-
class NDArraySubclass(np.ndarray[_nt.Rank, np.dtype[np.complex128]]): ...
6+
class NDArraySubclass(np.ndarray[_nt.Shape, np.dtype[np.complex128]]): ...
77

88
AR_b1: _nt.Array[np.bool]
99
AR_f4: _nt.Array[np.float32]
@@ -144,7 +144,8 @@ assert_type(np.nonzero(AR_f4), tuple[_nt.Array[np.intp], ...])
144144
assert_type(np.nonzero(AR_1d), tuple[_nt.Array[np.intp], ...])
145145
assert_type(np.nonzero(AR_nd), tuple[_nt.Array[np.intp], ...])
146146

147-
assert_type(np.shape(b1), tuple[()])
147+
# TODO: remove the `# type: ignore` once python/mypy#19110 is fixed
148+
assert_type(np.shape(b1), tuple[()]) # type: ignore[assert-type]
148149
assert_type(np.shape(f_0d), tuple[()])
149150
assert_type(np.shape(i_1d), tuple[int])
150151
assert_type(np.shape(i_2d), tuple[int, int])
@@ -153,9 +154,8 @@ assert_type(np.shape(i_4d), tuple[int, ...])
153154
assert_type(np.shape(AR_b1), tuple[int, ...])
154155
assert_type(np.shape(AR_nd), tuple[int, ...])
155156
# these fail on mypy, but it works as expected with pyright/pylance
156-
# assert_type(np.shape(AR_0d), tuple[()])
157-
# assert_type(np.shape(AR_1d), tuple[int])
158-
# assert_type(np.shape(AR_2d), tuple[int, int])
157+
assert_type(np.shape(AR_0d), tuple[()]) # type: ignore[assert-type]
158+
assert_type(np.shape(AR_1d), tuple[int]) # type: ignore[assert-type]
159159

160160
assert_type(np.compress(b_1d, b1), _nt.Array[np.bool])
161161
assert_type(np.compress(b_1d, f4), _nt.Array[np.float32])

src/numpy-stubs/@test/static/accept/ndarray_misc.pyi

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import numpy as np
99

1010
###
1111

12-
class SubArray(np.ndarray[_nt.Rank, np.dtype[np.object_]]): ...
12+
class SubArray(np.ndarray[_nt.Shape, np.dtype[np.object_]]): ...
1313

1414
f8: np.float64
1515
i8: np.int64
@@ -191,7 +191,7 @@ assert_type(complex(AR_f8), complex)
191191

192192
assert_type(operator.index(AR_i8), int)
193193

194-
assert_type(AR_f8.__array_wrap__(AR_O_sub), _nt.ArrayND[np.object_])
194+
assert_type(AR_f8.__array_wrap__(AR_O_sub), _nt.Array[np.object_])
195195

196196
assert_type(AR_V[0], Any)
197197
assert_type(AR_V[0, 0], Any)

src/numpy-stubs/@test/static/accept/shape.pyi

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ class XYGrid(NamedTuple):
99

1010
arr: np.ndarray[XYGrid, Any]
1111

12-
# Test shape property matches shape typevar
13-
assert_type(arr.shape, XYGrid)
12+
# NOTE(jorenham): mypy 1.15 ignores the typevar constraints, and incorrectly infers `XYGrid``
13+
assert_type(arr.shape, tuple[int, int]) # type: ignore[assert-type]

src/numpy-stubs/@test/static/reject/ma.pyi

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import numpy as np
33
m: np.ma.MaskedArray[tuple[int], np.dtype[np.float64]]
44

55
m.shape = (3, 1) # type: ignore[assignment]
6-
m.dtype = np.bool # type: ignore[misc] # pyright: ignore[reportAttributeAccessIssue]
6+
m.dtype = np.bool # type: ignore[assignment, misc] # pyright: ignore[reportAttributeAccessIssue]
77

88
np.amin(m, axis=1.0) # type: ignore[call-overload] # pyright: ignore[reportArgumentType, reportCallIssue]
99
np.amin(m, keepdims=1.0) # type: ignore[call-overload] # pyright: ignore[reportArgumentType, reportCallIssue]

0 commit comments

Comments
 (0)