Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✅ migrate numpy's static rejection tests for specific error codes #13

Merged
merged 3 commits into from
Jan 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ env:
jobs:
lint:
runs-on: ubuntu-latest
timeout-minutes: 2
timeout-minutes: 5

steps:
- uses: actions/checkout@v4
Expand All @@ -35,3 +35,9 @@ jobs:
run: |
uv run ruff check --output-format=github
uv run ruff format --check

# TODO: static acceptance tests
- name: test static (reject)
run: |
uv run mypy --hide-error-context --hide-error-code-links --no-pretty test/static/reject
uv run basedpyright test/static/reject
4 changes: 3 additions & 1 deletion test/static/accept/README.md
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
Static acceptance type-tests for true negatives.
# Static acceptance type-tests for true negatives

This mainly relies on `typing_extensions.assert_type`.
7 changes: 6 additions & 1 deletion test/static/reject/README.md
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
Static rejection type-tests for true positives.
# Static rejection type-tests for true positives

For (based)mypy, this requires the `ignore-without-code` error code and the `warn_unused_ignores`
setting to be enabled.
For (based)pyright, the `enableTypeIgnoreComments` and `reportUnnecessaryTypeIgnoreComment` rules
must be enabled.
140 changes: 70 additions & 70 deletions test/static/reject/arithmetic.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -28,96 +28,96 @@ AR_LIKE_M: list[np.datetime64]
# Array subtraction

# NOTE: mypys `NoReturn` errors are, unfortunately, not that great
_1 = ... # E: Need type annotation
_2 = ... # E: Need type annotation
AR_i - b"" # E: No overload variant
_1 = AR_b - AR_LIKE_b # type: ignore[var-annotated]
_2 = AR_LIKE_b - AR_b # type: ignore[var-annotated]
AR_i - b"" # type: ignore[operator] # pyright: ignore[reportOperatorIssue]

AR_f - AR_LIKE_m # E: Unsupported operand types
AR_f - AR_LIKE_M # E: Unsupported operand types
AR_c - AR_LIKE_m # E: Unsupported operand types
AR_c - AR_LIKE_M # E: Unsupported operand types
AR_f - AR_LIKE_m # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
AR_f - AR_LIKE_M # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
AR_c - AR_LIKE_m # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
AR_c - AR_LIKE_M # type: ignore[operator] # pyright: ignore[reportOperatorIssue]

AR_m - AR_LIKE_f # E: Unsupported operand types
AR_M - AR_LIKE_f # E: Unsupported operand types
AR_m - AR_LIKE_c # E: Unsupported operand types
AR_M - AR_LIKE_c # E: Unsupported operand types
AR_m - AR_LIKE_f # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
AR_M - AR_LIKE_f # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
AR_m - AR_LIKE_c # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
AR_M - AR_LIKE_c # type: ignore[operator] # pyright: ignore[reportOperatorIssue]

AR_m - AR_LIKE_M # E: Unsupported operand types
AR_LIKE_m - AR_M # E: Unsupported operand types
AR_m - AR_LIKE_M # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
AR_LIKE_m - AR_M # type: ignore[operator] # pyright: ignore[reportOperatorIssue]

# array floor division

AR_M // AR_LIKE_b # E: Unsupported operand types
AR_M // AR_LIKE_u # E: Unsupported operand types
AR_M // AR_LIKE_i # E: Unsupported operand types
AR_M // AR_LIKE_f # E: Unsupported operand types
AR_M // AR_LIKE_c # E: Unsupported operand types
AR_M // AR_LIKE_m # E: Unsupported operand types
AR_M // AR_LIKE_M # E: Unsupported operand types

AR_b // AR_LIKE_M # E: Unsupported operand types
AR_u // AR_LIKE_M # E: Unsupported operand types
AR_i // AR_LIKE_M # E: Unsupported operand types
AR_f // AR_LIKE_M # E: Unsupported operand types
AR_c // AR_LIKE_M # E: Unsupported operand types
AR_m // AR_LIKE_M # E: Unsupported operand types
AR_M // AR_LIKE_M # E: Unsupported operand types

_3 = ... # E: Need type annotation
AR_m // AR_LIKE_c # E: Unsupported operand types

AR_b // AR_LIKE_m # E: Unsupported operand types
AR_u // AR_LIKE_m # E: Unsupported operand types
AR_i // AR_LIKE_m # E: Unsupported operand types
AR_f // AR_LIKE_m # E: Unsupported operand types
AR_c // AR_LIKE_m # E: Unsupported operand types
AR_M // AR_LIKE_b # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
AR_M // AR_LIKE_u # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
AR_M // AR_LIKE_i # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
AR_M // AR_LIKE_f # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
AR_M // AR_LIKE_c # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
AR_M // AR_LIKE_m # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
AR_M // AR_LIKE_M # type: ignore[operator] # pyright: ignore[reportOperatorIssue]

AR_b // AR_LIKE_M # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
AR_u // AR_LIKE_M # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
AR_i // AR_LIKE_M # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
AR_f // AR_LIKE_M # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
AR_c // AR_LIKE_M # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
AR_m // AR_LIKE_M # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
AR_M // AR_LIKE_M # type: ignore[operator] # pyright: ignore[reportOperatorIssue]

_3 = AR_m // AR_LIKE_b # type: ignore[var-annotated]
AR_m // AR_LIKE_c # type: ignore[operator] # pyright: ignore[reportOperatorIssue]

AR_b // AR_LIKE_m # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
AR_u // AR_LIKE_m # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
AR_i // AR_LIKE_m # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
AR_f // AR_LIKE_m # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
AR_c // AR_LIKE_m # type: ignore[operator] # pyright: ignore[reportOperatorIssue]

# Array multiplication

AR_b *= AR_LIKE_u # E: incompatible type
AR_b *= AR_LIKE_i # E: incompatible type
AR_b *= AR_LIKE_f # E: incompatible type
AR_b *= AR_LIKE_c # E: incompatible type
AR_b *= AR_LIKE_m # E: incompatible type
AR_b *= AR_LIKE_u # type: ignore[arg-type] # pyright: ignore[reportAssignmentType]
AR_b *= AR_LIKE_i # type: ignore[arg-type] # pyright: ignore[reportAssignmentType]
AR_b *= AR_LIKE_f # type: ignore[arg-type] # pyright: ignore[reportAssignmentType]
AR_b *= AR_LIKE_c # type: ignore[arg-type] # pyright: ignore[reportAssignmentType]
AR_b *= AR_LIKE_m # type: ignore[arg-type] # pyright: ignore[reportAssignmentType]

AR_u *= AR_LIKE_i # E: incompatible type
AR_u *= AR_LIKE_f # E: incompatible type
AR_u *= AR_LIKE_c # E: incompatible type
AR_u *= AR_LIKE_m # E: incompatible type
AR_u *= AR_LIKE_i # type: ignore[arg-type] # pyright: ignore[reportAssignmentType]
AR_u *= AR_LIKE_f # type: ignore[arg-type] # pyright: ignore[reportAssignmentType]
AR_u *= AR_LIKE_c # type: ignore[arg-type] # pyright: ignore[reportAssignmentType]
AR_u *= AR_LIKE_m # type: ignore[arg-type] # pyright: ignore[reportAssignmentType]

AR_i *= AR_LIKE_f # E: incompatible type
AR_i *= AR_LIKE_c # E: incompatible type
AR_i *= AR_LIKE_m # E: incompatible type
AR_i *= AR_LIKE_f # type: ignore[arg-type] # pyright: ignore[reportAssignmentType]
AR_i *= AR_LIKE_c # type: ignore[arg-type] # pyright: ignore[reportAssignmentType]
AR_i *= AR_LIKE_m # type: ignore[arg-type] # pyright: ignore[reportAssignmentType]

AR_f *= AR_LIKE_c # E: incompatible type
AR_f *= AR_LIKE_m # E: incompatible type
AR_f *= AR_LIKE_c # type: ignore[arg-type] # pyright: ignore[reportAssignmentType]
AR_f *= AR_LIKE_m # type: ignore[arg-type] # pyright: ignore[reportAssignmentType]

# Array power

AR_b **= AR_LIKE_b # E: Invalid self argument
AR_b **= AR_LIKE_u # E: Invalid self argument
AR_b **= AR_LIKE_i # E: Invalid self argument
AR_b **= AR_LIKE_f # E: Invalid self argument
AR_b **= AR_LIKE_c # E: Invalid self argument
AR_b **= AR_LIKE_b # type: ignore[misc] # pyright: ignore[reportAssignmentType]
AR_b **= AR_LIKE_u # type: ignore[misc] # pyright: ignore[reportAssignmentType]
AR_b **= AR_LIKE_i # type: ignore[misc] # pyright: ignore[reportAssignmentType]
AR_b **= AR_LIKE_f # type: ignore[misc] # pyright: ignore[reportAssignmentType]
AR_b **= AR_LIKE_c # type: ignore[misc] # pyright: ignore[reportAssignmentType]

AR_u **= AR_LIKE_i # E: incompatible type
AR_u **= AR_LIKE_f # E: incompatible type
AR_u **= AR_LIKE_c # E: incompatible type
AR_u **= AR_LIKE_i # type: ignore[arg-type] # pyright: ignore[reportAssignmentType]
AR_u **= AR_LIKE_f # type: ignore[arg-type] # pyright: ignore[reportAssignmentType]
AR_u **= AR_LIKE_c # type: ignore[arg-type] # pyright: ignore[reportAssignmentType]

AR_i **= AR_LIKE_f # E: incompatible type
AR_i **= AR_LIKE_c # E: incompatible type
AR_i **= AR_LIKE_f # type: ignore[arg-type] # pyright: ignore[reportAssignmentType]
AR_i **= AR_LIKE_c # type: ignore[arg-type] # pyright: ignore[reportAssignmentType]

AR_f **= AR_LIKE_c # E: incompatible type
AR_f **= AR_LIKE_c # type: ignore[arg-type] # pyright: ignore[reportAssignmentType]

# Scalars

b_ - b_ # E: No overload variant
b_ - b_ # type: ignore[call-overload] # pyright: ignore[reportOperatorIssue]

dt + dt # E: Unsupported operand types
td - dt # E: Unsupported operand types
td % 1 # E: Unsupported operand types
td / dt # E: No overload
td % dt # E: Unsupported operand types
dt + dt # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
td - dt # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
td % 1 # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
td / dt # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
td % dt # type: ignore[operator] # pyright: ignore[reportOperatorIssue]

-b_ # E: Unsupported operand type
+b_ # E: Unsupported operand type
-b_ # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
+b_ # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
42 changes: 21 additions & 21 deletions test/static/reject/array_constructors.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,33 @@ import numpy as np
import numpy.typing as npt

a: npt.NDArray[np.float64]
generator = ...
generator = (i for i in range(10))

np.require(a, requirements=1) # E: No overload variant
np.require(a, requirements="TEST") # E: incompatible type
np.require(a, requirements=1) # type: ignore[call-overload] # pyright: ignore[reportCallIssue,reportArgumentType]
np.require(a, requirements="TEST") # type: ignore[arg-type] # pyright: ignore[reportCallIssue,reportArgumentType]

np.zeros("test") # E: incompatible type
np.zeros() # E: require at least one argument
np.zeros("test") # type: ignore[arg-type] # pyright: ignore[reportCallIssue,reportArgumentType]
np.zeros() # type: ignore[call-overload] # pyright: ignore[reportCallIssue]

np.ones("test") # E: incompatible type
np.ones() # E: require at least one argument
np.ones("test") # type: ignore[arg-type] # pyright: ignore[reportCallIssue,reportArgumentType]
np.ones() # type: ignore[call-overload] # pyright: ignore[reportCallIssue]

np.array(0, float, True) # E: No overload variant
np.array(0, float, True) # type: ignore[call-overload] # pyright: ignore[reportCallIssue]

np.linspace(None, "bob") # E: No overload variant
np.linspace(0, 2, num=10.0) # E: No overload variant
np.linspace(0, 2, endpoint="True") # E: No overload variant
np.linspace(0, 2, retstep=b"False") # E: No overload variant
np.linspace(0, 2, dtype=0) # E: No overload variant
np.linspace(0, 2, axis=None) # E: No overload variant
np.linspace(None, "bob") # type: ignore[call-overload] # pyright: ignore[reportCallIssue,reportArgumentType]
np.linspace(0, 2, num=10.0) # type: ignore[call-overload] # pyright: ignore[reportCallIssue,reportArgumentType]
np.linspace(0, 2, endpoint="True") # type: ignore[call-overload] # pyright: ignore[reportCallIssue,reportArgumentType]
np.linspace(0, 2, retstep=b"False") # type: ignore[call-overload] # pyright: ignore[reportCallIssue,reportArgumentType]
np.linspace(0, 2, dtype=0) # type: ignore[call-overload] # pyright: ignore[reportCallIssue,reportArgumentType]
np.linspace(0, 2, axis=None) # type: ignore[call-overload] # pyright: ignore[reportCallIssue,reportArgumentType]

np.logspace(None, "bob") # E: No overload variant
np.logspace(0, 2, base=None) # E: No overload variant
np.logspace(None, "bob") # type: ignore[call-overload] # pyright: ignore[reportCallIssue,reportArgumentType]
np.logspace(0, 2, base=None) # type: ignore[call-overload] # pyright: ignore[reportCallIssue,reportArgumentType]

np.geomspace(None, "bob") # E: No overload variant
np.geomspace(None, "bob") # type: ignore[call-overload] # pyright: ignore[reportCallIssue,reportArgumentType]

np.stack(generator) # E: No overload variant
np.hstack({1, 2}) # E: No overload variant
np.vstack(1) # E: No overload variant
np.stack(generator) # type: ignore[call-overload] # pyright: ignore[reportCallIssue,reportArgumentType]
np.hstack({1, 2}) # type: ignore[call-overload] # pyright: ignore[reportCallIssue,reportArgumentType]
np.vstack(1) # type: ignore[call-overload] # pyright: ignore[reportCallIssue,reportArgumentType]

np.array([1], like=1) # E: No overload variant
np.array([1], like=1) # type: ignore[call-overload] # pyright: ignore[reportCallIssue,reportArgumentType]
10 changes: 5 additions & 5 deletions test/static/reject/array_like.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ from numpy._typing import ArrayLike

class A: ...

x1: ArrayLike = ... # E: Incompatible types in assignment
x2: ArrayLike = ... # E: Incompatible types in assignment
x3: ArrayLike = {1: "foo", 2: "bar"} # E: Incompatible types in assignment
x1: ArrayLike = (i for i in range(10)) # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
x2: ArrayLike = A() # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
x3: ArrayLike = {1: "foo", 2: "bar"} # type: ignore[assignment] # pyright: ignore[reportAssignmentType]

scalar = np.int64(1)
scalar.__array__(dtype=np.float64) # E: No overload variant
scalar.__array__(dtype=np.float64) # type: ignore[call-overload] # pyright: ignore[reportCallIssue]
array = np.array([1])
array.__array__(dtype=np.float64) # E: No overload variant
array.__array__(dtype=np.float64) # type: ignore[call-overload] # pyright: ignore[reportCallIssue]
2 changes: 1 addition & 1 deletion test/static/reject/array_pad.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ import numpy.typing as npt

AR_i8: npt.NDArray[np.int64]

np.pad(AR_i8, 2, mode="bob") # E: No overload variant
np.pad(AR_i8, 2, mode="bob") # type: ignore[call-overload] # pyright: ignore[reportCallIssue,reportArgumentType]
12 changes: 6 additions & 6 deletions test/static/reject/arrayprint.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ AR: npt.NDArray[np.float64]
func1: Callable[[Any], str]
func2: Callable[[np.integer[Any]], str]

np.array2string(AR, style=None) # E: Unexpected keyword argument
np.array2string(AR, legacy="1.14") # E: incompatible type
np.array2string(AR, sign="*") # E: incompatible type
np.array2string(AR, floatmode="default") # E: incompatible type
np.array2string(AR, formatter={"A": func1}) # E: incompatible type
np.array2string(AR, formatter={"float": func2}) # E: Incompatible types
np.array2string(AR, style=None) # type: ignore[call-arg] # pyright: ignore[reportCallIssue]
np.array2string(AR, legacy="1.14") # type: ignore[arg-type] # pyright: ignore[reportArgumentType]
np.array2string(AR, sign="*") # type: ignore[arg-type] # pyright: ignore[reportArgumentType]
np.array2string(AR, floatmode="default") # type: ignore[arg-type] # pyright: ignore[reportArgumentType]
np.array2string(AR, formatter={"A": func1}) # type: ignore[arg-type] # pyright: ignore[reportArgumentType]
np.array2string(AR, formatter={"float": func2}) # type: ignore[typeddict-item] # pyright: ignore[reportArgumentType]
16 changes: 8 additions & 8 deletions test/static/reject/arrayterator.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import numpy.typing as npt
AR_i8: npt.NDArray[np.int64]
ar_iter = np.lib.Arrayterator(AR_i8)

np.lib.Arrayterator(np.int64()) # E: incompatible type
ar_iter.shape = (10, 5) # E: is read-only
ar_iter[None] # E: Invalid index type
ar_iter[None, 1] # E: Invalid index type
ar_iter[np.intp()] # E: Invalid index type
ar_iter[np.intp(), ...] # E: Invalid index type
ar_iter[AR_i8] # E: Invalid index type
ar_iter[AR_i8, :] # E: Invalid index type
np.lib.Arrayterator(np.int64()) # type: ignore[arg-type] # pyright: ignore[reportArgumentType]
ar_iter.shape = (10, 5) # type: ignore[misc] # pyright: ignore[reportAttributeAccessIssue]
ar_iter[None] # type: ignore[index] # pyright: ignore[reportArgumentType]
ar_iter[None, 1] # type: ignore[index] # pyright: ignore[reportArgumentType]
ar_iter[np.intp()] # type: ignore[index] # pyright: ignore[reportArgumentType]
ar_iter[np.intp(), ...] # type: ignore[index] # pyright: ignore[reportArgumentType]
ar_iter[AR_i8] # type: ignore[index] # pyright: ignore[reportArgumentType]
ar_iter[AR_i8, :] # type: ignore[index] # pyright: ignore[reportArgumentType]
35 changes: 22 additions & 13 deletions test/static/reject/bitwise_ops.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,31 @@ from typing import Final

import numpy as np

i8: Final[np.int64] = ...
i0: Final[int] = ...

b1: Final[np.bool] = ...
i4: Final[np.int32] = ...
i8: Final[np.int64] = ...
u8: Final[np.uint64] = ...
b_: Final[np.bool] = ...
i: Final[int] = 0
f8: Final[np.float64] = ...

f8 = np.float64()
###

b_ >> f8 # E: No overload variant
i8 << f8 # E: No overload variant
i | f8 # E: Unsupported operand types
i8 ^ f8 # E: No overload variant
u8 & f8 # E: No overload variant
~f8 # E: Unsupported operand type
# TODO: Certain mixes like i4 << u8 go to float and thus should fail

# mypys' error message for `NoReturn` is unfortunately pretty bad
# TODO: Re-enable this once we add support for numerical precision for `number`s
# a = u8 | 0 # E: Need type annotation
~f8 # type: ignore[operator] # pyright: ignore[reportOperatorIssue]

b1 >> f8 # type: ignore[call-overload] # pyright: ignore[reportOperatorIssue]
f8 >> b1 # type: ignore[call-overload] # pyright: ignore[reportOperatorIssue]

i8 << f8 # type: ignore[call-overload] # pyright: ignore[reportOperatorIssue]
f8 << i8 # type: ignore[call-overload] # pyright: ignore[reportOperatorIssue]

f8 | i0 # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
i0 | f8 # type: ignore[operator] # pyright: ignore[reportOperatorIssue]

f8 ^ i8 # type: ignore[call-overload] # pyright: ignore[reportOperatorIssue]
i8 ^ f8 # type: ignore[call-overload] # pyright: ignore[reportOperatorIssue]

f8 & u8 # type: ignore[call-overload] # pyright: ignore[reportOperatorIssue]
u8 & f8 # type: ignore[call-overload] # pyright: ignore[reportOperatorIssue]
Loading