ty_python_semantic: add snapshot tests for existing union function type diagnostics

This is just capturing the status quo so that we can better see the
changes. I took these tests from the (now defunct) PR #17959.
This commit is contained in:
Andrew Gallant 2025-05-09 07:51:26 -04:00 committed by Andrew Gallant
parent e9da1750a1
commit 90272ad85a
5 changed files with 345 additions and 0 deletions

View file

@ -0,0 +1,121 @@
# Calling a union of function types
<!-- snapshot-diagnostics -->
```toml
[environment]
python-version = "3.12"
```
## A smaller scale example
```py
def f1() -> int:
return 0
def f2(name: str) -> int:
return 0
def _(flag: bool):
if flag:
f = f1
else:
f = f2
# error: [too-many-positional-arguments]
x = f(3)
```
## Multiple variants but only one is invalid
This test in particular demonstrates some of the smarts of this diagnostic. Namely, since only one
variant is invalid, additional context specific to that variant is added to the diagnostic output.
(If more than one variant is invalid, then this additional context is elided to avoid overwhelming
the end user.)
```py
def f1(a: int) -> int:
return 0
def f2(name: str) -> int:
return 0
def _(flag: bool):
if flag:
f = f1
else:
f = f2
# error: [invalid-argument-type]
x = f(3)
```
## Try to cover all possible reasons
These tests is likely to become stale over time, but this was added when the union-specific
diagnostic was initially created. In each test, we try to cover as much as we can. This is mostly
just ensuring that we get test coverage for each of the possible diagnostic messages.
### Cover non-keyword related reasons
```py
from inspect import getattr_static
def f1() -> int:
return 0
def f2(name: str) -> int:
return 0
def f3(a: int, b: int) -> int:
return 0
def f4[T: str](x: T) -> int:
return 0
class OverloadExample:
def f(self, x: str) -> int:
return 0
f5 = getattr_static(OverloadExample, "f").__get__
def _(n: int):
class PossiblyNotCallable:
if n == 0:
def __call__(self) -> int:
return 0
if n == 0:
f = f1
elif n == 1:
f = f2
elif n == 2:
f = f3
elif n == 3:
f = f4
elif n == 4:
f = 5
elif n == 5:
f = f5
else:
f = PossiblyNotCallable()
# error: [too-many-positional-arguments]
x = f(3)
```
### Cover keyword argument related reasons
```py
def any(*args, **kwargs) -> int:
return 0
def f1(name: str) -> int:
return 0
def _(n: int):
if n == 0:
f = f1
else:
f = any
# error: [parameter-already-assigned]
# error: [unknown-argument]
y = f("foo", name="bar", unknown="quux")
```

View file

@ -0,0 +1,43 @@
---
source: crates/ty_test/src/lib.rs
expression: snapshot
---
---
mdtest name: union_call.md - Calling a union of function types - A smaller scale example
mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/union_call.md
---
# Python source files
## mdtest_snippet.py
```
1 | def f1() -> int:
2 | return 0
3 |
4 | def f2(name: str) -> int:
5 | return 0
6 |
7 | def _(flag: bool):
8 | if flag:
9 | f = f1
10 | else:
11 | f = f2
12 | # error: [too-many-positional-arguments]
13 | x = f(3)
```
# Diagnostics
```
error: lint:too-many-positional-arguments: Too many positional arguments to function `f1`: expected 0, got 1
--> src/mdtest_snippet.py:13:11
|
11 | f = f2
12 | # error: [too-many-positional-arguments]
13 | x = f(3)
| ^
|
info: `lint:too-many-positional-arguments` is enabled by default
```

View file

@ -0,0 +1,52 @@
---
source: crates/ty_test/src/lib.rs
expression: snapshot
---
---
mdtest name: union_call.md - Calling a union of function types - Multiple variants but only one is invalid
mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/union_call.md
---
# Python source files
## mdtest_snippet.py
```
1 | def f1(a: int) -> int:
2 | return 0
3 |
4 | def f2(name: str) -> int:
5 | return 0
6 |
7 | def _(flag: bool):
8 | if flag:
9 | f = f1
10 | else:
11 | f = f2
12 | # error: [invalid-argument-type]
13 | x = f(3)
```
# Diagnostics
```
error: lint:invalid-argument-type: Argument to this function is incorrect
--> src/mdtest_snippet.py:13:11
|
11 | f = f2
12 | # error: [invalid-argument-type]
13 | x = f(3)
| ^ Expected `str`, found `Literal[3]`
|
info: Function defined here
--> src/mdtest_snippet.py:4:5
|
2 | return 0
3 |
4 | def f2(name: str) -> int:
| ^^ --------- Parameter declared here
5 | return 0
|
info: `lint:invalid-argument-type` is enabled by default
```

View file

@ -0,0 +1,57 @@
---
source: crates/ty_test/src/lib.rs
expression: snapshot
---
---
mdtest name: union_call.md - Calling a union of function types - Try to cover all possible reasons - Cover keyword argument related reasons
mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/union_call.md
---
# Python source files
## mdtest_snippet.py
```
1 | def any(*args, **kwargs) -> int:
2 | return 0
3 |
4 | def f1(name: str) -> int:
5 | return 0
6 |
7 | def _(n: int):
8 | if n == 0:
9 | f = f1
10 | else:
11 | f = any
12 | # error: [parameter-already-assigned]
13 | # error: [unknown-argument]
14 | y = f("foo", name="bar", unknown="quux")
```
# Diagnostics
```
error: lint:parameter-already-assigned: Multiple values provided for parameter `name` of function `f1`
--> src/mdtest_snippet.py:14:18
|
12 | # error: [parameter-already-assigned]
13 | # error: [unknown-argument]
14 | y = f("foo", name="bar", unknown="quux")
| ^^^^^^^^^^
|
info: `lint:parameter-already-assigned` is enabled by default
```
```
error: lint:unknown-argument: Argument `unknown` does not match any known parameter of function `f1`
--> src/mdtest_snippet.py:14:30
|
12 | # error: [parameter-already-assigned]
13 | # error: [unknown-argument]
14 | y = f("foo", name="bar", unknown="quux")
| ^^^^^^^^^^^^^^
|
info: `lint:unknown-argument` is enabled by default
```

View file

@ -0,0 +1,72 @@
---
source: crates/ty_test/src/lib.rs
expression: snapshot
---
---
mdtest name: union_call.md - Calling a union of function types - Try to cover all possible reasons - Cover non-keyword related reasons
mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/union_call.md
---
# Python source files
## mdtest_snippet.py
```
1 | from inspect import getattr_static
2 |
3 | def f1() -> int:
4 | return 0
5 |
6 | def f2(name: str) -> int:
7 | return 0
8 |
9 | def f3(a: int, b: int) -> int:
10 | return 0
11 |
12 | def f4[T: str](x: T) -> int:
13 | return 0
14 |
15 | class OverloadExample:
16 | def f(self, x: str) -> int:
17 | return 0
18 |
19 | f5 = getattr_static(OverloadExample, "f").__get__
20 |
21 | def _(n: int):
22 | class PossiblyNotCallable:
23 | if n == 0:
24 | def __call__(self) -> int:
25 | return 0
26 |
27 | if n == 0:
28 | f = f1
29 | elif n == 1:
30 | f = f2
31 | elif n == 2:
32 | f = f3
33 | elif n == 3:
34 | f = f4
35 | elif n == 4:
36 | f = 5
37 | elif n == 5:
38 | f = f5
39 | else:
40 | f = PossiblyNotCallable()
41 | # error: [too-many-positional-arguments]
42 | x = f(3)
```
# Diagnostics
```
error: lint:too-many-positional-arguments: Too many positional arguments to function `f1`: expected 0, got 1
--> src/mdtest_snippet.py:42:11
|
40 | f = PossiblyNotCallable()
41 | # error: [too-many-positional-arguments]
42 | x = f(3)
| ^
|
info: `lint:too-many-positional-arguments` is enabled by default
```