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

Tagged unions don't work with Enums #12432

Closed
hackaugusto opened this issue Mar 23, 2022 · 3 comments
Closed

Tagged unions don't work with Enums #12432

hackaugusto opened this issue Mar 23, 2022 · 3 comments
Labels
bug mypy got something wrong topic-enum topic-type-narrowing Conditional type narrowing / binder

Comments

@hackaugusto
Copy link
Contributor

hackaugusto commented Mar 23, 2022

Bug Report

With the example below, the second if doesn't properly narrow the type, it works fine if the Literal['b'] instead of the enum version.

To Reproduce

from queue import Queue
from typing import Literal, TypedDict, Union
from enum import Enum, unique

@unique
class Tag(Enum):
    a = 'a'
    b = 'b'

class OpA(TypedDict):
    tag: Literal[Tag.a]
    a: str

class OpB(TypedDict):
    tag: Literal[Tag.b]
    b: str

Ops = Union[OpA, OpB]

def do(op: Ops):
    if op['tag'] == Tag.a:
        reveal_type(op)
    if op['tag'] == Tag.b:
        reveal_type(op)

Expected Behavior

    if op['tag'] == Tag.b:
        reveal_type(op)

Should report:

t.py:24: note: Revealed type is "TypedDict('t.OpB', {'tag': Literal[t.Tag.b], 'b': builtins.str})"

Actual Behavior

Reported type is:

t.py:24: note: Revealed type is "Union[TypedDict('t.OpA', {'tag': Literal[t.Tag.a], 'a': builtins.str}), TypedDict('t.OpB', {'tag': Literal[t.Tag.b], 'b': builtins.str})]"

Your Environment

  • Mypy version(s) used: mypy 0.910, mypy 0.941, mypy 0.950+dev.fd8a15e1abdd2bb4f75c3a6319ebfba233e1fe8e (compiled: no)
  • Mypy command-line flags: mypy t.py
  • Mypy configuration options from mypy.ini (and other config files): nothing
  • Python version used: Python 3.10.2
  • Operating system and version: Fedora Linux 35
@hackaugusto hackaugusto added the bug mypy got something wrong label Mar 23, 2022
@AlexWaygood
Copy link
Member

AlexWaygood commented Mar 23, 2022

Although narrowing using == is completely valid, and mypy is indeed incorrect here, the more idiomatic way to compare enum values is using is rather than ==. If you use is instead of ==, mypy understands your code flow as you'd expect (mypy playground link here).

You'd just rewrite your do function like so:

def do(op: Ops):
    if op['tag'] is Tag.a:
        reveal_type(op)
    if op['tag'] is Tag.b:
        reveal_type(op)

@AlexWaygood
Copy link
Member

With regard to mypy not understanding enum narrowing using ==, there's already an open PR by @hauntsaninja to fix that: #11521

@JelleZijlstra JelleZijlstra added the topic-type-narrowing Conditional type narrowing / binder label Mar 23, 2022
@AlexWaygood
Copy link
Member

Closing as a duplicate of #10915

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-enum topic-type-narrowing Conditional type narrowing / binder
Projects
None yet
Development

No branches or pull requests

3 participants