python / mypy

Optional static typing for Python
https://www.mypy-lang.org/
Other
18.55k stars 2.84k forks source link

(🐞) `TypeGuard` is applied to the `self` argument when passed explicitly #16146

Closed KotlinIsland closed 1 year ago

KotlinIsland commented 1 year ago
from typing import TypeGuard
class A:
    def f(self, a: object) -> TypeGuard[int]:
       return True

a = A()

b: object
assert a.f(b)
reveal_type(a)  # A
reveal_type(b)  # int

c: object
assert A.f(a, c)
reveal_type(a)  # int
reveal_type(c)  # object

PEP doesn't cover this case, but it is obviously incorrect.

KotlinIsland commented 1 year ago

@AlexWaygood

Can you delete / report this AI spam comment.

https://github.com/python/mypy/issues/16146#issuecomment-1730198641

AlexWaygood commented 1 year ago

@AlexWaygood

Can you delete / report this AI spam comment.

#16146 (comment)

Sadly not; I'm not a maintainer at mypy, and editing/deleting comments requires more than my triage privileges. Otherwise I would.

JelleZijlstra commented 1 year ago

Reported and deleted the comment, will hide your comments and mine as off-topic.

eli-schwartz commented 1 year ago

PEP doesn't cover this case, but it is obviously incorrect.

Isn't it? The PEP says that narrowing will be performed on the first explicit argument passed to the TypeGuard function, and that is the explicitly passed self on an instance method accessed via its class.

It's not a very good TypeGuard since it can just be a freestanding function, but it does seem to be PEP compliant...

erictraut commented 1 year ago

This code sample uses a user-defined type guard function in a manner for which it wasn't designed and I wouldn't recommend. That said, I think that mypy is behaving correctly here and is in compliance with PEP 647, so I don't consider this a bug. Note: I'm the author of PEP 647.

The PEP says that the expression passed as the first positional argument to the call should be narrowed. In your example, the first positional argument in the call expression A.f(a, c) is a. Mypy behaving in accordance with the text of the PEP. It's also working consistently with pyright, which is the reference implementation for PEP 647.

KotlinIsland commented 1 year ago

BTW this was resolved (among other typeguard issues) in basedmypy 2.2.0

playground

docs