@@ -705,19 +705,9 @@ def analyze_class_attribute_access(itype: Instance,
705
705
check_final_member (name , info , mx .msg , mx .context )
706
706
707
707
if info .is_enum and not (mx .is_lvalue or is_decorated or is_method ):
708
- # Skip "_order_" and "__order__", since Enum will remove it
709
- if name in ("_order_" , "__order__" ):
710
- return mx .msg .has_no_attr (
711
- mx .original_type , itype , name , mx .context , mx .module_symbol_table
712
- )
713
-
714
- enum_literal = LiteralType (name , fallback = itype )
715
- # When we analyze enums, the corresponding Instance is always considered to be erased
716
- # due to how the signature of Enum.__new__ is `(cls: Type[_T], value: object) -> _T`
717
- # in typeshed. However, this is really more of an implementation detail of how Enums
718
- # are typed, and we really don't want to treat every single Enum value as if it were
719
- # from type variable substitution. So we reset the 'erased' field here.
720
- return itype .copy_modified (erased = False , last_known_value = enum_literal )
708
+ enum_class_attribute_type = analyze_enum_class_attribute_access (itype , name , mx )
709
+ if enum_class_attribute_type :
710
+ return enum_class_attribute_type
721
711
722
712
t = node .type
723
713
if t :
@@ -815,6 +805,28 @@ def analyze_class_attribute_access(itype: Instance,
815
805
return typ
816
806
817
807
808
+ def analyze_enum_class_attribute_access (itype : Instance ,
809
+ name : str ,
810
+ mx : MemberContext ,
811
+ ) -> Optional [Type ]:
812
+ # Skip "_order_" and "__order__", since Enum will remove it
813
+ if name in ("_order_" , "__order__" ):
814
+ return mx .msg .has_no_attr (
815
+ mx .original_type , itype , name , mx .context , mx .module_symbol_table
816
+ )
817
+ # For other names surrendered by underscores, we don't make them Enum members
818
+ if name .startswith ('__' ) and name .endswith ("__" ) and name .replace ('_' , '' ) != '' :
819
+ return None
820
+
821
+ enum_literal = LiteralType (name , fallback = itype )
822
+ # When we analyze enums, the corresponding Instance is always considered to be erased
823
+ # due to how the signature of Enum.__new__ is `(cls: Type[_T], value: object) -> _T`
824
+ # in typeshed. However, this is really more of an implementation detail of how Enums
825
+ # are typed, and we really don't want to treat every single Enum value as if it were
826
+ # from type variable substitution. So we reset the 'erased' field here.
827
+ return itype .copy_modified (erased = False , last_known_value = enum_literal )
828
+
829
+
818
830
def add_class_tvars (t : ProperType , isuper : Optional [Instance ],
819
831
is_classmethod : bool ,
820
832
original_type : Type ,
0 commit comments