Skip to content

Commit ad7f171

Browse files
committed
Copy test_repl.py from CPython 3.8.3
1 parent b14d277 commit ad7f171

File tree

1 file changed

+98
-0
lines changed

1 file changed

+98
-0
lines changed

Lib/test/test_repl.py

+98
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
"""Test the interactive interpreter."""
2+
3+
import sys
4+
import os
5+
import unittest
6+
import subprocess
7+
from textwrap import dedent
8+
from test.support import cpython_only, SuppressCrashReport
9+
from test.support.script_helper import kill_python
10+
11+
def spawn_repl(*args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, **kw):
12+
"""Run the Python REPL with the given arguments.
13+
14+
kw is extra keyword args to pass to subprocess.Popen. Returns a Popen
15+
object.
16+
"""
17+
18+
# To run the REPL without using a terminal, spawn python with the command
19+
# line option '-i' and the process name set to '<stdin>'.
20+
# The directory of argv[0] must match the directory of the Python
21+
# executable for the Popen() call to python to succeed as the directory
22+
# path may be used by Py_GetPath() to build the default module search
23+
# path.
24+
stdin_fname = os.path.join(os.path.dirname(sys.executable), "<stdin>")
25+
cmd_line = [stdin_fname, '-E', '-i']
26+
cmd_line.extend(args)
27+
28+
# Set TERM=vt100, for the rationale see the comments in spawn_python() of
29+
# test.support.script_helper.
30+
env = kw.setdefault('env', dict(os.environ))
31+
env['TERM'] = 'vt100'
32+
return subprocess.Popen(cmd_line, executable=sys.executable,
33+
stdin=subprocess.PIPE,
34+
stdout=stdout, stderr=stderr,
35+
**kw)
36+
37+
class TestInteractiveInterpreter(unittest.TestCase):
38+
39+
@cpython_only
40+
def test_no_memory(self):
41+
# Issue #30696: Fix the interactive interpreter looping endlessly when
42+
# no memory. Check also that the fix does not break the interactive
43+
# loop when an exception is raised.
44+
user_input = """
45+
import sys, _testcapi
46+
1/0
47+
print('After the exception.')
48+
_testcapi.set_nomemory(0)
49+
sys.exit(0)
50+
"""
51+
user_input = dedent(user_input)
52+
user_input = user_input.encode()
53+
p = spawn_repl()
54+
with SuppressCrashReport():
55+
p.stdin.write(user_input)
56+
output = kill_python(p)
57+
self.assertIn(b'After the exception.', output)
58+
# Exit code 120: Py_FinalizeEx() failed to flush stdout and stderr.
59+
self.assertIn(p.returncode, (1, 120))
60+
61+
@cpython_only
62+
def test_multiline_string_parsing(self):
63+
# bpo-39209: Multiline string tokens need to be handled in the tokenizer
64+
# in two places: the interactive path and the non-interactive path.
65+
user_input = '''\
66+
x = """<?xml version="1.0" encoding="iso-8859-1"?>
67+
<test>
68+
<Users>
69+
<fun25>
70+
<limits>
71+
<total>0KiB</total>
72+
<kbps>0</kbps>
73+
<rps>1.3</rps>
74+
<connections>0</connections>
75+
</limits>
76+
<usages>
77+
<total>16738211KiB</total>
78+
<kbps>237.15</kbps>
79+
<rps>1.3</rps>
80+
<connections>0</connections>
81+
</usages>
82+
<time_to_refresh>never</time_to_refresh>
83+
<limit_exceeded_URL>none</limit_exceeded_URL>
84+
</fun25>
85+
</Users>
86+
</test>"""
87+
'''
88+
user_input = dedent(user_input)
89+
user_input = user_input.encode()
90+
p = spawn_repl()
91+
with SuppressCrashReport():
92+
p.stdin.write(user_input)
93+
output = kill_python(p)
94+
self.assertEqual(p.returncode, 0)
95+
96+
97+
if __name__ == "__main__":
98+
unittest.main()

0 commit comments

Comments
 (0)