Skip to content

Commit

Permalink
Exclude "__order__" attribute from Enum Union expansion (#8140)
Browse files Browse the repository at this point in the history
  • Loading branch information
lazytype authored and msullivan committed Dec 13, 2019
1 parent 24f562a commit c957ac8
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 2 deletions.
6 changes: 6 additions & 0 deletions mypy/checkmember.py
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,12 @@ def analyze_class_attribute_access(itype: Instance,
check_final_member(name, info, mx.msg, mx.context)

if info.is_enum and not (mx.is_lvalue or is_decorated or is_method):
# Skip "_order_" and "__order__", since Enum will remove it
if name in ("_order_", "__order__"):
return mx.msg.has_no_attr(
mx.original_type, itype, name, mx.context, mx.module_symbol_table
)

enum_literal = LiteralType(name, fallback=itype)
# When we analyze enums, the corresponding Instance is always considered to be erased
# due to how the signature of Enum.__new__ is `(cls: Type[_T], value: object) -> _T`
Expand Down
4 changes: 2 additions & 2 deletions mypyc/genops.py
Original file line number Diff line number Diff line change
Expand Up @@ -1445,8 +1445,8 @@ def add_non_ext_class_attr(self, non_ext: NonExtClassInfo, lvalue: NameExpr,
if (
cdef.info.bases
and cdef.info.bases[0].type.fullname == 'enum.Enum'
# Skip "_order_", since Enum will remove it
and lvalue.name != '_order_'
# Skip "_order_" and "__order__", since Enum will remove it
and lvalue.name not in ('_order_', '__order__')
):
attr_to_cache.append(lvalue)

Expand Down
34 changes: 34 additions & 0 deletions test-data/unit/check-enum.test
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,40 @@ else:
reveal_type(y) # No output here: this branch is unreachable
[builtins fixtures/bool.pyi]

[case testEnumReachabilityChecksWithOrdering]
from enum import Enum
from typing_extensions import Literal

class Foo(Enum):
_order_ = "A B"
A = 1
B = 2

Foo._order_ # E: "Type[Foo]" has no attribute "_order_"

x: Literal[Foo.A, Foo.B]
if x is Foo.A:
reveal_type(x) # N: Revealed type is 'Literal[__main__.Foo.A]'
elif x is Foo.B:
reveal_type(x) # N: Revealed type is 'Literal[__main__.Foo.B]'
else:
reveal_type(x) # No output here: this branch is unreachable

class Bar(Enum):
__order__ = "A B"
A = 1
B = 2

Bar.__order__ # E: "Type[Bar]" has no attribute "__order__"

y: Literal[Bar.A, Bar.B]
if y is Bar.A:
reveal_type(y) # N: Revealed type is 'Literal[__main__.Bar.A]'
elif y is Bar.B:
reveal_type(y) # N: Revealed type is 'Literal[__main__.Bar.B]'
else:
reveal_type(y) # No output here: this branch is unreachable

[case testEnumReachabilityChecksIndirect]
from enum import Enum
from typing_extensions import Literal, Final
Expand Down

0 comments on commit c957ac8

Please sign in to comment.