-
-
Notifications
You must be signed in to change notification settings - Fork 34.5k
gh-146406: Add cross-language method suggestions for builtin AttributeError #146407
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 2 commits
7adad8b
aecaacb
6d58cdc
8a39e32
196dbe4
99e106a
57a4d39
2a2c0d5
f702e79
3ad54c8
0089761
e2c12ec
564ca3a
e1eb6f4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1153,6 +1153,11 @@ def __init__(self, exc_type, exc_value, exc_traceback, *, limit=None, | |
| self._str += f". Did you mean '.{suggestion}' instead of '.{wrong_name}'?" | ||
| else: | ||
| self._str += f". Did you mean '.{suggestion}' ({suggestion!a}) instead of '.{wrong_name}' ({wrong_name!a})?" | ||
| elif hasattr(exc_value, 'obj'): | ||
| with suppress(Exception): | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm, what needs to be suppressed here?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nothing realistic - |
||
| hint = _get_cross_language_hint(exc_value.obj, wrong_name) | ||
| if hint: | ||
| self._str += f". {hint}" | ||
| elif exc_type and issubclass(exc_type, NameError) and \ | ||
| getattr(exc_value, "name", None) is not None: | ||
| wrong_name = getattr(exc_value, "name", None) | ||
|
|
@@ -1649,6 +1654,45 @@ def print(self, *, file=None, chain=True, **kwargs): | |
| _MOVE_COST = 2 | ||
| _CASE_COST = 1 | ||
|
|
||
| # Cross-language method suggestions for builtin types. | ||
| # Consulted as a fallback when Levenshtein-based suggestions find no match. | ||
| # | ||
| # Inclusion criteria: | ||
| # 1. Must have evidence of real cross-language confusion (Stack Overflow | ||
|
vstinner marked this conversation as resolved.
|
||
| # traffic, bug reports in production repos, developer survey data) | ||
| # 2. Must not be catchable by Levenshtein distance (too different from | ||
| # the correct Python method name) | ||
| # 3. Must be from a top-4 language by Python co-usage: JavaScript, Java, | ||
| # C#, or Ruby (JetBrains/PSF Developer Survey 2024) | ||
|
vstinner marked this conversation as resolved.
Outdated
|
||
| # | ||
| # Each entry maps (builtin_type, wrong_name) to a suggestion string. | ||
| # If the suggestion is a Python method name, the standard "Did you mean" | ||
| # format is used. If it contains a space, it's rendered as a full hint. | ||
| # | ||
| # See https://discuss.python.org/t/106632 for the design discussion. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's link to the GH issue instead.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done, switched to the GH issue link. |
||
| _CROSS_LANGUAGE_HINTS = { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You might use a
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Applied in f702e79 - wrapped in
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You don't need
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice - frozendict is cleaner than the MappingProxyType wrapper. Thanks for applying it.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems like the frozendict was lost in the meanwhile. |
||
| # list -- JavaScript/Ruby equivalents | ||
| (list, "push"): "append", | ||
| (list, "concat"): "extend", | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd prefer to keep standard convention and just use a single space after the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Makes sense, dropped the alignment. |
||
| # list -- Java/C# equivalents | ||
| (list, "addAll"): "extend", | ||
| # list -- wrong-type suggestion (per Serhiy Storchaka, Terry Reedy, | ||
| # Paul Moore: list.add() more likely means the user expected a set) | ||
|
vstinner marked this conversation as resolved.
Outdated
|
||
| (list, "add"): "Did you mean to use a set? Sets have an .add() method", | ||
| # str -- JavaScript equivalents | ||
| (str, "toUpperCase"): "upper", | ||
| (str, "toLowerCase"): "lower", | ||
| (str, "trimStart"): "lstrip", | ||
| (str, "trimEnd"): "rstrip", | ||
| # dict -- Java equivalents | ||
| (dict, "keySet"): "keys", | ||
| (dict, "entrySet"): "items", | ||
| (dict, "putAll"): "update", | ||
| # Note: indexOf, trim, and getOrDefault are not included because | ||
| # Levenshtein distance already catches them (indexOf->index, | ||
| # trim->strip, getOrDefault->setdefault). | ||
| } | ||
|
|
||
|
|
||
| def _substitution_cost(ch_a, ch_b): | ||
| if ch_a == ch_b: | ||
|
|
@@ -1711,6 +1755,23 @@ def _check_for_nested_attribute(obj, wrong_name, attrs): | |
| return None | ||
|
|
||
|
|
||
| def _get_cross_language_hint(obj, wrong_name): | ||
| """Check if wrong_name is a common method name from another language. | ||
|
|
||
| Only checks exact builtin types (list, str, dict) to avoid false | ||
| positives on subclasses that may intentionally lack these methods. | ||
| Returns a formatted hint string, or None. | ||
| """ | ||
| hint = _CROSS_LANGUAGE_HINTS.get((type(obj), wrong_name)) | ||
| if hint is None: | ||
| return None | ||
| if ' ' in hint: | ||
| # Full custom hint (e.g., wrong-type suggestion for list.add) | ||
| return hint | ||
|
vstinner marked this conversation as resolved.
Outdated
|
||
| # Direct method equivalent -- format like Levenshtein suggestions | ||
| return f"Did you mean '.{hint}' instead of '.{wrong_name}'?" | ||
|
|
||
|
|
||
| def _get_safe___dir__(obj): | ||
| # Use obj.__dir__() to avoid a TypeError when calling dir(obj). | ||
| # See gh-131001 and gh-139933. | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,5 @@ | ||||||||
| Cross-language method suggestions are now shown for :exc:`AttributeError` on | ||||||||
| builtin types when the existing Levenshtein-based suggestions find no match. | ||||||||
| For example, ``[].push()`` now suggests ``append`` (JavaScript), and | ||||||||
| ``"".toUpperCase()`` suggests ``upper``. The ``list.add()`` case suggests | ||||||||
| using a set instead, following feedback from the community discussion. | ||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This last sentence isn't particularly useful:
Suggested change
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Applied your suggestion. |
||||||||
Uh oh!
There was an error while loading. Please reload this page.