Skip to content

[1.16 regression] no longer recognizes enum singleton as only possible case #19271

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

Closed
gwk opened this issue Jun 10, 2025 · 4 comments · Fixed by #19273
Closed

[1.16 regression] no longer recognizes enum singleton as only possible case #19271

gwk opened this issue Jun 10, 2025 · 4 comments · Fixed by #19273
Labels
bug mypy got something wrong topic-enum

Comments

@gwk
Copy link

gwk commented Jun 10, 2025

I have an enum class Raise that has a single member, Raise._. I use this as a pattern to indicate that a function argument, if not specified, will default to raising an exception. Essentially it serves as an alternative to None, which a caller might want to explicitly pass. The following used to work in 1.15 but 1.16 complains.

from enum import Enum
from os import environ
from typing import final, TypeVar, Union


@final # 1.16 fails with or without this.
class Raise(Enum):
  '''
  A singleton value to indicate that the default behavior is to raise an exception.
  '''
  _ = 0


def get_some_config_val(default:str|Raise=Raise._) -> str:
  '''
  Get some config value or return the default. If default is not specified,
  then raise an exception.
  '''
  try:
    return environ['SOME_CONFIG_VAL']
  except KeyError:
    if default is Raise._: raise
    return default

In 1.15 it appears that that mypy understood that Raise._ was the only value of type Raise. In 1.16 that returns error: Incompatible return value type (got "str | Raise", expected "str") [return-value].

Note that originally I did not have the @final decoration. After some reading I am unsure whether or not it should be required for this example to work, but it does not seem to affect the behavior of either 1.15 or 1.16. It would seem that the @Final should be necessary for mypy to recognize that Raise._ is the only possible value of type Raise, unless it was proving to itself that there is no subclass of Raise.

Obviously, I can change the implementation to if is instance(Raise._, Raise): raise, but there is an apparent loss of sophistication in 1.16 so I thought it was worth reporting.

Python 3.13.3
mypy 1.16.0 (compiled: yes)
@gwk gwk added the bug mypy got something wrong label Jun 10, 2025
@brianschubert
Copy link
Collaborator

Bisects to #18675, cc @sobolevn

@hauntsaninja hauntsaninja changed the title Possible 1.16 regression: no longer recognizes enum singleton as only possible case [1.16 regression] no longer recognizes enum singleton as only possible case Jun 10, 2025
@sterliakov
Copy link
Collaborator

Wow, and this is rather important - such enums are commonly used as sentinel values, like SENTINEL = object() but with type checker support. I'm surprised none of our tests have identified this regression.

@A5rocks
Copy link
Collaborator

A5rocks commented Jun 11, 2025

Wow, and this is rather important - such enums are commonly used as sentinel values, like SENTINEL = object() but with type checker support. I'm surprised none of our tests have identified this regression.

This is only for things named _

Note that originally I did not have the @final decoration. After some reading I am unsure whether or not it should be required for this example to work, but it does not seem to affect the behavior of either 1.15 or 1.16.

No, you cannot subclass enums with members. Enums are implicitly final.

@sterliakov
Copy link
Collaborator

@A5rocks Ough, I haven't noticed that this only happens for members named literally _. Nice catch! I wouldn't have tried to rename the member.

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.

4 participants