@@ -705,19 +705,9 @@ def analyze_class_attribute_access(itype: Instance,
705705 check_final_member (name , info , mx .msg , mx .context )
706706
707707 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
721711
722712 t = node .type
723713 if t :
@@ -815,6 +805,28 @@ def analyze_class_attribute_access(itype: Instance,
815805 return typ
816806
817807
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+
818830def add_class_tvars (t : ProperType , isuper : Optional [Instance ],
819831 is_classmethod : bool ,
820832 original_type : Type ,
0 commit comments