Skip to content

Is Enum's _generate_next_value_ really a @staticmethod? #10428

Closed

Description

@Avasam

I was playing around with a custom enum and wanted to give it custom auto values. But come time to override _generate_next_value_ and pyright tells me that: Method "_generate_next_value_" overrides class "Enum" in an incompatible manner. Base method is declared as a staticmethod but override is not.

mypy:

error: Signature of "_generate_next_value_" incompatible with supertype "Enum"  [override]
note:      Superclass:
note:          def _generate_next_value_(name: str, start: int, count: int, last_values: list[Any]) -> Any
note:      Subclass:
note:          def _generate_next_value_(name, *_: Any) -> Any

The following code in Python 3.9 works as expected, although with a type error:

from enum import Enum, EnumMeta, auto, unique
from typing import cast
from typing_extensions import override

class CaptureMethodMeta(EnumMeta):
    # Allow checking if simple string is enum
    @override
    def __contains__(self, other: object):
        try:
            self(other)
        except ValueError:
            return False
        return True

@unique
# TODO: Replace with StrEnum in Python 3.11
class CaptureMethodEnum(str, Enum, metaclass=CaptureMethodMeta):
    # Allow TOML to save as a simple string
    @override
    def __repr__(self):
        return self.value
    __str__ = __repr__

    @override
    def _generate_next_value_(name: str, *_):
        return name

    NONE = ""
    BITBLT = auto()
    WINDOWS_GRAPHICS_CAPTURE = auto()
    PRINTWINDOW_RENDERFULLCONTENT = auto()
    DESKTOP_DUPLICATION = auto()
    VIDEO_CAPTURE_DEVICE = auto()

bitblt: str = cast(str, "BITBLT")
bar: str = cast(str, "bar")
print(bitblt == CaptureMethodEnum.BITBLT)
print(bar == CaptureMethodEnum.BITBLT)
print("BITBLT" in CaptureMethodEnum)
print("bar" in CaptureMethodEnum)

If I decorate _generate_next_value_ with @staticmethod, I get the following error:

Traceback (most recent call last):
  File "c:\Users\Avasam\Desktop\from enum import Enum, EnumMeta, unique.py", line 18, in <module>
    class CaptureMethodEnum(str, Enum, metaclass=CaptureMethodMeta):
  File "c:\Users\Avasam\Desktop\from enum import Enum, EnumMeta, unique.py", line 31, in CaptureMethodEnum
    BITBLT = auto()
  File "C:\Program Files\Python39\lib\enum.py", line 142, in __setitem__
    value.value = self._generate_next_value(
TypeError: 'staticmethod' object is not callable

Activity

  1. srittau commented on Jul 10, 2023

    @srittau
    Collaborator

    I haven't looked at this in depth, but considering the highly "custom" nature of enums, it's quite possible that this was/is a hack to make things work. That said, it never hurts to check whether hacks are still necessary and remove them if not. At least, there should be a comment explaining the necessity of a hack.

  2. eltoder commented on Jul 11, 2023

    @eltoder
    Contributor

    This looks like a duplicate of python/mypy#7591, but the mypy bug does not have a lot of details. From a quick look, I found that:

    • _generate_next_value_ is a de-facto @staticmethod, but the docs did not decorate it until python 3.11. See python 3.10 docs, python 3.11 docs.
    • Until python 3.10, decorating _generate_next_value_ produced an error at runtime that can be seen in the OP. However, this only happens when _generate_next_value_ is defined directly in the class. If you instead define it in a base class, decorating the method works fine.

    In short, move it to a base class and use @staticmethod. This is probably what you want anyway, since it allows you to package and reuse this functionality.

  3. Avasam commented on Jul 12, 2023

    @Avasam
    SponsorCollaboratorAuthor

    Hum, if all that is correct, I wonder if typeshed should only decorate _generate_next_value_ with @staticmethod for python 3.10 or above. So that a user's type-checker doesn't tell them to decorate it, which would fail at runtime.
    In fact it would warn the user of "incompatible override" if they decorated it.

  4. eltoder commented on Jul 12, 2023

    @eltoder
    Contributor

    If you don't decorate it, you'll hit another problem. It will be considered an instance method, and you'll get an error that the first argument's type is wrong. See the mypy bug I linked above.

  5. jenstroeger commented on Aug 15, 2025

    @jenstroeger
    Contributor
  6. Avasam commented on May 18, 2026

    @Avasam
    SponsorCollaboratorAuthor

    python/mypy#15382 (comment)

    I believe _generate_next_value_ should be decorated with @staticmethod. But that crashes in python 3.8 and 3.9 . Not sure if that can be fixed on the type-definition side (see python/typeshed#10428)

    mypy 1.17 has dropped support for Python 3.8:

    and mypy 2.0 has dropped support for Python 3.9:

    So this should now be solvable by always decorating _generate_next_value_ with @staticmethod

    Since typeshed also dropped Python 39 support (#15708) I'll just close this as my issue "fixed itself"

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions