python / python/mypy

Type-checking generic of enum.Meta with a custom metaclass fails with code that runs, and passes with code that doesn't run.

Offen
#11,970 4 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

bug topic-enum
Vorherrschende Sprache
Python
Sterne
20.6k
Forks
3.3k
PR-Merge-Kennzahlen
PR-Kennzahlen ausstehend

Beschreibung

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

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Beginne damit, die beiden verlinkten mypy-play-Reproduktionen mit Python 3.9 und mypy master auszuführen, und vergleiche die Version, die den ungültigen Carrier-Aufruf ablehnt, mit der Version, die zwar ausgeführt wird, ihn aber akzeptiert. Untersuche dann, wie mypy generische enum.Enum-Unterklassen und benutzerdefinierte EnumMeta-Klassen behandelt, und füge Regressionstestabdeckung für den erwarteten Typfehler hinzu.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
python
Bereich
devtools
Issue-Typ
Bug
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Veraltet
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
35/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.