8000 ENH: add type stubs from numpy-stubs · numpy/numpy@11b95d1 · GitHub
[go: up one dir, main page]

Skip to content

Commit 11b95d1

Browse files
committed
ENH: add type stubs from numpy-stubs
Add the type stubs and tests from numpy-stubs. Things this entails: - Copy over the stubs (numpy/__init__.pyi and numpy/core/_internal.pyi) - The only modification made was removing `ndarray.tostring` since it is deprecated - Update some setup.py files to include pyi files - Move the tests from numpy-stubs/tests into numpy/tests - Skip them if mypy is not installed (planning on setting up CI in a future PR) - Add a mypy.ini; use it to configure mypy in the tests - It tells mypy where to find NumPy in the test env - It ignores internal NumPy type errors (since we only want to consider errors from the tests cases) - Some small edits were made to fix test cases that were emitting deprecation warnings - Add numpy/py.typed so that the types are picked up in an installed version of NumPy
1 parent a5d021a commit 11b95d1

35 files changed

+2491
-0
lines changed

numpy/__init__.pyi

Lines changed: 1077 additions & 0 deletions
Large diffs are not rendered by default.

numpy/core/_internal.pyi

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from typing import Any
2+
3+
# TODO: add better annotations when ctypes is stubbed out
4+
5+
class _ctypes:
6+
@property
7+
def data(self) -> int: ...
8+
@property
9+
def shape(self) -> Any: ...
10+
@property
11+
def strides(self) -> Any: ...
12+
def data_as(self, obj: Any) -> Any: ...
13+
def shape_as(self, obj: Any) -> Any: ...
14+
def strides_as(self, obj: Any) -> Any: ...
15+
def get_data(self) -> int: ...
16+
def get_shape(self) -> Any: ...
17+
def get_strides(self) -> Any: ...
18+
def get_as_parameter(self) -> Any: ...

numpy/core/setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -967,6 +967,7 @@ def generate_umath_c(ext, build_dir):
967967
config.add_subpackage('tests')
968968
config.add_data_dir('tests/data')
969969
config.add_data_dir('tests/examples')
970+
config.add_data_files('*.pyi')
970971

971972
config.make_svn_version_py()
972973

numpy/py.typed

Whitespace-only changes.

numpy/setup.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ def configuration(parent_package='',top_path=None):
1818
config.add_subpackage('random')
1919
config.add_subpackage('testing')
2020
config.add_data_dir('doc')
21+
config.add_data_files('py.typed')
22+
config.add_data_files('*.pyi')
2123
config.add_subpackage('tests')
2224
config.make_config_py() # installs __config__.py
2325
return config

numpy/tests/fail/array_like.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from typing import Any, TYPE_CHECKING
2+
3+
import numpy as np
4+
5+
if TYPE_CHECKING:
6+
from numpy.typing import ArrayLike
7+
else:
8+
ArrayLike = Any
9+
10+
11+
class A:
12+
pass
13+
14+
15+
x1: ArrayLike = (i for i in range(10)) # E: Incompatible types in assignment
16+
x2: ArrayLike = A() # E: Incompatible types in assignment
17+
x3: ArrayLike = {1: "foo", 2: "bar"} # E: Incompatible types in assignment
18+
19+
scalar = np.int64(1)
20+
scalar.__array__(dtype=np.float64) # E: Unexpected keyword argument
21+
array = np.array([1])
22+
array.__array__(dtype=np.float64) # E: Unexpected keyword argument

numpy/tests/fail/fromnumeric.py

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
"""Tests for :mod:`numpy.core.fromnumeric`."""
2+
3+
import numpy as np
4+
5+
A = np.array(True, ndmin=2, dtype=bool)
6+
A.setflags(write=False)
7+
8+
a = np.bool_(True)
9+
10+
np.take(a, None) # E: No overload variant of "take" matches argument type
11+
np.take(a, axis=1.0) # E: No overload variant of "take" matches argument type
12+
np.take(A, out=1) # E: No overload variant of "take" matches argument type
13+
np.take(A, mode="bob") # E: No overload variant of "take" matches argument type
14+
15+
np.reshape(a, None) # E: Argument 2 to "reshape" has incompatible type
16+
np.reshape(A, 1, order="bob") # E: Argument "order" to "reshape" has incompatible type
17+
18+
np.choose(a, None) # E: No overload variant of "choose" matches argument type
19+
np.choose(a, out=1.0) # E: No overload variant of "choose" matches argument type
20+
np.choose(A, mode="bob") # E: No overload variant of "choose" matches argument type
21+
22+
np.repeat(a, None) # E: Argument 2 to "repeat" has incompatible type
23+
np.repeat(A, 1, axis=1.0) # E: Argument "axis" to "repeat" has incompatible type
24+
25+
np.swapaxes(a, 0, 0) # E: Argument 1 to "swapaxes" has incompatible type
26+
np.swapaxes(A, None, 1) # E: Argument 2 to "swapaxes" has incompatible type
27+
np.swapaxes(A, 1, [0]) # E: Argument 3 to "swapaxes" has incompatible type
28+
29+
np.transpose(a, axes=1) # E: Argument "axes" to "transpose" has incompatible type
30+
np.transpose(A, axes=1.0) # E: Argument "axes" to "transpose" has incompatible type
31+
32+
np.partition(a, None) # E: Argument 2 to "partition" has incompatible type
33+
np.partition(
34+
a, 0, axis="bob" # E: Argument "axis" to "partition" has incompatible type
35+
)
36+
np.partition(
37+
A, 0, kind="bob" # E: Argument "kind" to "partition" has incompatible type
38+
)
39+
np.partition(
40+
A, 0, order=range(5) # E: Argument "order" to "partition" has incompatible type
41+
)
42+
43+
np.argpartition( # E: No overload variant of "argpartition" matches argument type
44+
a, None
45+
)
46+
np.argpartition( # E: No overload variant of "argpartition" matches argument type
47+
a, 0, axis="bob"
48+
)
49+
np.argpartition( # E: No overload variant of "argpartition" matches argument type
50+
A, 0, kind="bob"
51+
)
52+
np.argpartition(
53+
A, 0, order=range(5) # E: Argument "order" to "argpartition" has incompatible type
54+
)
55+
56+
np.sort(a) # E: Argument 1 to "sort" has incompatible type
57+
np.sort(A, axis="bob") # E: Argument "axis" to "sort" has incompatible type
58+
np.sort(A, kind="bob") # E: Argument "kind" to "sort" has incompatible type
59+
np.sort(A, order=range(5)) # E: Argument "order" to "sort" has incompatible type
60+
61+
np.argsort(a) # E: Argument 1 to "argsort" has incompatible type
62+
np.argsort(A, axis="bob") # E: Argument "axis" to "argsort" has incompatible type
63+
np.argsort(A, kind="bob") # E: Argument "kind" to "argsort" has incompatible type
64+
np.argsort(A, order=range(5)) # E: Argument "order" to "argsort" has incompatible type
65+
66+
np.argmax(a) # E: No overload variant of "argmax" matches argument type
67+
np.argmax(A, axis="bob") # E: No overload variant of "argmax" matches argument type
68+
np.argmax(A, kind="bob") # E: No overload variant of "argmax" matches argument type
69+
70+
np.argmin(a) # E: No overload variant of "argmin" matches argument type
71+
np.argmin(A, axis="bob") # E: No overload variant of "argmin" matches argument type
72+
np.argmin(A, kind="bob") # E: No overload variant of "argmin" matches argument type
73+
74+
np.searchsorted(a, 0) # E: No overload variant of "searchsorted" matches argument type
75+
np.searchsorted( # E: No overload variant of "searchsorted" matches argument type
76+
A[0], 0, side="bob"
77+
)
78+
np.searchsorted( # E: No overload variant of "searchsorted" matches argument type
79+
A[0], 0, sorter=1.0
80+
)
81+
82+
np.resize(A, 1.0) # E: Argument 2 to "resize" has incompatible type
83+
84+
np.squeeze(A, 1.0) # E: No overload variant of "squeeze" matches argument type
85+
86+
np.diagonal(a) # E: Argument 1 to "diagonal" has incompatible type
87+
np.diagonal(A, offset=None) # E: Argument "offset" to "diagonal" has incompatible type
88+
np.diagonal(A, axis1="bob") # E: Argument "axis1" to "diagonal" has incompatible type
89+
np.diagonal(A, axis2=[]) # E: Argument "axis2" to "diagonal" has incompatible type
90+
91+
np.trace(a) # E: Argument 1 to "trace" has incompatible type
92+
np.trace(A, offset=None) # E: Argument "offset" to "trace" has incompatible type
93+
np.trace(A, axis1="bob") # E: Argument "axis1" to "trace" has incompatible type
94+
np.trace(A, axis2=[]) # E: Argument "axis2" to "trace" has incompatible type
95+
96+
np.ravel(a, order="bob") # E: Argument "order" to "ravel" has incompatible type
97+
98+
np.compress(True, A) # E: Argument 1 to "compress" has incompatible type
99+
np.compress(
100+
[True], A, axis=1.0 # E: Argument "axis" to "compress" has incompatible type
101+
)

numpy/tests/fail/ndarray.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import numpy as np
2+
3+
# Ban setting dtype since mutating the type of the array in place
4+
# makes having ndarray be generic over dtype impossible. Generally
5+
# users should use `ndarray.view` in this situation anyway. See
6+
#
7+
# https://github.com/numpy/numpy-stubs/issues/7
8+
#
9+
# for more context.
10+
float_array = np.array([1.0])
11+
float_array.dtype = np.bool_ # E: Property "dtype" defined in "ndarray" is read-only

numpy/tests/fail/numerictypes.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import numpy as np
2+
3+
# Techincally this works, but probably shouldn't. See
4+
#
5+
# https://github.com/numpy/numpy/issues/16366
6+
#
7+
np.maximum_sctype(1) # E: incompatible type "int"
8+
9+
np.issubsctype(1, np.int64) # E: incompatible type "int"
10+
11+
np.issubdtype(1, np.int64) # E: incompatible type "int"
12+
13+
np.find_common_type(np.int64, np.int64) # E: incompatible type "Type[int64]"

numpy/tests/fail/scalars.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import numpy as np
2+
3+
# Construction
4+
5+
np.float32(3j) # E: incompatible type
6+
7+
# Technically the following examples are valid NumPy code. But they
8+
# are not considered a best practice, and people who wish to use the
9+
# stubs should instead do
10+
#
11+
# np.array([1.0, 0.0, 0.0], dtype=np.float32)
12+
# np.array([], dtype=np.complex64)
13+
#
14+
# See e.g. the discussion on the mailing list
15+
#
16+
# https://mail.python.org/pipermail/numpy-discussion/2020-April/080566.html
17+
#
18+
# and the issue
19+
#
20+
# https://github.com/numpy/numpy-stubs/issues/41
21+
#
22+
# for more context.
23+
np.float32([1.0, 0.0, 0.0]) # E: incompatible type
24+
np.complex64([]) # E: incompatible type
25+
26+
np.complex64(1, 2) # E: Too many arguments
27+
# TODO: protocols (can't check for non-existent protocols w/ __getattr__)
28+
29+
np.datetime64(0) # E: non-matching overload
30+
31+
dt_64 = np.datetime64(0, "D")
32+
td_64 = np.timedelta64(1, "h")
33+
34+
dt_64 + dt_64 # 10000 E: Unsupported operand types
35+
36+
td_64 - dt_64 # E: Unsupported operand types
37+
td_64 / dt_64 # E: No overload
38+
td_64 % 1 # E: Unsupported operand types
39+
td_64 % dt_64 # E: Unsupported operand types
40+
41+
42+
class A:
43+
def __float__(self):
44+
return 1.0
45+
46+
47+
np.int8(A()) # E: incompatible type
48+
np.int16(A()) # E: incompatible type
49+
np.int32(A()) # E: incompatible type
50+
np.int64(A()) # E: incompatible type
51+
np.uint8(A()) # E: incompatible type
52+
np.uint16(A()) # E: incompatible type
53+
np.uint32(A()) # E: incompatible type
54+
np.uint64(A()) # E: incompatible type
55+
56+
np.void("test") # E: incompatible type
57+
58+
np.generic(1) # E: Cannot instantiate abstract class
59+
np.number(1) # E: Cannot instantiate abstract class
60+
np.integer(1) # E: Cannot instantiate abstract class
61+
np.signedinteger(1) # E: Cannot instantiate abstract class
62+
np.unsignedinteger(1) # E: Cannot instantiate abstract class
63+
np.inexact(1) # E: Cannot instantiate abstract class
64+
np.floating(1) # E: Cannot instantiate abstract class
65+
np.complexfloating(1) # E: Cannot instantiate abstract class
66+
np.character("test") # E: Cannot instantiate abstract class
67+
np.flexible(b"test") # E: Cannot instantiate abstract class

numpy/tests/fail/simple.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
"""Simple expression that should fail with mypy."""
2+
3+
import numpy as np
4+
5+
# Array creation routines checks
6+
np.zeros("test") # E: incompatible type
7+
np.zeros() # E: Too few arguments
8+
9+
np.ones("test") # E: incompatible type
10+
np.ones() # E: Too few arguments

numpy/tests/fail/ufuncs.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import numpy as np
2+
3+
np.sin.nin + "foo" # E: Unsupported operand types
4+
np.sin(1, foo="bar") # E: Unexpected keyword argument
5+
np.sin(1, extobj=["foo", "foo", "foo"]) # E: incompatible type
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import numpy as np
2+
3+
np.AxisError(1.0) # E: Argument 1 to "AxisError" has incompatible type
4+
np.AxisError(1, ndim=2.0) # E: Argument "ndim" to "AxisError" has incompatible type
5+
np.AxisError(
6+
2, msg_prefix=404 # E: Argument "msg_prefix" to "AxisError" has incompatible type
7+
)

numpy/tests/mypy.ini

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[mypy]
2+
mypy_path = ../..
3+
4+
[mypy-numpy]
5+
ignore_errors = True
6+
7+
[mypy-numpy.*]
8+
ignore_errors = True

numpy/tests/pass/array_like.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
from typing import Any, List, Optional, TYPE_CHECKING
2+
3+
import numpy as np
4+
5+
if TYPE_CHECKING:
6+
from numpy.typing import ArrayLike, DtypeLike, _SupportsArray
7+
else:
8+
ArrayLike = Any
9+
DtypeLike = Any
10+
_SupportsArray = Any
11+
12+
x1: ArrayLike = True
13+
x2: ArrayLike = 5
14+
x3: ArrayLike = 1.0
15+
x4: ArrayLike = 1 + 1j
16+
x5: ArrayLike = np.int8(1)
17+
x6: ArrayLike = np.float64(1)
18+
x7: ArrayLike = np.complex128(1)
19+
x8: ArrayLike = np.array([1, 2, 3])
20+
x9: ArrayLike = [1, 2, 3]
21+
x10: ArrayLike = (1, 2, 3)
22+
x11: ArrayLike = "foo"
23+
24+
25+
class A:
26+
def __array__(self, dtype: DtypeLike = None) -> np.ndarray:
27+
return np.array([1, 2, 3])
28+
29+
30+
x12: ArrayLike = A()
31+
32+
scalar: _SupportsArray = np.int64(1)
33+
scalar.__array__(np.float64)
34+
array: _SupportsArray = np.array(1)
35+
array.__array__(np.float64)
36+
37+
a: _SupportsArray = A()
38+
a.__array__(np.int64)
39+
a.__array__(dtype=np.int64)
40+
41+
# Escape hatch for when you mean to make something like an object
42+
# array.
43+
object_array_scalar: Any = (i for i in range(10))
44+
np.array(object_array_scalar)

0 commit comments

Comments
 (0)
0