Description
I've encountered cases where the changes from int
to a literal type in stubs causes regressions for mypy users. Here's one (simplified) example:
import logging
class C:
def __init__(self) -> None:
self.level = logging.INFO
def enable_debug(self) -> None:
# Error: expression has type "Literal[10]", variable has type "Literal[20]"
self.level = logging.DEBUG
Here's another example:
import logging
class Base:
level = logging.INFO
class Derived(Base):
level = logging.DEBUG # Error -- incompatible with base class
Previously the types were int
, so no errors were generated. The code in the above examples doesn't look buggy to me, and the behavior of mypy also seems as expected.
There could well be other problematic cases like this. Having more precise types is generally useful, but in the case of literal types, the regressions such as the above may make them not worth the potential false positives (which are hard to predict, since in most use cases literal types are fine). I wonder if there are concrete examples where the literal types bring concrete benefits that could offset the false positives.
There were several false positives like the above in a big internal codebase when using a recent typeshed. Working around the issues is simple by annotating the attributes as int
, but this could be quite non-obvious for non-expert users who aren't familiar with literal types (a somewhat advanced typing feature).
Thoughts? I'm leaning towards preferring to only use literal types when there is a concrete use cases where they help, since the fallout from using them seems difficult to predict.