-
-
Notifications
You must be signed in to change notification settings - Fork 30.3k
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
The new repl sometimes does not show the error location when SyntaxError
is raised
#121804
Comments
This issue is valid for basic repl as well:
|
These errors happen in different places (parser vs symtable): // symtable.c:1425
PyErr_Format(PyExc_SyntaxError, DUPLICATE_ARGUMENT, name);
SET_ERROR_LOCATION(st->st_filename, loc); So, I guess it is not related to the new repl. |
Exceptions metadata differ when compile() has valid filename argument wrt fake filename like >>> def f(x, x): ...
File "/tmp/tmpuygzaco0", line 1
def f(x, x): ...
^
SyntaxError: duplicate argument 'x' in function definition POC diffdiff --git a/Lib/_pyrepl/console.py b/Lib/_pyrepl/console.py
index a8d3f52034..0df16c2b3d 100644
--- a/Lib/_pyrepl/console.py
+++ b/Lib/_pyrepl/console.py
@@ -168,6 +168,12 @@ def showtraceback(self):
super().showtraceback(colorize=self.can_colorize)
def runsource(self, source, filename="<input>", symbol="single"):
+ import tempfile
+ import os
+ file = tempfile.NamedTemporaryFile('w+', delete=False)
+ file.write(source)
+ file.close()
+ filename = file.name
try:
tree = ast.parse(source)
except (SyntaxError, OverflowError, ValueError):
@@ -189,11 +195,15 @@ def runsource(self, source, filename="<input>", symbol="single"):
f" top-level 'await' and run background asyncio tasks."
)
self.showsyntaxerror(filename)
+ os.unlink(filename)
return False
except (OverflowError, ValueError):
self.showsyntaxerror(filename)
+ os.unlink(filename)
return False
+ os.unlink(filename)
+
if code is None:
return True
|
There are multiple systems / setups where temporary files could not be created:
Plus, I am not sure that users expect to see
There's also a question about how to append / rewrite / recreate this file on new statements. Storing state is hard :( |
imo fixing the core issue with the metadata is probably better than using a temp file for the reasons @sobolevn mentioned, but I don't know enough about the code to tell how hard that would be.. |
Yes, this is not easy:)
I think this can be fixed. On another hand, we have almost all required metadata for exception in it's attributes: >>> try:
... compile("def f(x,x): ...\n", "spam.py", "single")
... except Exception as e:
... print(e.lineno, e.offset)
...
1 9 The So, we can provide >>> def f(x, x): ...
File "<python-input-0>", line 1
def f(x, x): ...
^
SyntaxError: duplicate argument 'x' in function definition
>>> def f[Foo, Foo](): ...
File "<python-input-1>", line 1
def f[Foo, Foo](): ...
^^^
SyntaxError: duplicate type parameter 'Foo' POC patchdiff --git a/Lib/_pyrepl/console.py b/Lib/_pyrepl/console.py
index a8d3f52034..1eda92d49c 100644
--- a/Lib/_pyrepl/console.py
+++ b/Lib/_pyrepl/console.py
@@ -161,8 +161,8 @@ def __init__(
super().__init__(locals=locals, filename=filename, local_exit=local_exit) # type: ignore[call-arg]
self.can_colorize = _colorize.can_colorize()
- def showsyntaxerror(self, filename=None):
- super().showsyntaxerror(colorize=self.can_colorize)
+ def showsyntaxerror(self, filename=None, **kwargs):
+ super().showsyntaxerror(colorize=self.can_colorize, **kwargs)
def showtraceback(self):
super().showtraceback(colorize=self.can_colorize)
@@ -188,7 +188,7 @@ def runsource(self, source, filename="<input>", symbol="single"):
f"Try the asyncio REPL ({python} -m asyncio) to use"
f" top-level 'await' and run background asyncio tasks."
)
- self.showsyntaxerror(filename)
+ self.showsyntaxerror(filename, source=source)
return False
except (OverflowError, ValueError):
self.showsyntaxerror(filename)
diff --git a/Lib/code.py b/Lib/code.py
index a55fced070..78bcdcdca5 100644
--- a/Lib/code.py
+++ b/Lib/code.py
@@ -64,7 +64,7 @@ def runsource(self, source, filename="<input>", symbol="single"):
code = self.compile(source, filename, symbol)
except (OverflowError, SyntaxError, ValueError):
# Case 1
- self.showsyntaxerror(filename)
+ self.showsyntaxerror(filename, source=source)
return False
if code is None:
@@ -107,6 +107,7 @@ def showsyntaxerror(self, filename=None, **kwargs):
"""
colorize = kwargs.pop('colorize', False)
+ source = kwargs.pop('source', "")
type, value, tb = sys.exc_info()
sys.last_exc = value
sys.last_type = type
@@ -124,6 +125,8 @@ def showsyntaxerror(self, filename=None, **kwargs):
value = SyntaxError(msg, (filename, lineno, offset, line))
sys.last_exc = sys.last_value = value
if sys.excepthook is sys.__excepthook__:
+ if source:
+ value.text = source.splitlines()[value.lineno-1]
lines = traceback.format_exception_only(type, value, colorize=colorize)
self.write(''.join(lines))
else: If this is not too hackish way to deal with the issue - I'll make a pr. Edit: Similar fix is possible for basic repl. POC patch for basic repldiff --git a/Python/pythonrun.c b/Python/pythonrun.c
index ce7f194e92..43e12acb0e 100644
--- a/Python/pythonrun.c
+++ b/Python/pythonrun.c
@@ -283,6 +283,19 @@ PyRun_InteractiveOneObjectEx(FILE *fp, PyObject *filename,
_PyArena_Free(arena);
Py_DECREF(main_module);
if (res == NULL) {
+ PyThreadState *tstate = _PyThreadState_GET();
+ PyObject *exc = tstate->current_exception;
+ if ((PyObject *)Py_TYPE(exc) == PyExc_SyntaxError) {
+ /* fix "text" attribute */
+ PyObject *xs = PyUnicode_Splitlines(interactive_src, 1);
+ PyObject *ln = PyObject_GetAttr(exc, &_Py_ID(lineno));
+ PyObject *line = PyList_GetItem(xs, PyLong_AsLong(ln) - 1);
+ Py_DECREF(ln);
+ Py_INCREF(line);
+ Py_DECREF(xs);
+ PyObject_SetAttr(exc, &_Py_ID(text), line);
+ Py_DECREF(line);
+ }
return -1;
}
Py_DECREF(res); |
…repl >>> def good(x, y): ... ... def bad(x, x): ... File "<python-input-13>", line 2 def bad(x, x): ... ^ SyntaxError: duplicate argument 'x' in function definition
…repl >>> def good(x, y): ... ... def bad(x, x): ... File "<python-input-13>", line 2 def bad(x, x): ... ^ SyntaxError: duplicate argument 'x' in function definition
pr is ready for review: #121886 |
cc @pablogsal, maybe you could take look on pr? |
Will do today |
…in new repl (pythonGH-121886) (cherry picked from commit 354d55e) Co-authored-by: Sergey B Kirpichev <[email protected]>
@pablogsal, this is still valid, in the basic repl. Does it not worth fixing? |
Unless the fix is trivial I would prefer not to add extra complexity for just the fallback. |
You can see fixes (drafts) few commits above (for basic repl too): #121804 (comment) |
Ok, go for it, but that patch needs a bunch of handling for errors in these calls. If you decide to create a PR, please be aware that if it's a lot of code we may still decide to not go with that (although I personally I am happy to go forward). |
@pablogsal, here is a new pr: #123202 Still marked as a draft, because it crashes on debug builds. gdb shows it happens in PyUnicode_Check(interactive_src).
It could be reproduced on the current master with: diff --git a/Python/pythonrun.c b/Python/pythonrun.c
index ce7f194e92..2601c9268c 100644
--- a/Python/pythonrun.c
+++ b/Python/pythonrun.c
@@ -282,6 +282,10 @@ PyRun_InteractiveOneObjectEx(FILE *fp, PyObject *filename,
PyObject *res = run_mod(mod, filename, main_dict, main_dict, flags, arena, interactive_src, 1);
_PyArena_Free(arena);
Py_DECREF(main_module);
+ if (interactive_src) {
+ printf("float? - %d\n", PyFloat_Check(interactive_src));
+ printf("unicode? - %d\n", PyUnicode_Check(interactive_src));
+ }
if (res == NULL) {
return -1;
} Works on non-debug builds (prints 0 and then 1) and crashes on the first check for debug builds. I think it's a bug, but not with my code: the Should I report new issue? |
It's not a bug, the In debug mode crashes because the allocator has a special code that writes |
Thanks for help! Now pr is ready for review. |
To aid future backports here.
I'm reopening this issue (and add the labels) until we've merged the second PR (just for tracking purposes). |
…c repl (pythonGH-123202) (cherry picked from commit 6822cb2) Co-authored-by: Sergey B Kirpichev <[email protected]>
Bug report
Bug description:
When I run
def f[Foo, Foo](): ...
from a file, I get a nice error message including the location of the error:However, when I run this in the new repl, the error location is not shown:
The same thing happens with this error as well:
The missing location seems to be the case for these two errors only as other errors do show it:
What's interesting is that for the first two errors the file shows up as
<python-input-0>
while for the last one it's<unknown>
. This could be related to the last error coming from the parser while the previous errors come from symtable:cpython/Python/symtable.c
Lines 1421 to 1435 in 6522f0e
Though it looks like that the error location is being set with
SET_ERROR_LOCATION
..CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux
Linked PRs
The text was updated successfully, but these errors were encountered: