Skip to content

Enum member aliases are treated as never-equal #16830

Open
@finite-state-machine

Description

@finite-state-machine

Bug Report

Elements/members of an Enum which have the same value (aliases or duplicate values) are treated as never-equal in mypy.

To Reproduce

mypy-play.net gist

# run with: --strict-equality --warn-unreachable
from __future__ import annotations
from enum import *

class TrafficLight(Enum):

    RED = auto()
    AMBER = auto()  # (term often used in law)
    GREEN = auto()

    YELLOW = AMBER  # alias (used in everyday language)


def demo1(inst: TrafficLight) -> None:

    if inst is TrafficLight.AMBER:
        reveal_type(inst)  # mypy: ≈ Literal[AMBER]  (ok)
    else:
        reveal_type(inst)  # mypy: ≈ Literal[RED, GREEN, YELLOW]
                           # expected ≈ Literal[RED, GREEN]

def demo2() -> None:

    if TrafficLight.AMBER is TrafficLight.YELLOW:
            # this is true at runtime, but...
            # mypy: Non-overlapping identity check (
            #           left operand type: "Literal[TrafficLight.AMBER]",
            #           right operand type: "Literal[TrafficLight.YELLOW]"
            #           )
            #       [comparison-overlap]
            # expected: (no error)
        _ = True  # mypy: [unreachable]
                  # expected: (no error)
    else:
        _ = True  # mypy: (no error)
                  # expected: [unreachable]

Expected Behavior

The tool should ideally understand that TrafficLight.AMBER is indistinguishable from TrafficLight.YELLOW, and that the latter is an alias of the former.

The tool should not issue a false positive under the incorrect assumption that Enum members always have distinct values.

Actual Behavior

The tool assumes (incorrectly) that YELLOW and AMBER are never equal or the same.

Your Environment

  • Mypy version used: 1.8.0
  • Mypy command-line flags: --strict-equality --warn-unreachable
  • Mypy configuration options from mypy.ini (and other config files): none
  • Python version used: 3.8, 3.12

Existing bugs

None were found, open or closed, using the search terms (enum alias) and (enum duplicate).

Specifications and runtime behaviour

https://docs.python.org/3/howto/enum.html#duplicating-enum-members-and-values

[A]n enum member can have other names associated with it. Given two entries A and B with the same value (and A defined first), B is an alias for the member A. By-value lookup of the value of A will return the member A. By-name lookup of A will return the member A. By-name lookup of B will also return the member A[.]

At runtime, two Enum elements with the same value, retrieved using dot-notation (attribute lookup), are exactly the same object.

Motivation

In my use case, the Enum describes various scaled units (second, millisecond, microsecond, etc.); one of these is the "fundamental unit" in which quantities are stored (as an unqualified numeric value), while the others are converted to and from that unit by the read() and write() functions. The Enum defines the fundamental unit twice, first as NANOSECOND with FUNDAMENTAL as an alias. Since the fundamental unit could change, the alias is useful.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions