Skip to content

Commit

Permalink
gh-118893: Evaluate all statements in the new REPL separately
Browse files Browse the repository at this point in the history
  • Loading branch information
pablogsal committed May 21, 2024
1 parent c4f9823 commit fcc44e6
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 5 deletions.
26 changes: 22 additions & 4 deletions Lib/_pyrepl/simple_interact.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import linecache
import sys
import code
import ast
from types import ModuleType

from .readline import _get_reader, multiline_input
Expand Down Expand Up @@ -77,6 +78,26 @@ def __init__(
def showtraceback(self):
super().showtraceback(colorize=self.can_colorize)

def runsource(self, source, filename="<input>", symbol="single"):
tree = ast.parse(source)
if tree.body:
*_, last_stmt = tree.body
for stmt in tree.body:
wrapper = ast.Interactive if stmt is last_stmt else ast.Module
the_symbol = symbol if stmt is last_stmt else "exec"
item = wrapper([stmt])
try:
code = compile(item, filename, the_symbol)
except (OverflowError, ValueError):
self.showsyntaxerror(filename)
return False

if code is None:
return True

self.runcode(code)
return False


def run_multiline_interactive_console(
mainmodule: ModuleType | None= None, future_flags: int = 0
Expand Down Expand Up @@ -144,10 +165,7 @@ def more_lines(unicodetext: str) -> bool:

input_name = f"<python-input-{input_n}>"
linecache._register_code(input_name, statement, "<stdin>") # type: ignore[attr-defined]
symbol = "single" if not contains_pasted_code else "exec"
more = console.push(_strip_final_indent(statement), filename=input_name, _symbol=symbol) # type: ignore[call-arg]
if contains_pasted_code and more:
more = console.push(_strip_final_indent(statement), filename=input_name, _symbol="single") # type: ignore[call-arg]
more = console.push(_strip_final_indent(statement), filename=input_name, _symbol="single") # type: ignore[call-arg]
assert not more
input_n += 1
except KeyboardInterrupt:
Expand Down
61 changes: 60 additions & 1 deletion Lib/test/test_pyrepl.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import itertools
import os
import rlcompleter
import sys
import tempfile
import unittest
from code import InteractiveConsole
from functools import partial
from unittest import TestCase
from unittest.mock import MagicMock, patch
from textwrap import dedent
import contextlib
import io

from test.support import requires
from test.support.import_helper import import_module
Expand Down Expand Up @@ -1002,5 +1004,62 @@ def test_up_arrow_after_ctrl_r(self):
self.assert_screen_equals(reader, "")


class TestSimpleInteract(unittest.TestCase):
def test_multiple_statements(self):
namespace = {}
code = dedent("""\
class A:
def foo(self):
pass
class B:
def bar(self):
pass
a = 1
a
""")
console = InteractiveColoredConsole(namespace, filename="<stdin>")
with (
patch.object(InteractiveColoredConsole, "showsyntaxerror") as showsyntaxerror,
patch.object(InteractiveColoredConsole, "runsource", wraps=console.runsource) as runsource,
):
more = console.push(code, filename="<stdin>", _symbol="single") # type: ignore[call-arg]
self.assertFalse(more)
showsyntaxerror.assert_not_called()


def test_multiple_statements_output(self):
namespace = {}
code = dedent("""\
b = 1
b
a = 1
a
""")
console = InteractiveColoredConsole(namespace, filename="<stdin>")
f = io.StringIO()
with contextlib.redirect_stdout(f):
more = console.push(code, filename="<stdin>", _symbol="single") # type: ignore[call-arg]
self.assertFalse(more)
self.assertEqual(f.getvalue(), "1\n")

def test_empty(self):
namespace = {}
code = ""
console = InteractiveColoredConsole(namespace, filename="<stdin>")
f = io.StringIO()
with contextlib.redirect_stdout(f):
more = console.push(code, filename="<stdin>", _symbol="single") # type: ignore[call-arg]
self.assertFalse(more)
self.assertEqual(f.getvalue(), "")


if __name__ == '__main__':
unittest.main()


if __name__ == '__main__':
unittest.main()

0 comments on commit fcc44e6

Please sign in to comment.