Treat Literal of all elements of enum equal to the enum in type annotations

Would it be reasonable to define in the typing specification that that a literal of all elements of an enum should be treated equally to the enum itself in type annotations?

For example:

import enum
import typing as t

class Importance(enum.IntEnum):
    LOW = 1
    MEDIUM = 2
    HIGH = 3

type AllT = t.Literal[Importance.LOW, Importance.MEDIUM, Importance.HIGH]

class Task[T: Importance]:
    ...

def manage_task(task: Task[AllT]) -> t.Any:
    ...

task: Task[Importance] = ...

manage_task(task)  # error

This function call would currently show a typing error. Obviously this example is made up and not too sensical but you get the gist.

Would defining this make sense or are there reasons to not allow this?

Yes, type checkers should already do this. Both the type Importance and the type Literal[Importance.LOW, Importance.MEDIUM, Importance.HIGH] contain the same values and therefore should be treated as equivalent under the typing spec.

Checking in multiplay: ty, pyrefly, mypy, and pycroscope already accept your program. Pyright and zuban do not; that’s best seen as a bug in those type checkers.

2 Likes

Ah perfect okay then I will create an issue in Pyright for this!

I was curious so I checked the references in typing specification and it’s indeed explicitly spelled out in #enum-literal-expansion.

Likewise, a type checker should treat a complete union of all literal members as equivalent to the enum type:

With that called out specially in the spec I would have guessed it was included in the conformance test-suite :thinking:. (I’ll probably check and dig a bit deeper).

I think it makes sense to add this case to the conformance suite, yes.

I will add an issue there. I did some checks and there were indeed a check but only when returning a parameterized type, not as accepting it as an argument.

I posted an issue to typing here.