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

TypeGuard does not narrow when assignment expression #17088

Open
roganov opened this issue Apr 2, 2024 · 4 comments
Open

TypeGuard does not narrow when assignment expression #17088

roganov opened this issue Apr 2, 2024 · 4 comments
Labels
bug mypy got something wrong topic-pep-572 PEP 572 (walrus operator) topic-typeguard TypeGuard / PEP 647

Comments

@roganov
Copy link

roganov commented Apr 2, 2024

Bug Report

In the example below, is_str is a type guard, but when used mypy fails to narrow the type. I'm pretty sure this happens because of the assignment expression.

To Reproduce
https://mypy-play.net/?mypy=latest&python=3.12&gist=42da00a72ace0a51a5d2335721877591

import typing

s: str | int


def is_str(x: str | int) -> typing.TypeGuard[str]:
    return bool(
        isinstance(x, str)
        and (y if len(y := '123'.split('/')) > 1 else '')
    )


if is_str(s):
    s + ''

Expected Behavior
No mypy errors.

Actual Behavior

main.py:14: error: Unsupported operand types for + ("int" and "str") [operator]
main.py:14: note: Left operand is of type "str | int"
Found 1 error in 1 file (checked 1 source file)

Your Environment

  • Mypy version used: 1.19
  • Mypy command-line flags: non
  • Mypy configuration options from mypy.ini (and other config files): non
  • Python version used: 3.12
@roganov roganov added the bug mypy got something wrong label Apr 2, 2024
@AlexWaygood AlexWaygood added the topic-typeguard TypeGuard / PEP 647 label Apr 2, 2024
@AlexWaygood
Copy link
Member

This is really weird. Here's a slightly more minimal repro:

import typing

s: str | int


def is_str(x: str | int) -> typing.TypeGuard[str]:
    return y if (y := False) else False


if is_str(s):
    s + ''

https://mypy-play.net/?mypy=latest&python=3.12&gist=592d718662024c2496121bd58e85f5fd

@AlexWaygood AlexWaygood added the topic-pep-572 PEP 572 (walrus operator) label Apr 2, 2024
@JelleZijlstra
Copy link
Member

This also reproduces it:

import typing

s: str | int


def is_str(x: str | int) -> typing.TypeGuard[str]:
    return y


if is_str(s):
    s + ''

Or

def is_str(x: str | int) -> typing.TypeGuard[str]:
    return True + "x"

It (correctly) emits an error inside the TypeGuard, but then also disables the TypeGuard.

@AlexWaygood
Copy link
Member

So there's two bugs here:

  1. Mypy gets confused about a typeguard function that returns a boolean conditions if the boolean condition involves a walrus expression. It thinks that it's an invalid typeguard function when it should see it as valid.
  2. If mypy sees something it deems to be an invalid typeguard function, the error "leaks" out to places where the typeguard function is called, when mypy should just emit an error at the location where the typeguard function is originally defined.

@jaycle
Copy link

jaycle commented Apr 5, 2024

I just opened #17104, but looking at comments, they may be related.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong topic-pep-572 PEP 572 (walrus operator) topic-typeguard TypeGuard / PEP 647
Projects
None yet
Development

No branches or pull requests

4 participants