Skip to content

Commit cf4a5a0

Browse files
Update docs and tests changed by GH-157585
Too complex source now raises SyntaxError, so the tests inject MemoryError to test that any compile() error is reported. Compiling a too deeply nested AST object still raises RecursionError. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1 parent 8ed1a65 commit cf4a5a0

5 files changed

Lines changed: 19 additions & 16 deletions

File tree

‎Doc/builtins/functions.rst‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,7 @@ are always available. They are listed here in alphabetical order.
390390
that is too complex to parse or compile,
391391
for example an expression with many thousands of nested operators,
392392
or that is too large;
393+
:exc:`RecursionError` if an AST object *source* is too deeply nested;
393394
and :exc:`ValueError` if *mode* or *flags* is invalid.
394395

395396
If you want to parse Python code into its AST representation, see

‎Doc/library/code.rst‎

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,7 @@ build applications which provide an interactive interpreter prompt.
7474

7575
Returns a code object (the same as ``compile(source, filename, symbol)``) if the
7676
command is complete and valid; ``None`` if the command is incomplete; raises
77-
:exc:`SyntaxError` if the command is complete and contains a syntax error, or
78-
raises :exc:`OverflowError` or :exc:`ValueError` if the command contains an
79-
invalid literal.
77+
:exc:`SyntaxError` if the command is complete and invalid.
8078

8179

8280
.. _interpreter-objects:
@@ -91,8 +89,8 @@ Interactive Interpreter Objects
9189
:func:`compile_command`; the default for *filename* is ``'<input>'``, and for
9290
*symbol* is ``'single'``. One of several things can happen:
9391

94-
* The input is incorrect; :func:`compile_command` raised an exception
95-
(usually :exc:`SyntaxError`). A syntax traceback will be
92+
* The input is incorrect; :func:`compile_command` raised
93+
:exc:`SyntaxError`. A syntax traceback will be
9694
printed by calling the :meth:`showsyntaxerror` method. :meth:`runsource`
9795
returns ``False``.
9896

‎Lib/code.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def runsource(self, source, filename="<input>", symbol="single"):
4444
One of several things can happen:
4545
4646
1) The input is incorrect; compile_command() raised an
47-
exception (usually SyntaxError). A syntax traceback will be
47+
exception (SyntaxError). A syntax traceback will be
4848
printed by calling the showsyntaxerror() method.
4949
5050
2) The input is incomplete, and more input is required;

‎Lib/test/test_code_module.py‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -146,13 +146,15 @@ def test_unicode_error(self):
146146

147147
def test_compile_error(self):
148148
# Any error raised by compile() must be reported (gh-69919).
149-
self.infunc.side_effect = ['-' * 100_000 + '1', EOFError('Finished')]
150-
self.console.interact()
149+
self.infunc.side_effect = ['1', EOFError('Finished')]
150+
with mock.patch.object(self.console, 'compile',
151+
side_effect=MemoryError('spam')):
152+
self.console.interact()
151153
output = ''.join(''.join(call[1]) for call in self.stderr.method_calls)
152154
output = output[output.index('(InteractiveConsole)'):]
153155
output = output[output.index('\n') + 1:]
154-
self.assertRegex(output, r'^(MemoryError|RecursionError): ')
155-
self.assertIn(self.sysmod.last_type, (MemoryError, RecursionError))
156+
self.assertRegex(output, r'^MemoryError: spam\n')
157+
self.assertIs(self.sysmod.last_type, MemoryError)
156158
self.assertIs(self.sysmod.last_exc, self.sysmod.last_value)
157159

158160
def test_sysexcepthook(self):

‎Lib/test/test_pyrepl/test_interact.py‎

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -135,12 +135,13 @@ def test_runsource_shows_syntax_error_for_failed_compilation(self):
135135
def test_runsource_compile_error(self):
136136
# Any error raised by compile() is reported (gh-69919).
137137
console = InteractiveColoredConsole()
138-
source = '-' * 100_000 + '1'
139138
f = io.StringIO()
140-
with contextlib.redirect_stderr(f):
141-
result = console.runsource(source)
139+
with (contextlib.redirect_stderr(f),
140+
patch.object(console.compile, 'compiler',
141+
side_effect=MemoryError('spam'))):
142+
result = console.runsource('1')
142143
self.assertFalse(result)
143-
self.assertRegex(f.getvalue(), r'^(MemoryError|RecursionError): ')
144+
self.assertRegex(f.getvalue(), r'^MemoryError: spam$')
144145

145146
def test_runsource_survives_null_bytes(self):
146147
console = InteractiveColoredConsole()
@@ -195,9 +196,10 @@ def test_invalid_syntax_single_line(self):
195196

196197
def test_compile_error_single_line(self):
197198
namespace = {}
198-
code = '-' * 100_000 + '1' # MemoryError or RecursionError
199+
code = "1"
199200
console = InteractiveColoredConsole(namespace, filename="<stdin>")
200-
self.assertFalse(_more_lines(console, code))
201+
with patch.object(console, 'compile', side_effect=MemoryError):
202+
self.assertFalse(_more_lines(console, code))
201203

202204
def test_empty_line(self):
203205
namespace = {}

0 commit comments

Comments
 (0)