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:

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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions