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

mypy treats enum fields as enum members #16730

Closed
rlazarus opened this issue Jan 2, 2024 · 1 comment · Fixed by #17207
Closed

mypy treats enum fields as enum members #16730

rlazarus opened this issue Jan 2, 2024 · 1 comment · Fixed by #17207
Labels
bug mypy got something wrong topic-enum

Comments

@rlazarus
Copy link

rlazarus commented Jan 2, 2024

Bug Report

When Enum members have a field set in the Enum's __init__ method, mypy exhaustiveness checking incorrectly considers that field to be a member of the Enum, and therefore a possible value.

To Reproduce

Using the Planet example from the enum documentation:

https://mypy-play.net/?mypy=1.8.0&python=3.12&gist=8efc534dda9e5cb62e4ff9f7aff7f5e6

from enum import Enum
from typing import assert_never

class Planet(Enum):
    MERCURY = (3.303e+23, 2.4397e6)
    VENUS   = (4.869e+24, 6.0518e6)
    EARTH   = (5.976e+24, 6.37814e6)
    MARS    = (6.421e+23, 3.3972e6)
    JUPITER = (1.9e+27,   7.1492e7)
    SATURN  = (5.688e+26, 6.0268e7)
    URANUS  = (8.686e+25, 2.5559e7)
    NEPTUNE = (1.024e+26, 2.4746e7)
    def __init__(self, mass, radius):
        self.mass = mass       # in kilograms
        self.radius = radius   # in meters

def foo(p: Planet) -> None:
    match p:
        case Planet.MERCURY|Planet.VENUS|Planet.EARTH|Planet.MARS|Planet.JUPITER|Planet.SATURN|Planet.URANUS|Planet.NEPTUNE:
            pass
        case _:
            assert_never(p)  # mypy error here

Expected Behavior

All members of the enum are represented in match cases, so the exhaustiveness check should pass. I expect no mypy errors.

Actual Behavior

main.py:22: error: Argument 1 to "assert_never" has incompatible type "Literal[Planet.mass, Planet.radius]"; expected "NoReturn"  [arg-type]
Found 1 error in 1 file (checked 1 source file)

Planet.mass is not an enum member, so Literal[Planet.mass] is not a possible type for p. In fact, evaluating Planet.mass raises AttributeError. Only an expression like Planet.EARTH.mass is allowed. Same for radius.

Your Environment

  • Mypy version used: 1.8.0
  • Mypy command-line flags: none
  • Mypy configuration options from mypy.ini (and other config files): none
  • Python version used: 3.12
@rlazarus rlazarus added the bug mypy got something wrong label Jan 2, 2024
@rlazarus
Copy link
Author

rlazarus commented Jan 2, 2024

Here's a shorter example, same bug with less code:

from enum import Enum
from typing import assert_never

class Color(Enum):
    RED = ('stop,')
    GREEN = ('go',)
    def __init__(self, signal):
        self.signal = signal

def foo(c: Color) -> None:
    match c:
        case Color.RED | Color.GREEN:
             pass
        case _:
            assert_never(c)  # mypy error here

https://mypy-play.net/?mypy=1.8.0&python=3.12&gist=1940cd24ab1da3b82e23b4d1c16e29e2

main.py:15: error: Argument 1 to "assert_never" has incompatible type "Literal[Color.signal]"; expected "NoReturn"  [arg-type]

I just wanted to use Planet in the bug report since it's straight out of the documentation -- to show there's no funny business in the enum itself.

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
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants