From 50e48d181e927d50f5854a964d29333469e84f36 Mon Sep 17 00:00:00 2001 From: Michael Carlstrom Date: Tue, 11 Nov 2025 21:57:24 -0800 Subject: [PATCH 1/5] add native enum support --- mypy/stubgenc.py | 8 ++++++-- .../pybind11_fixtures/demo.pyi | 16 +++++++++++++++- .../pybind11_fixtures/demo.pyi | 16 +++++++++++++++- test-data/pybind11_fixtures/src/main.cpp | 11 +++++++++++ 4 files changed, 47 insertions(+), 4 deletions(-) diff --git a/mypy/stubgenc.py b/mypy/stubgenc.py index e0e063927aad..a2dea90938f3 100755 --- a/mypy/stubgenc.py +++ b/mypy/stubgenc.py @@ -870,8 +870,12 @@ def generate_class_stub( # special case for __hash__ continue prop_type_name = self.strip_or_import(self.get_type_annotation(value)) - classvar = self.add_name("typing.ClassVar") - static_properties.append(f"{self._indent}{attr}: {classvar}[{prop_type_name}] = ...") + # Pybind supports native enums now + if issubclass(cls, enum.Enum) and attr in cls._member_names_: + static_properties.append(f"{self._indent}{attr} = ...") + else: + classvar = self.add_name("typing.ClassVar") + static_properties.append(f"{self._indent}{attr}: {classvar}[{prop_type_name}] = ...") self.dedent() diff --git a/test-data/pybind11_fixtures/expected_stubs_no_docs/pybind11_fixtures/demo.pyi b/test-data/pybind11_fixtures/expected_stubs_no_docs/pybind11_fixtures/demo.pyi index 09e75e1ad4aa..ee00d67aaaff 100644 --- a/test-data/pybind11_fixtures/expected_stubs_no_docs/pybind11_fixtures/demo.pyi +++ b/test-data/pybind11_fixtures/expected_stubs_no_docs/pybind11_fixtures/demo.pyi @@ -1,9 +1,23 @@ +import enum import typing -from typing import ClassVar, overload +from typing import Callable, ClassVar, overload PI: float __version__: str +class Color(enum.Enum): + __new__: ClassVar[Callable] = ... + GREEN = ... + RED = ... + _generate_next_value_: ClassVar[Callable] = ... + _member_map_: ClassVar[dict] = ... + _member_names_: ClassVar[list] = ... + _member_type_: ClassVar[type[object]] = ... + _unhashable_values_: ClassVar[list] = ... + _use_args_: ClassVar[bool] = ... + _value2member_map_: ClassVar[dict] = ... + _value_repr_: ClassVar[None] = ... + class Point: class AngleUnit: __members__: ClassVar[dict] = ... # read-only diff --git a/test-data/pybind11_fixtures/expected_stubs_with_docs/pybind11_fixtures/demo.pyi b/test-data/pybind11_fixtures/expected_stubs_with_docs/pybind11_fixtures/demo.pyi index 580aa2700178..bfd141382460 100644 --- a/test-data/pybind11_fixtures/expected_stubs_with_docs/pybind11_fixtures/demo.pyi +++ b/test-data/pybind11_fixtures/expected_stubs_with_docs/pybind11_fixtures/demo.pyi @@ -1,9 +1,23 @@ +import enum import typing -from typing import ClassVar, overload +from typing import Callable, ClassVar, overload PI: float __version__: str +class Color(enum.Enum): + __new__: ClassVar[Callable] = ... + GREEN = ... + RED = ... + _generate_next_value_: ClassVar[Callable] = ... + _member_map_: ClassVar[dict] = ... + _member_names_: ClassVar[list] = ... + _member_type_: ClassVar[type[object]] = ... + _unhashable_values_: ClassVar[list] = ... + _use_args_: ClassVar[bool] = ... + _value2member_map_: ClassVar[dict] = ... + _value_repr_: ClassVar[None] = ... + class Point: class AngleUnit: """Members: diff --git a/test-data/pybind11_fixtures/src/main.cpp b/test-data/pybind11_fixtures/src/main.cpp index 4d275ab1fd70..3eecb9cbda36 100644 --- a/test-data/pybind11_fixtures/src/main.cpp +++ b/test-data/pybind11_fixtures/src/main.cpp @@ -51,6 +51,7 @@ #include #include #include +#include namespace py = pybind11; @@ -212,6 +213,11 @@ const Point Point::y_axis = Point(0, 1); Point::LengthUnit Point::length_unit = Point::LengthUnit::mm; Point::AngleUnit Point::angle_unit = Point::AngleUnit::radian; +enum Color { + RED = 0, + GREEN = 1 +}; + } // namespace: demo // Bindings @@ -230,6 +236,11 @@ void bind_demo(py::module& m) { py::class_ pyPoint(m, "Point"); py::enum_ pyLengthUnit(pyPoint, "LengthUnit"); py::enum_ pyAngleUnit(pyPoint, "AngleUnit"); + py::native_enum(m, "Color", "enum.Enum") + .value("RED", Color::RED) + .value("GREEN", Color::GREEN) + .finalize(); + pyPoint .def(py::init<>()) From ee0ebb80514c8090ee77d245f29193dd8b422b5f Mon Sep 17 00:00:00 2001 From: Michael Carlstrom Date: Tue, 11 Nov 2025 22:01:30 -0800 Subject: [PATCH 2/5] Add literal --- mypy/stubgenc.py | 2 +- .../expected_stubs_no_docs/pybind11_fixtures/demo.pyi | 4 ++-- .../expected_stubs_with_docs/pybind11_fixtures/demo.pyi | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mypy/stubgenc.py b/mypy/stubgenc.py index a2dea90938f3..ce4e9453bcd4 100755 --- a/mypy/stubgenc.py +++ b/mypy/stubgenc.py @@ -872,7 +872,7 @@ def generate_class_stub( prop_type_name = self.strip_or_import(self.get_type_annotation(value)) # Pybind supports native enums now if issubclass(cls, enum.Enum) and attr in cls._member_names_: - static_properties.append(f"{self._indent}{attr} = ...") + static_properties.append(f"{self._indent}{attr} = {cls._member_map_[attr].value}") else: classvar = self.add_name("typing.ClassVar") static_properties.append(f"{self._indent}{attr}: {classvar}[{prop_type_name}] = ...") diff --git a/test-data/pybind11_fixtures/expected_stubs_no_docs/pybind11_fixtures/demo.pyi b/test-data/pybind11_fixtures/expected_stubs_no_docs/pybind11_fixtures/demo.pyi index ee00d67aaaff..b1557e1c3402 100644 --- a/test-data/pybind11_fixtures/expected_stubs_no_docs/pybind11_fixtures/demo.pyi +++ b/test-data/pybind11_fixtures/expected_stubs_no_docs/pybind11_fixtures/demo.pyi @@ -7,8 +7,8 @@ __version__: str class Color(enum.Enum): __new__: ClassVar[Callable] = ... - GREEN = ... - RED = ... + GREEN = 1 + RED = 0 _generate_next_value_: ClassVar[Callable] = ... _member_map_: ClassVar[dict] = ... _member_names_: ClassVar[list] = ... diff --git a/test-data/pybind11_fixtures/expected_stubs_with_docs/pybind11_fixtures/demo.pyi b/test-data/pybind11_fixtures/expected_stubs_with_docs/pybind11_fixtures/demo.pyi index bfd141382460..36769f6c13f8 100644 --- a/test-data/pybind11_fixtures/expected_stubs_with_docs/pybind11_fixtures/demo.pyi +++ b/test-data/pybind11_fixtures/expected_stubs_with_docs/pybind11_fixtures/demo.pyi @@ -7,8 +7,8 @@ __version__: str class Color(enum.Enum): __new__: ClassVar[Callable] = ... - GREEN = ... - RED = ... + GREEN = 1 + RED = 0 _generate_next_value_: ClassVar[Callable] = ... _member_map_: ClassVar[dict] = ... _member_names_: ClassVar[list] = ... From 72ada9e4923590a617962be3aeeddd5e9c4e11ee Mon Sep 17 00:00:00 2001 From: Michael Carlstrom Date: Tue, 11 Nov 2025 22:09:26 -0800 Subject: [PATCH 3/5] remove special enum attrs --- mypy/stubgenc.py | 15 ++++++++++++++- .../pybind11_fixtures/demo.pyi | 8 -------- .../pybind11_fixtures/demo.pyi | 8 -------- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/mypy/stubgenc.py b/mypy/stubgenc.py index ce4e9453bcd4..95ac75c52972 100755 --- a/mypy/stubgenc.py +++ b/mypy/stubgenc.py @@ -14,7 +14,7 @@ import os.path from collections.abc import Mapping from types import FunctionType, ModuleType -from typing import Any, Callable +from typing import Any, Callable, Final from mypy.fastparse import parse_type_comment from mypy.moduleinspect import is_c_module @@ -40,6 +40,17 @@ ) from mypy.util import quote_docstring +SPECIAL_ENUM_ATTRS: Final = { + "_generate_next_value_", + "_member_map_", + "_member_names_", + "_member_type_", + "_unhashable_values_", + "_use_args_", + "_value2member_map_", + "_value_repr_" +} + class ExternalSignatureGenerator(SignatureGenerator): def __init__( @@ -862,6 +873,8 @@ def generate_class_stub( ) elif inspect.isclass(value) and self.is_defined_in_module(value): self.generate_class_stub(attr, value, types, parent_class=class_info) + elif attr in SPECIAL_ENUM_ATTRS: + pass else: attrs.append((attr, value)) diff --git a/test-data/pybind11_fixtures/expected_stubs_no_docs/pybind11_fixtures/demo.pyi b/test-data/pybind11_fixtures/expected_stubs_no_docs/pybind11_fixtures/demo.pyi index b1557e1c3402..f491683987b8 100644 --- a/test-data/pybind11_fixtures/expected_stubs_no_docs/pybind11_fixtures/demo.pyi +++ b/test-data/pybind11_fixtures/expected_stubs_no_docs/pybind11_fixtures/demo.pyi @@ -9,14 +9,6 @@ class Color(enum.Enum): __new__: ClassVar[Callable] = ... GREEN = 1 RED = 0 - _generate_next_value_: ClassVar[Callable] = ... - _member_map_: ClassVar[dict] = ... - _member_names_: ClassVar[list] = ... - _member_type_: ClassVar[type[object]] = ... - _unhashable_values_: ClassVar[list] = ... - _use_args_: ClassVar[bool] = ... - _value2member_map_: ClassVar[dict] = ... - _value_repr_: ClassVar[None] = ... class Point: class AngleUnit: diff --git a/test-data/pybind11_fixtures/expected_stubs_with_docs/pybind11_fixtures/demo.pyi b/test-data/pybind11_fixtures/expected_stubs_with_docs/pybind11_fixtures/demo.pyi index 36769f6c13f8..d07d58498a33 100644 --- a/test-data/pybind11_fixtures/expected_stubs_with_docs/pybind11_fixtures/demo.pyi +++ b/test-data/pybind11_fixtures/expected_stubs_with_docs/pybind11_fixtures/demo.pyi @@ -9,14 +9,6 @@ class Color(enum.Enum): __new__: ClassVar[Callable] = ... GREEN = 1 RED = 0 - _generate_next_value_: ClassVar[Callable] = ... - _member_map_: ClassVar[dict] = ... - _member_names_: ClassVar[list] = ... - _member_type_: ClassVar[type[object]] = ... - _unhashable_values_: ClassVar[list] = ... - _use_args_: ClassVar[bool] = ... - _value2member_map_: ClassVar[dict] = ... - _value_repr_: ClassVar[None] = ... class Point: class AngleUnit: From c30b3a373a3ab64cdde5e54cc975a9484593018d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 12 Nov 2025 06:13:18 +0000 Subject: [PATCH 4/5] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mypy/stubgenc.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mypy/stubgenc.py b/mypy/stubgenc.py index 95ac75c52972..6b4c51d3e3a4 100755 --- a/mypy/stubgenc.py +++ b/mypy/stubgenc.py @@ -48,7 +48,7 @@ "_unhashable_values_", "_use_args_", "_value2member_map_", - "_value_repr_" + "_value_repr_", } @@ -888,7 +888,9 @@ def generate_class_stub( static_properties.append(f"{self._indent}{attr} = {cls._member_map_[attr].value}") else: classvar = self.add_name("typing.ClassVar") - static_properties.append(f"{self._indent}{attr}: {classvar}[{prop_type_name}] = ...") + static_properties.append( + f"{self._indent}{attr}: {classvar}[{prop_type_name}] = ..." + ) self.dedent() From 7fb1db5df06352c4d007706960b87f00e20e7bff Mon Sep 17 00:00:00 2001 From: Michael Carlstrom Date: Tue, 11 Nov 2025 22:14:40 -0800 Subject: [PATCH 5/5] add docstring --- .../expected_stubs_with_docs/pybind11_fixtures/demo.pyi | 1 + test-data/pybind11_fixtures/src/main.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/test-data/pybind11_fixtures/expected_stubs_with_docs/pybind11_fixtures/demo.pyi b/test-data/pybind11_fixtures/expected_stubs_with_docs/pybind11_fixtures/demo.pyi index d07d58498a33..400826965087 100644 --- a/test-data/pybind11_fixtures/expected_stubs_with_docs/pybind11_fixtures/demo.pyi +++ b/test-data/pybind11_fixtures/expected_stubs_with_docs/pybind11_fixtures/demo.pyi @@ -6,6 +6,7 @@ PI: float __version__: str class Color(enum.Enum): + """Color Enum""" __new__: ClassVar[Callable] = ... GREEN = 1 RED = 0 diff --git a/test-data/pybind11_fixtures/src/main.cpp b/test-data/pybind11_fixtures/src/main.cpp index 3eecb9cbda36..2d5291d3c635 100644 --- a/test-data/pybind11_fixtures/src/main.cpp +++ b/test-data/pybind11_fixtures/src/main.cpp @@ -236,7 +236,7 @@ void bind_demo(py::module& m) { py::class_ pyPoint(m, "Point"); py::enum_ pyLengthUnit(pyPoint, "LengthUnit"); py::enum_ pyAngleUnit(pyPoint, "AngleUnit"); - py::native_enum(m, "Color", "enum.Enum") + py::native_enum(m, "Color", "enum.Enum", "Color Enum") .value("RED", Color::RED) .value("GREEN", Color::GREEN) .finalize();