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

"Enum" has no attribute "__iter__" on instance attributes defined with functional API #8009

Closed
lbenezriravin opened this issue Nov 25, 2019 · 7 comments · Fixed by #8107
Closed

Comments

@lbenezriravin
Copy link

Steps to reproduce
Run mypy against the following code:

from enum import Enum


class OuterEnum(Enum):
    foo = "bar"


class Foo:
    def __init__(self,) -> None:
        self.OuterEnum = OuterEnum
        list(self.OuterEnum)
        self.InnerEnum = Enum("InnerEnum", [("foo", "bar")])
        list(self.InnerEnum)  # Error!
        [i for i in self.InnerEnum]  # Error!
        self.DictEnum = Enum("DictEnum", {"foo": "bar"})
        list(self.DictEnum)  # Error!


OtherEnum = Enum("OtherEnum", [("foo", "bar")])
list(OtherEnum)

Observed behavior
When trying to iterate over an enumeration defined as an instance attribute using the functional API, mypy raises an error when attempting to iterate over said attribute.

The above snippet raises three mypy errors where marked:

$ poetry run mypy foo.py 
foo.py:13: error: No overload variant of "list" matches argument type "Enum"
foo.py:13: note: Possible overload variant:
foo.py:13: note:     def [_T] __init__(self, iterable: Iterable[_T]) -> List[_T]
foo.py:13: note:     <1 more non-matching overload not shown>
foo.py:14: error: "Enum" has no attribute "__iter__"; maybe "__str__" or "__dir__"? (not iterable)
foo.py:16: error: No overload variant of "list" matches argument type "Enum"
foo.py:16: note: Possible overload variant:
foo.py:16: note:     def [_T] __init__(self, iterable: Iterable[_T]) -> List[_T]
foo.py:16: note:     <1 more non-matching overload not shown>
Found 3 errors in 1 file (checked 1 source file)

Expected behavior
When testing the above code, iteration over the instance attribute Enum works fine, and mypy does not raise errors when iterating over similar Enums if they're defined using the class syntax or aren't instance attributes. I would not expect mypy to raise an error here.

Environment

$ poetry run mypy --version
mypy 0.740
$ poetry run python --version
Python 3.7.4

Also tested against master with the same behavior

$ poetry run mypy --version
mypy 0.750+dev.2af0ac021335ec4a3e84a0ba739b4aea7e659c43

Thank you for your work on this tool!

@lbenezriravin
Copy link
Author

It looks like this might be more general than just iteration -- mypy raises an error on almost any normal Enum operation:

        self.InnerEnum("bar")
        self.InnerEnum["foo"]

gives

"Enum" not callable
Value of type "Enum" is not indexable

@ilevkivskyi
Copy link
Member

The actual bug here is that creating enum as an attribute on self should be plain prohibited (with a clear error message), see similar issue #7531 and fix for it #7662 for named tuples. Probably the same should be also for typed dicts.

@lbenezriravin
Copy link
Author

Thanks for the prompt response; that makes sense. Out of curiosity, why should generating enums and namedtuples as attributes be prohibited? It would be quite convenient for me in this case, since I'd like to build up an enumeration from data I'm reading in from the file system.

@ilevkivskyi
Copy link
Member

Out of curiosity, why should generating enums and namedtuples as attributes be prohibited?

Creating a new type for every instance doesn't really make sense in a statically typed world (assuming we will never do full scale dependent types): Foo().InnerEnum and Foo().InnerEnum are two different classes if you call it twice.

Also this is honestly an anti-pattern. I could easily imagine this causes subtle bugs when you compare two enum values from different instances.

Currently mypy allows assigning normal class objects (i.e. non-special like enums) as attributes, because this pattern is used in unit tests (and there it kind of fine because there is typically a single instance of the test case class).

@lbenezriravin
Copy link
Author

That makes sense to me. Thank you for the feedback.

@rdbisme
Copy link

rdbisme commented Feb 24, 2020

What about having an Enum as class attribute? It looks like I'm getting the same error for a class attribute

@Avasam
Copy link
Contributor

Avasam commented Feb 22, 2024

What about having an Enum as class attribute? It looks like I'm getting the same error for a class attribute

A similar question was asked in setuptools: how about at a module level?
pypa/setuptools#3979 (comment)

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

Successfully merging a pull request may close this issue.

4 participants