Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support functional API for Enum creation #2306

Closed
gvanrossum opened this issue Oct 24, 2016 · 11 comments
Closed

Support functional API for Enum creation #2306

gvanrossum opened this issue Oct 24, 2016 · 11 comments

Comments

@gvanrossum
Copy link
Member

The enum.Enum class (new in Python 3.4, also backported as enum34) supports several short forms of creating an Enum type, described under functional API:

A = Enum('A', 'x y z')
B = Enum('B', ('p', 'q'))

These are equivalent to

class A(Enum):
    x = 1
    y = 2
    z = 3
class B(Enum):
    p = 1
    q = 2

Some other syntactic variants are also allowed:

A = Enum('A', 'x,y,z')
A = Enum('A', 'x, y, z')
B = Enum('B', ['p', 'q'])

The values can also be expressed as a list of tuples:

[('cyan', 4), ('magenta', 5), ('yellow', 6)]

or a mapping:

{'chartreuse': 7, 'sea_green': 11, 'rosemary': 42}
@homeworkprod
Copy link

I've been checking out mypy for less than two minutes, stumbled upon the error (Too many arguments for "Enum") with the first few files to check, searched the web, and followed a trail of issues to find out that this is at least known.

Yeah, I'd like to see this fixed rather sooner than later. This might drive new users away right at the start.

Until then, is there a way to suppress the error and keep mypy from exiting with a return code > 0 (for use in CI scripts)?

@JukkaL
Copy link
Collaborator

JukkaL commented Jan 31, 2017

@homeworkprod The recommended fix is to refactor your code to use an alternative enum syntax. Is that not feasible for some reason? If not, I'd like to hear about your concerns. You can also try adding # type: ignore to silence the message.

@gvanrossum What do you think about making this a high priority issue? Multiple users seem to be hitting this, and this shouldn't be hard to support (though the implementation will be pretty tedious to write).

@gvanrossum
Copy link
Member Author

Agreed.

@homeworkprod
Copy link

@JukkaL Well, I highly prefer the (oftentimes) one-liner functional API to spreading the definition of a (smaller) enum over multiple lines and including distracting, somewhat error-prone numbers that are irrelevant for the business logic (in the cases in question). Why have (to read) half a page of code when three lines neatly do the trick?

The ignore hint works for me, so I'll go with that for now, thank you.

homeworkprod added a commit to byceps/byceps that referenced this issue Feb 3, 2017
Ignore hints can be removed after python/mypy#2306 gets resolved.
gvanrossum pushed a commit that referenced this issue Feb 3, 2017
gvanrossum pushed a commit that referenced this issue Feb 3, 2017
gvanrossum pushed a commit that referenced this issue Feb 3, 2017
@gvanrossum gvanrossum self-assigned this Feb 3, 2017
gvanrossum pushed a commit that referenced this issue Feb 3, 2017
gvanrossum pushed a commit that referenced this issue Feb 3, 2017
gvanrossum pushed a commit that referenced this issue Feb 3, 2017
gvanrossum pushed a commit that referenced this issue Feb 3, 2017
gvanrossum pushed a commit that referenced this issue Feb 7, 2017
gvanrossum pushed a commit that referenced this issue Mar 24, 2017
gvanrossum pushed a commit that referenced this issue Mar 25, 2017
gvanrossum pushed a commit that referenced this issue Mar 27, 2017
gvanrossum pushed a commit that referenced this issue Mar 27, 2017
@gvanrossum gvanrossum removed this from the 0.5 milestone Mar 29, 2017
JukkaL pushed a commit that referenced this issue Mar 31, 2017
Fixes #2306.

Also move Enum tests from runtests to pytest.
@homeworkprod
Copy link

Just a quick feedback: Works for me now (tested with Mypy 0.511). Thanks!

@anentropic
Copy link

anentropic commented Nov 1, 2017

mypy 0.540

PictureSize = Enum('PictureSize', 'P0 P1 P2 P3 P4 P5 P6 P7 P8', type=str, module=__name__)

gives:

error: Too many arguments for Enum()

Later when trying to access a value from the enum:

error: "Type[Enum]" has no attribute "P0"

I understand if it won't be fixed, but I thought from previous comment maybe it had been?

@anentropic
Copy link

ah I see, removing the type=str, module=__name__ extra kwargs gets rid of the second error too

I guess with this much working now it ought to be easy to add recognition of all the kwargs the constructor supports as detailed in the docs?https://docs.python.org/3/library/enum.html#functional-api

@JukkaL
Copy link
Collaborator

JukkaL commented Nov 1, 2017

@anentropic Yeah, this is something mypy should be able to support pretty easily. Created #4184 to track the issue.

@rdbisme
Copy link

rdbisme commented Feb 27, 2020

Is this related? #4865

Because I'm hitting the same problem...

from enum import IntEnum
from typing import Collection


def list_to_enum(cls, fields: Collection[str]) -> IntEnum:
    """ Convert a list of textual fields to the class:`IntEnum` that needs
    to be stored in this class :attr:`fields` """

    return IntEnum(
        cls._FIELDS_ENUM_NAME, dict(zip(fields, range(len(fields))))
    )

From here

The second argument is the source of enumeration member names. It can be a whitespace-separated string of names, a sequence of names, a sequence of 2-tuples with key/value pairs, or a mapping (e.g. dictionary) of names to values. The last two options enable assigning arbitrary values to enumerations; the others auto-assign increasing integers starting with 1 (use the start parameter to specify a different starting value). A new class derived from Enum is returned.

@JukkaL
Copy link
Collaborator

JukkaL commented Feb 28, 2020

@rubendibattista Your example is too dynamic for mypy to understand (see #4865 (comment)).

@mvoitko
Copy link

mvoitko commented Oct 15, 2021

Are there PRs, issues or at least plans to handle the case @rubendibattista metioned?
I have faced a similar problem:

import enum
from typing import Any


class StrAutoEnum(str, enum.Enum):
    def _generate_next_value_(name: str, start: Any, count: int, last_values: Any) -> str:  # type: ignore[misc, override] # noqa:E501
        return name


Target = StrAutoEnum('Target', {name: enum.auto() for name in model_names})  # type: ignore[call-overload]

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

No branches or pull requests

6 participants