admin管理员组

文章数量:1291221

pyright seems to expect a name of the parameter in a Callable when using assert_type

For such code:

from typing import assert_type
from collections.abc import Callable
def tuple_of_nums(n: int) -> tuple[int,...]:
    return tuple(range(n))
assert_type(tuple_of_nums, Callable[[int], tuple[int,...]])

running pyright file.py yields:

file.py:5:13 - error: "assert_type" mismatch: expected "(int) -> tuple[int, ...]" but received "(n: int) -> tuple[int, ...]" (reportAssertTypeFailure)

The only difference being n: in the received function.

How do I make this type assertion work?

pyright seems to expect a name of the parameter in a Callable when using assert_type

For such code:

from typing import assert_type
from collections.abc import Callable
def tuple_of_nums(n: int) -> tuple[int,...]:
    return tuple(range(n))
assert_type(tuple_of_nums, Callable[[int], tuple[int,...]])

running pyright file.py yields:

file.py:5:13 - error: "assert_type" mismatch: expected "(int) -> tuple[int, ...]" but received "(n: int) -> tuple[int, ...]" (reportAssertTypeFailure)

The only difference being n: in the received function.

How do I make this type assertion work?

Share Improve this question edited Feb 13 at 16:58 jonrsharpe 122k30 gold badges267 silver badges474 bronze badges asked Feb 13 at 16:55 VulwsztynVulwsztyn 2,2711 gold badge14 silver badges23 bronze badges 9
  • 3 Make n positional-only: def tuple_of_nums(n: int, /) -> tuple[int, ...]: .... I'll look for a dupe. – InSync Commented Feb 13 at 16:59
  • 1 Relevant python discuss page: discuss.python./t/… – STerliakov Commented Feb 13 at 17:02
  • 1 Ough, sorry, pyright playground took so long to check that I thought pyright also accepted this snippet. Then you're probably out of luck - only posonly args can work with Callable and assert_type with pyright, and protocols don't seem to work at all. – STerliakov Commented Feb 13 at 17:08
  • 1 @InSync let's keep this open - assert_type isn't strictly about subtyping, but requires exact match. And the problem in question is the opposite anyway: this def is assignable to Callable[[int], something], because it can be called with one positional arg of type int, so assert_type would have passed if it were to follow subtyping relationships. – STerliakov Commented Feb 13 at 18:40
  • 1 @STerliakov Agree. None of the questions I found actually have a truly good answer: they don't explain the implementation-defined semantics of assert_type(). – InSync Commented Feb 13 at 19:01
 |  Show 4 more comments

1 Answer 1

Reset to default 2

There are two reasons for this.

First, the asserted signature (int) -> tuple[int, ...] only allows the lone argument to be passed in positionally, but the actual signature (n: int) -> tuple[int, ...] allows it to be passed as n as well, which causes a difference in arity.

Second, assert_type()'s semantics are not standardized. Here's everything what the specs have to say about it, save for an example (emphasis mine):

The function typing.assert_type(val, typ) allows users to ask a static type checker to confirm that val has an inferred type of typ.

When a type checker encounters a call to assert_type(), it should emit an error if the value is not of the specified type[.]

Neither the exact algorithm assert_type() should follow nor type inference is standardized, and so different type checkers might handle assert_type() differently.

In this case, the type checker is Pyright, and it checks for equivalency (or, more precisely, gradual equivalency) rather than assignability.

本文标签: pythonasserttype with callableStack Overflow