diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 7dc3364561d8a1..26151b7d3b6070 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -1815,6 +1815,18 @@ class TestKeywordTypoSuggestions(unittest.TestCase): ("[x for x\nin range(3)\nof x]", "if"), ("[123 fur x\nin range(3)\nif x]", "for"), ("for x im n:\n pass", "in"), + ("mach x:", "match"), + ("math x:", "match"), + ("match 1:\n cse 1:", "case"), + ("typ x = int", "type"), + ("typed x = int", "type"), + ("lazi import x", "lazy"), + ("lezi import x", "lazy"), + ("switch x:\n case:", "match"), + ("delete x", "del"), + ("function f():", "def"), + ("func f():", "def"), + ("void f():", "def"), ] def test_keyword_suggestions_from_file(self): diff --git a/Lib/traceback.py b/Lib/traceback.py index 614a12f69b32e4..dcdab1f12e9a16 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -1485,11 +1485,22 @@ def _find_keyword_typos(self): # Limit the number of possible matches to try max_matches = 3 matches = [] + + hint = _get_cross_language_keyword_hint(wrong_name) + if hint: + matches.append(hint) if _suggestions is not None: - suggestion = _suggestions._generate_suggestions(keyword.kwlist, wrong_name) + suggestion = _suggestions._generate_suggestions(keyword.kwlist + keyword.softkwlist, wrong_name) if suggestion: matches.append(suggestion) - matches.extend(difflib.get_close_matches(wrong_name, keyword.kwlist, n=max_matches, cutoff=0.5)) + matches.extend( + difflib.get_close_matches( + wrong_name, + keyword.kwlist + keyword.softkwlist, + n=max_matches, + cutoff=0.5 + ) + ) matches = matches[:max_matches] for suggestion in matches: if not suggestion or suggestion == wrong_name: @@ -1787,6 +1798,17 @@ def print(self, *, file=None, chain=True, **kwargs): }) +# Cross-language keyword suggestions. +_CROSS_LANGUAGE_KEYWORD_HINTS = frozendict({ + # C/C++ equivalents + 'switch': 'match', + 'delete': 'del', + # function define equivalents + 'function': 'def', + 'func': 'def', + 'void': 'def', +}) + def _substitution_cost(ch_a, ch_b): if ch_a == ch_b: return 0 @@ -1866,6 +1888,12 @@ def _get_cross_language_hint(obj, wrong_name): return None +def _get_cross_language_keyword_hint(wrong_name): + """Check if wrong_name is a common keyword from another language + """ + return _CROSS_LANGUAGE_KEYWORD_HINTS.get(wrong_name) + + def _get_safe___dir__(obj): # Use obj.__dir__() to avoid a TypeError when calling dir(obj). # See gh-131001 and gh-139933. diff --git a/Misc/NEWS.d/next/Library/2026-06-12-00-17-29.gh-issue-151128.-LYO3a.rst b/Misc/NEWS.d/next/Library/2026-06-12-00-17-29.gh-issue-151128.-LYO3a.rst new file mode 100644 index 00000000000000..6e760686af2b01 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-12-00-17-29.gh-issue-151128.-LYO3a.rst @@ -0,0 +1,3 @@ +Cross-language keyword suggestions are now shown for :exc:`SyntaxError` messages. +For example, ``switch x:`` suggests ``match``, ``delete x`` suggests ``del``, +``function f():`` suggests ``def``. Contributed by Zang Langyan.