For context, I’m looking at a typing issue from the attrs issue tracker. This is something that (I’m somewhat sure) used to work on both pyright and mypy, but no longer does. The issue reporter also asked pyright for their opinion.
The enum
standard library module is very useful for creating singletons - a common pattern is (was?) to create a single member enum, and alias that member at module scope to something friendly. Users almost wouldn’t even need to know an enum was involved, they would just import the member.
Here’s a short snippet directly from attrs:
import enum
class _Nothing(enum.Enum):
NOTHING = enum.auto()
NOTHING = _Nothing.NOTHING
Then, this could be used in a function signature like this:
from attrs import NOTHING
def f(a: str | Literal[NOTHING] = NOTHING):
....
Like I mentioned, at a certain point this stopped working. Both mypy and pyright claim that NOTHING
is a variable, and so unsuitable for use with Literal
. Which makes sense. So I tried changing the code to:
NOTHING: Final = _Nothing.NOTHING
Now NOTHING
is definitely not a variable - it’s supposed to just be an alias to _Nothing.NOTHING
. I’d expect, since Literal[_Nothing.NOTHING]
is valid, Literal[NOTHING]
would be valid too (since it’s equivalent to _Nothing.NOTHING
). To my surprise, this doesn’t seem to be the case.
From what I can tell, it’s not really possible to “alias”/“mirror” enum members directly to module scope any more and keep their full functionality (like use in literals). This is unfortunate with regards to API ergonomics. It’s not just attrs, combining enums (and literals of enum members) in unions with other types is a nifty feature for advanced data modeling.
Can we get Final
to make this possible again?