python / python/mypy

Narrowing enums causes `.value` to be typed as `Any`

Open
#14,092 5 comments 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug topic-enum
Dominant language
Python
Stars
20.6k
Forks
3.3k
PR merge metrics
PR metrics pending

Description

Bug Report

Apologies if this has already been reported, but I couldn't find an existing issue for it.

The issue I'm seeing is related to accessing the .value of an Enum after "narrowing" it with the is operator. It seems like the narrowing (to Union[Literal[...]]) works as expected, but then it fails to realize that the .value of all the variants have the same type (and so falls back to Any).

This only affects runs with --warn-return-any enabled:

$ mypy --config-file /dev/null --warn-return-any enum_narrowing.py

To Reproduce

It's probably easiest to see in this example:

import enum
from typing import Tuple

RGB = Tuple[int, int, int]

class Color(enum.Enum):
    WHITE = (255, 255, 255)
    BLACK = (0, 0, 0)

    def red(self) -> int:
        if self is Color.WHITE:
            return 255
        return self.value[0]  # error: Returning Any from function declared to return "int"

(playground URL: https://mypy-play.net/?mypy=latest&python=3.8&flags=warn-return-any&gist=b2a6df92fb37717e5c9d7542b6e88fec)

Expected Behavior

This should deduce that self.value has type RGB and succeed.

Actual Behavior

If I add some reveal_type(self) and reveal_type(self.value)s before/after the narrowing, I get this output:

enum_narrowing.py:11: note: Revealed type is "enum_narrowing.Color"
enum_narrowing.py:12: note: Revealed type is "Tuple[Literal[255]?, Literal[255]?, Literal[255]?]"
enum_narrowing.py:15: note: Revealed type is "Literal[enum_narrowing.Color.BLACK]"
enum_narrowing.py:16: note: Revealed type is "Any"

Your Environment

$ python --version
Python 3.8.0
$ mypy --version
mypy 0.991 (compiled: yes)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by running the provided mypy command against enum_narrowing.py and compare the revealed types before and after the is narrowing. Trace the enum-member narrowing and .value type handling; the fix is complete when self.value[0] is inferred as an int and the example passes with --warn-return-any.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.