Description
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)