Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 354d55e

Browse filesBrowse files
authored
pythongh-121804: Always show error location for SyntaxError's in new repl (python#121886)
1 parent e077b20 commit 354d55e
Copy full SHA for 354d55e

File tree

5 files changed

+36
-10
lines changed
Filter options

5 files changed

+36
-10
lines changed

‎Lib/_pyrepl/console.py

Copy file name to clipboardExpand all lines: Lib/_pyrepl/console.py
+6-3Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,9 @@ def __init__(
161161
super().__init__(locals=locals, filename=filename, local_exit=local_exit) # type: ignore[call-arg]
162162
self.can_colorize = _colorize.can_colorize()
163163

164+
def showsyntaxerror(self, filename=None, **kwargs):
165+
super().showsyntaxerror(**kwargs)
166+
164167
def _excepthook(self, typ, value, tb):
165168
import traceback
166169
lines = traceback.format_exception(
@@ -173,7 +176,7 @@ def runsource(self, source, filename="<input>", symbol="single"):
173176
try:
174177
tree = ast.parse(source)
175178
except (SyntaxError, OverflowError, ValueError):
176-
self.showsyntaxerror(filename)
179+
self.showsyntaxerror(filename, source=source)
177180
return False
178181
if tree.body:
179182
*_, last_stmt = tree.body
@@ -190,10 +193,10 @@ def runsource(self, source, filename="<input>", symbol="single"):
190193
f"Try the asyncio REPL ({python} -m asyncio) to use"
191194
f" top-level 'await' and run background asyncio tasks."
192195
)
193-
self.showsyntaxerror(filename)
196+
self.showsyntaxerror(filename, source=source)
194197
return False
195198
except (OverflowError, ValueError):
196-
self.showsyntaxerror(filename)
199+
self.showsyntaxerror(filename, source=source)
197200
return False
198201

199202
if code is None:

‎Lib/code.py

Copy file name to clipboardExpand all lines: Lib/code.py
+13-6Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ def runsource(self, source, filename="<input>", symbol="single"):
6464
code = self.compile(source, filename, symbol)
6565
except (OverflowError, SyntaxError, ValueError):
6666
# Case 1
67-
self.showsyntaxerror(filename)
67+
self.showsyntaxerror(filename, source=source)
6868
return False
6969

7070
if code is None:
@@ -94,7 +94,7 @@ def runcode(self, code):
9494
except:
9595
self.showtraceback()
9696

97-
def showsyntaxerror(self, filename=None):
97+
def showsyntaxerror(self, filename=None, **kwargs):
9898
"""Display the syntax error that just occurred.
9999
100100
This doesn't display a stack trace because there isn't one.
@@ -118,7 +118,8 @@ def showsyntaxerror(self, filename=None):
118118
else:
119119
# Stuff in the right filename
120120
value = SyntaxError(msg, (filename, lineno, offset, line))
121-
self._showtraceback(typ, value, None)
121+
source = kwargs.pop('source', "")
122+
self._showtraceback(typ, value, None, source)
122123
finally:
123124
typ = value = tb = None
124125

@@ -132,14 +133,20 @@ def showtraceback(self):
132133
"""
133134
try:
134135
typ, value, tb = sys.exc_info()
135-
self._showtraceback(typ, value, tb.tb_next)
136+
self._showtraceback(typ, value, tb.tb_next, "")
136137
finally:
137138
typ = value = tb = None
138139

139-
def _showtraceback(self, typ, value, tb):
140+
def _showtraceback(self, typ, value, tb, source):
140141
sys.last_type = typ
141142
sys.last_traceback = tb
142-
sys.last_exc = sys.last_value = value = value.with_traceback(tb)
143+
value = value.with_traceback(tb)
144+
# Set the line of text that the exception refers to
145+
lines = source.splitlines()
146+
if (source and typ is SyntaxError
147+
and not value.text and len(lines) >= value.lineno):
148+
value.text = lines[value.lineno - 1]
149+
sys.last_exc = sys.last_value = value
143150
if sys.excepthook is sys.__excepthook__:
144151
self._excepthook(typ, value, tb)
145152
else:

‎Lib/idlelib/pyshell.py

Copy file name to clipboardExpand all lines: Lib/idlelib/pyshell.py
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -706,7 +706,7 @@ def prepend_syspath(self, filename):
706706
del _filename, _sys, _dirname, _dir
707707
\n""".format(filename))
708708

709-
def showsyntaxerror(self, filename=None):
709+
def showsyntaxerror(self, filename=None, **kwargs):
710710
"""Override Interactive Interpreter method: Use Colorizing
711711
712712
Color the offending position instead of printing it and pointing at it

‎Lib/test/test_pyrepl/test_interact.py

Copy file name to clipboardExpand all lines: Lib/test/test_pyrepl/test_interact.py
+14Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,20 @@ def test_runsource_returns_false_for_failed_compilation(self):
8888
self.assertFalse(result)
8989
self.assertIn('SyntaxError', f.getvalue())
9090

91+
@force_not_colorized
92+
def test_runsource_show_syntax_error_location(self):
93+
console = InteractiveColoredConsole()
94+
source = "def f(x, x): ..."
95+
f = io.StringIO()
96+
with contextlib.redirect_stderr(f):
97+
result = console.runsource(source)
98+
self.assertFalse(result)
99+
r = """
100+
def f(x, x): ...
101+
^
102+
SyntaxError: duplicate argument 'x' in function definition"""
103+
self.assertIn(r, f.getvalue())
104+
91105
def test_runsource_shows_syntax_error_for_failed_compilation(self):
92106
console = InteractiveColoredConsole()
93107
source = "print('Hello, world!'"
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Correctly show error locations, when :exc:`SyntaxError` raised in new repl.
2+
Patch by Sergey B Kirpichev.

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.