Skip to content

Commit 123ff26

Browse files
authored
bpo-43591: Fix error location in interactive mode for errors at the end of the line (GH-24973)
Co-authored-by: Erlend Egeberg Aasland
1 parent 39f6436 commit 123ff26

File tree

2 files changed

+17
-7
lines changed

2 files changed

+17
-7
lines changed

Lib/test/test_cmd_line.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -851,13 +851,19 @@ def test_sys_flags_not_set(self):
851851
)
852852

853853
class SyntaxErrorTests(unittest.TestCase):
854-
def test_tokenizer_error_with_stdin(self):
855-
proc = subprocess.run([sys.executable, "-"], input = b"(1+2+3",
854+
def check_string(self, code):
855+
proc = subprocess.run([sys.executable, "-"], input=code,
856856
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
857857
self.assertNotEqual(proc.returncode, 0)
858858
self.assertNotEqual(proc.stderr, None)
859859
self.assertIn(b"\nSyntaxError", proc.stderr)
860860

861+
def test_tokenizer_error_with_stdin(self):
862+
self.check_string(b"(1+2+3")
863+
864+
def test_decoding_error_at_the_end_of_the_line(self):
865+
self.check_string(b"'\u1f'")
866+
861867
def test_main():
862868
support.run_unittest(CmdLineTest, IgnoreEnvironmentTest, SyntaxErrorTests)
863869
support.reap_children()

Parser/pegen.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,11 @@ byte_offset_to_character_offset(PyObject *line, Py_ssize_t col_offset)
147147
if (!str) {
148148
return 0;
149149
}
150-
assert(col_offset >= 0 && (unsigned long)col_offset <= strlen(str));
150+
Py_ssize_t len = strlen(str);
151+
if (col_offset > len) {
152+
col_offset = len;
153+
}
154+
assert(col_offset >= 0);
151155
PyObject *text = PyUnicode_DecodeUTF8(str, col_offset, "replace");
152156
if (!text) {
153157
return 0;
@@ -392,10 +396,10 @@ _PyPegen_raise_error(Parser *p, PyObject *errtype, const char *errmsg, ...)
392396
static PyObject *
393397
get_error_line(Parser *p, Py_ssize_t lineno)
394398
{
395-
/* If p->tok->fp == NULL, then we're parsing from a string, which means that
396-
the whole source is stored in p->tok->str. If not, then we're parsing
397-
from the REPL, so the source lines of the current (multi-line) statement
398-
are stored in p->tok->stdin_content */
399+
/* If the file descriptor is interactive, the source lines of the current
400+
* (multi-line) statement are stored in p->tok->interactive_src_start.
401+
* If not, we're parsing from a string, which means that the whole source
402+
* is stored in p->tok->str. */
399403
assert(p->tok->fp == NULL || p->tok->fp == stdin);
400404

401405
char *cur_line = p->tok->fp_interactive ? p->tok->interactive_src_start : p->tok->str;

0 commit comments

Comments
 (0)