@@ -7475,6 +7475,12 @@ def name_not_defined(self, name: str, ctx: Context, namespace: str | None = None
74757475 self .record_incomplete_ref ()
74767476 return
74777477 message = f'Name "{ name } " is not defined'
7478+ # Collect all names in scope to suggest similar alternatives
7479+ alternatives = self ._get_names_in_scope ()
7480+ alternatives .discard (name )
7481+ matches = best_matches (name , alternatives , n = 3 )
7482+ if matches :
7483+ message += f"; did you mean { pretty_seq (matches , 'or' )} ?"
74787484 self .fail (message , ctx , code = codes .NAME_DEFINED )
74797485
74807486 if f"builtins.{ name } " in SUGGESTED_TEST_FIXTURES :
@@ -7499,6 +7505,36 @@ def name_not_defined(self, name: str, ctx: Context, namespace: str | None = None
74997505 ).format (module = module , name = lowercased [fullname ].rsplit ("." , 1 )[- 1 ])
75007506 self .note (hint , ctx , code = codes .NAME_DEFINED )
75017507
7508+ def _get_names_in_scope (self ) -> set [str ]:
7509+ """Collect all names visible in the current scope for fuzzy matching suggestions.
7510+
7511+ This includes:
7512+ - Local variables (from function scopes)
7513+ - Class attributes (if it's inside a class)
7514+ - Global/module-level names
7515+ - Builtins
7516+ """
7517+ names : set [str ] = set ()
7518+
7519+ for table in self .locals :
7520+ if table is not None :
7521+ names .update (table .keys ())
7522+
7523+ if self .type is not None :
7524+ names .update (self .type .names .keys ())
7525+
7526+ names .update (self .globals .keys ())
7527+
7528+ b = self .globals .get ("__builtins__" , None )
7529+ if b and isinstance (b .node , MypyFile ):
7530+ # Only include public builtins (not _private ones)
7531+ for builtin_name in b .node .names .keys ():
7532+ if not (len (builtin_name ) > 1 and builtin_name [0 ] == "_" and builtin_name [1 ] != "_" ):
7533+ names .add (builtin_name )
7534+
7535+ # Filter out internal/dunder names that aren't useful for suggestions and might introduce noise
7536+ return {n for n in names if not n .startswith ("__" ) or n .endswith ("__" )}
7537+
75027538 def already_defined (
75037539 self , name : str , ctx : Context , original_ctx : SymbolTableNode | SymbolNode | None , noun : str
75047540 ) -> None :
0 commit comments