diff --git a/mypy/checkmember.py b/mypy/checkmember.py index b22a3d9e0849..727196877750 100644 --- a/mypy/checkmember.py +++ b/mypy/checkmember.py @@ -1159,6 +1159,13 @@ def analyze_class_attribute_access( return itype.extra_attrs.attrs[name] if info.fallback_to_any or info.meta_fallback_to_any: return apply_class_attr_hook(mx, hook, AnyType(TypeOfAny.special_form)) + # For enum types, report missing member with fuzzy matching suggestions + if ( + info.is_enum + and info.enum_members + and not (name.startswith("__") and name.endswith("__")) + ): + return report_missing_attribute(mx.original_type, itype, name, mx) return None if ( diff --git a/mypy/messages.py b/mypy/messages.py index c5756a463894..eb82b70d13e9 100644 --- a/mypy/messages.py +++ b/mypy/messages.py @@ -510,6 +510,23 @@ def has_no_attr( code=codes.ATTR_DEFINED, ) failed = True + elif isinstance(typ, Instance) and typ.type.names: + alternatives = set(typ.type.names.keys()) + alternatives.discard(member) + matches = [m for m in COMMON_MISTAKES.get(member, []) if m in alternatives] + matches.extend(best_matches(member, alternatives, n=3)) + if matches: + self.fail( + '{} has no attribute "{}"; maybe {}?{}'.format( + format_type(original_type, self.options), + member, + pretty_seq(matches, "or"), + extra, + ), + context, + code=codes.ATTR_DEFINED, + ) + failed = True if not failed: self.fail( '{} has no attribute "{}"{}'.format( diff --git a/test-data/unit/check-enum.test b/test-data/unit/check-enum.test index c05dfdef2bf7..673eda587294 100644 --- a/test-data/unit/check-enum.test +++ b/test-data/unit/check-enum.test @@ -2550,6 +2550,20 @@ class Pet(Enum): # E: Incompatible types in assignment (expression has type "ellipsis", variable has type "str") [builtins fixtures/enum.pyi] +[case testEnumMemberFuzzyMatch] +from enum import Enum + +class Color(Enum): + GREEN = 1 + RED = 2 + YELLOW = 3 + +Color.GREN # E: "type[Color]" has no attribute "GREN"; maybe "GREEN"? +Color.YELOW # E: "type[Color]" has no attribute "YELOW"; maybe "YELLOW"? +Color.RDE # E: "type[Color]" has no attribute "RDE" +Color.BLUE # E: "type[Color]" has no attribute "BLUE" +[builtins fixtures/enum.pyi] + [case testEnumValueWithPlaceholderNodeType] # https://github.com/python/mypy/issues/11971 from enum import Enum