Skip to content

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

Closed
@bluenote10

Description

@bluenote10

Bug Report

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

class MyEnum:
    __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>

namespace py = pybind11;

enum class MyEnum { 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
from typing import ClassVar

class MyEnum:
    __doc__: ClassVar[str] = ...  # read-only
    __members__: ClassVar[dict] = ...  # read-only
    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: ...
    @property
    def name(self) -> str: ...
    @property
    def value(self) -> int: ...

Actual Behavior

__members__ is missing in the stub generator output.

Generator output mypy 0.950
from typing import ClassVar

class MyEnum:
    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: ...
    @property
    def name(self) -> str: ...
    @property
    def value(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