Type-checking generic of enum.Meta with a custom metaclass fails with code that runs, and passes with code that doesn't run.
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 20.6k
- Forks
- 3.3k
- PR merge metrics
- PR metrics pending
Description
Bug Report
Trying to type-check generic types of a bound enum.Enum (with a custom metaclass) only catches type errors when the actual code fails to run; but doesn't detect the issues when the code runs.
To Reproduce
The code in this gist properly detects the type error while calling Carrier(Foo, Bar.item1):
import enum
from dataclasses import dataclass
from typing import TypeVar, Generic, Type
M = TypeVar('M', bound="MyEnum")
class Meta(enum.EnumMeta):
pass
class MyEnum(metaclass=Meta):
...
class Foo(enum.Enum, MyEnum):
item1 = "1"
item2 = "2"
class Bar(enum.Enum, MyEnum):
item1 = "1"
item2 = "2"
@dataclass
class Carrier(Generic[M]):
meta: Type[M]
instance: M
Carrier(Foo, Foo.item1)
Carrier(Foo, Bar.item1) # should fail
However that code fails to run with
Traceback (most recent call last):
File "/home/manu/src/tmp/enums.py", line 14, in <module>
class Foo(enum.Enum, MyEnum):
File "/usr/lib/python3.10/enum.py", line 173, in __prepare__
member_type, first_enum = metacls._get_mixins_(cls, bases)
File "/usr/lib/python3.10/enum.py", line 619, in _get_mixins_
raise TypeError("new enumerations should be created as "
TypeError: new enumerations should be created as `EnumName([mixin_type, ...] [data_type,] enum_type)`
In order for the code to run we have to swap the positions of enum.Enum and MyEnum in both Foo and Bar (see the second gist); but then mypy fails to catch the type-error.
Your Environment
- Mypy version used: master and 0.931
- Mypy command-line flags: none
- Mypy configuration options from
mypy.ini(and other config files): none - Python version used: 3.9
- Operating system and version:
Linux pavla 5.15.12-1-MANJARO #1 SMP PREEMPT Wed Dec 29 18:08:07 UTC 2021 x86_64 GNU/Linux
Previous discussion in gitter: https://gitter.im/python/typing?at=61dab43cf5a3947800f73b71
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by running the two linked mypy-play reproductions with Python 3.9 and mypy master, comparing the version that rejects the invalid Carrier call with the version that runs but accepts it. Then trace mypy's handling of generic enum.Enum subclasses and custom EnumMeta classes, and add regression coverage for the expected type error.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- devtools
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100