Skip to content

Regression: Stub generator no longer generates __members__ for enum class #12717

Description

@bluenote10

Bug Report

In mypy version 0.942, the stub generator used to create __members__ fields like:

classMyEnum:
__members__: ClassVar[dict] = ... # read-only

In our case, MyEnum is a C++ enum class exposed to Python via pybind11. The type annotation seemed to be correct, because at runtime, __members__ does exist.

In mypy version 0.950 the __members__ field is no longer annotated, which means that existing value code no longer type checks properly.

To Reproduce

  • Create a temporary venv:
$ mkdir some_temporary_folder
$ cd some_temporary_folder
$ virtualenv ./tmp_venv -p /usr/bin/python3.8
$ . ./tmp_venv/bin/activate
$ pip install -U pip setuptools
$ pip install mypy==0.950 pybind11==2.9.0
  • Create a file native_enum_test.cpp with content:
#include<cstddef>
#include<memory>
#include<pybind11/pybind11.h>namespacepy= pybind11;
enumclassMyEnum { FOO, BAR };
PYBIND11_MODULE(native_enum_test, module) {
pybind11::enum_<MyEnum>(module, "MyEnum", pybind11::arithmetic())
.value("FOO", MyEnum::FOO)
.value("BAR", MyEnum::BAR);
}
  • Compile via:
$ c++ -O3 -Wall -shared -std=c++17 -fPIC $(python3 -m pybind11 --includes) native_enum_test.cpp -o native_enum_test.so
  • Run the stub generator:
$ stubgen -p native_enum_test

Expected Behavior

As far as I can see, __members__ should be generated by the stub generator.

Check against the previous mypy version: pip install mypy==0.942 and re-running the stub generator produces:

Generator output mypy 0.942
fromtypingimportClassVarclassMyEnum:
__doc__: ClassVar[str] = ... # read-only__members__: ClassVar[dict] = ... # read-onlyBAR: ClassVar[MyEnum] = ...
FOO: ClassVar[MyEnum] = ...
__entries: ClassVar[dict] = ...
def__init__(self, value: int) ->None: ...
def__eq__(self, other: object) ->bool: ...
def__ge__(self, other: object) ->bool: ...
def__getstate__(self) ->int: ...
def__gt__(self, other: object) ->bool: ...
def__hash__(self) ->int: ...
def__index__(self) ->int: ...
def__int__(self) ->int: ...
def__le__(self, other: object) ->bool: ...
def__lt__(self, other: object) ->bool: ...
def__ne__(self, other: object) ->bool: ...
def__setstate__(self, state: int) ->None: ...
@propertydefname(self) ->str: ...
@propertydefvalue(self) ->int: ...

Actual Behavior

__members__ is missing in the stub generator output.

Generator output mypy 0.950
fromtypingimportClassVarclassMyEnum:
BAR: ClassVar[MyEnum] = ...
FOO: ClassVar[MyEnum] = ...
__entries: ClassVar[dict] = ...
def__init__(self, value: int) ->None: ...
def__eq__(self, other: object) ->bool: ...
def__ge__(self, other: object) ->bool: ...
def__getstate__(self) ->int: ...
def__gt__(self, other: object) ->bool: ...
def__hash__(self) ->int: ...
def__index__(self) ->int: ...
def__int__(self) ->int: ...
def__le__(self, other: object) ->bool: ...
def__lt__(self, other: object) ->bool: ...
def__ne__(self, other: object) ->bool: ...
def__setstate__(self, state: int) ->None: ...
@propertydefname(self) ->str: ...
@propertydefvalue(self) ->int: ...

Your Environment

  • Mypy version used: 0.950
  • Mypy command-line flags: not relevant, this is about the stub generator
  • Mypy configuration options from mypy.ini (and other config files): not relevant, this is about the stub generator
  • Python version used: 3.8.10
  • Operating system and version: Ubuntu 20.04

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions