Now the question is that the suggestion list in NameError includes the f_builtins anyway:
However, when deleting a name, the interpreter won’t try to find the name in builtins. So you may see that the suggestions below playing football with you:
>>> del next
Traceback (most recent call last):
File "<python-input-0>", line 1, in <module>
del next
^^^^
NameError: name 'next' is not defined. Did you mean: 'anext'?
>>> del anext
Traceback (most recent call last):
File "<python-input-1>", line 1, in <module>
del anext
^^^^^
NameError: name 'anext' is not defined. Did you mean: 'next'?
To fix the question, I tried to make a change that add an attribute to describe which operation caused NameError. However, as you see, the change is too much and there are still many problems.
Is there a better way that can get the operation information with less change and less problem to fix this question?
As far as I know, you can’t delete names from the builtin scope. The error is telling you that next isn’t defined in the current global/local scope. del is a statement, which means it has its own semantics that doesn’t need to follow ordinary lookup rules like “find the name in the closest enclosing scope”.
However, it doesn’t solve the problem that how to exclude the builtins when NameError raised from del. In the suggestion function, it cannot distinguish. So I tried to add the attribute “op” to discribe which operation raised NameError. Is there another way?
You can see the code there. What is required is finding a way to distinguish the operations which raised NameError. For example, abc suggest “Did you mean ‘abs’? Or did you forgot to import ‘abc’?”, while del abc shouldn’t suggest “abs” because “abs” is a builtin function name.
Here’s a solution that doesn’t require modification to the language:
If the name is not in the global scope, but it is in the built-in scope, and it’s not an UnboundLocalError, then we assume the user is trying to delete a built-in name, and give an error message accordingly.
To take a step further, I think we should only provide typo suggestions when the name in question truly isn’t defined. If the name in question exists somewhere in the relevant namespaces but can’t be accessed anyway, we should just say “NAME couldn’t be accessed” or the like.
A simple solution. However, if the name what user tried to delete is similar to one of the builtins name, this builtins name will still interfent the suggestion (e.g. the name “abc” vs “abs” in above discussion), so it is a better but not best solution.
The key is for _compute_suggestion_error to avoid including f_builtins in the list of candidates when a NameError is raised from a del statement, which always compiles into a DELETE_* bytecode, which we can check by looking at the bytecode that f_lasti points to.
So the problem can be solved by minimally changing:
d = (
list(frame.f_locals)
+ list(frame.f_globals)
+ list(frame.f_builtins)
)
to (after importing dis):
d = (
list(frame.f_locals)
+ list(frame.f_globals)
)
if not dis.opname[frame.f_code.co_code[frame.f_lasti]].startswith('DELETE_'):
d += frame.f_builtins
Magicly! Even in the other language shell it can also work:
PS C:\Users\hh180\OneDrive\Desktop\node_python_bridge> node
Welcome to Node.js v24.1.0.
Type ".help" for more information.
> const bridge = require('bindings')('pybridge');
undefined
> bridge.runPython("del abc")
Traceback (most recent call last):
File "<string>", line 1, in <module>
NameError: name 'abc' is not defined. Did you forget to import 'abc'?
Uncaught Error: Python execution failed (see stderr)
>