-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
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 iteration on enums #2305
Comments
At first sight, we only need #2193 class Enum:
...
@classmethod
def __iter__(cls: Type[T]) -> Iterator[T]: ... And somehow making Enum itself iterable? But it's not so simple, since |
In terms of making a class itself iterable it seems you have to use a metaclass instead of using just a In [7]: class A:
...: @classmethod
...: def __iter__(cls):
...: return iter(range(3))
...:
In [8]: list(A)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-8-ed10f13c6f39> in <module>()
----> 1 list(A)
TypeError: 'type' object is not iterable
In [9]: class MetaIter(type):
...: def __iter__(self):
...: return iter(range(3))
...:
In [10]: class B(metaclass=MetaIter): pass
In [11]: list(B)
Out[11]: [0, 1, 2] |
Yes, that's what I meant. But that's runtime. How to do it in mypy is
probably quite different because it doesn't interpret the metaclass.
|
Did you check the is_type_obj() method? It should still know...
Also, I doubt that defining a classmethod is the same as having it on the
metaclass. IIRC that doesn't even work in CPython.
|
I didn't check yet. As you said, it's not how mypy work. I think it should, but I guess it will require a big change. (I wonder whether mypy should mimic Smalltalk's object model. It's very elegant, and perhaps we can think of Python as "hiding the theory" (e.g. that type(type) != type) for the convenience of the user. Similarly to the |
* Support enum iteration. Fixes python/mypy#2305. * Make EnumMeta inherit from type, not ABCMeta.
Fixed by #1136. |
Should be python/typeshed#1136 |
I'm seeing this problem when using a subclass of IntEnum on mypy v0520. Should it be fixed in 0520? test.py:
|
Test cases for python#2305
@gvanrossum Doesn't seem to be working currently (see #4400). Can this issue be re-opened? |
@ngaya-ll Hm, that is a good catch. I will reopen this. |
Correction: it should be opened, since it is fixed by python/typeshed#1755 which is not merged yet. Sorry @ethanhs. |
Interesting. The original test case proposed by @bbc2 passes, but mypy still doesn't accept enum types as |
The original test passes because this kind of iteration uses structural typing already. The compatibility checks use structural subtyping (protocols) only if there is no explicit (nominal) protocol declared. That's what python/typeshed#1755 fixes - the problem is in typeshed. However, said PR uses a feature that reveals some other, seemingly unrelated problem in mypy: #4272. |
For reference, using mypy 0.560, the following: from enum import Enum
class Foo(Enum):
X = "x"
reveal_type(list(Foo))
reveal_type(set(Foo)) will print
I'd expect this to be |
This example seems to work on master |
I will report back when 0.570 is released. |
Test cases for python#2305
Test cases for python#2305
Test cases for python#2305
Test cases for python#2305
All examples I have found in this issue now work on mypy master. |
I'm seeing this issue when using a subclass of test.py: from aenum import MultiValueEnum
class MyEnum(MultiValueEnum):
A = 1, 2
B = 3
C = 4
for x in MyEnum:
print(x) > mypy test.py
|
@otchita that might be an issue with the stubs for aenum. |
@ilevkivskyi I'm seeing this issue when trying to express a function that should work for enums in general. Simplified example: from enum import Enum
from typing import Type
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3
def enum_getter(x: Type[Enum]) -> Enum:
return next(iter(x))
x = enum_getter(Color) This code runs in practice, but i get the following type checking error: |
Confirming that I'm running into the same behavior as @harahu on 0.991. Possibly related: #12553. Interestingly, if that example is modified slightly, it does work: from enum import Enum
from typing import Type
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3
def enum_getter(x: Type[Enum]) -> Enum:
for v in x:
return v
assert False, "unreachable"
x = enum_getter(Color) So it seems that as far as mypy is concerned This also makes the error go away: from enum import Enum
from typing import Type, Iterable
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3
def enum_getter(x: Type[Enum]) -> Enum:
y: Iterable[Enum] = x
return next(iter(y))
x = enum_getter(Color) Not sure if this is exactly the same problem as the original -- perhaps a maintainer could advise as to whether a new issue is warranted. |
Yes, this is most likely #12553 (which seems easy to fix, so I may submit PR there soon). |
Iterating on enums makes mypy (0.4.5) raise errors even though it's OK:
(follow-up issue created as suggested in #529)
The text was updated successfully, but these errors were encountered: