You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
"Enum" has no attribute "__iter__" on instance attributes defined with functional API #8009
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
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.
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.
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).
Activity
lihu-zhong commentedon Nov 25, 2019
It looks like this might be more general than just iteration -- mypy raises an error on almost any normal
Enumoperation:gives
ilevkivskyi commentedon Nov 25, 2019
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.
lihu-zhong commentedon Nov 25, 2019
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 commentedon Nov 25, 2019
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().InnerEnumandFoo().InnerEnumare 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).
lihu-zhong commentedon Nov 25, 2019
That makes sense to me. Thank you for the feedback.
rdbisme commentedon Feb 24, 2020
What about having an
Enumas class attribute? It looks like I'm getting the same error for a class attributeAvasam commentedon Feb 22, 2024
A similar question was asked in setuptools: how about at a module level?
pypa/setuptools#3979 (comment)