Skip to content

Commit 3211d57

Browse files
authored
gh-57129: Add test for inspect.getsource in the REPL (#111197)
1 parent 8b44f3c commit 3211d57

File tree

1 file changed

+64
-1
lines changed

1 file changed

+64
-1
lines changed

Lib/test/test_inspect/test_inspect.py

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import shutil
1717
import stat
1818
import sys
19+
import subprocess
1920
import time
2021
import types
2122
import tempfile
@@ -35,7 +36,8 @@
3536
from test.support import MISSING_C_DOCSTRINGS, ALWAYS_EQ
3637
from test.support.import_helper import DirsOnSysPath, ready_to_import
3738
from test.support.os_helper import TESTFN
38-
from test.support.script_helper import assert_python_ok, assert_python_failure
39+
from test.support.script_helper import assert_python_ok, assert_python_failure, kill_python
40+
from test.support import has_subprocess_support, SuppressCrashReport
3941
from test import support
4042

4143
from . import inspect_fodder as mod
@@ -4961,5 +4963,66 @@ def test_getsource_reload(self):
49614963
self.assertInspectEqual(path, module)
49624964

49634965

4966+
class TestRepl(unittest.TestCase):
4967+
4968+
def spawn_repl(self, *args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, **kw):
4969+
"""Run the Python REPL with the given arguments.
4970+
4971+
kw is extra keyword args to pass to subprocess.Popen. Returns a Popen
4972+
object.
4973+
"""
4974+
4975+
# To run the REPL without using a terminal, spawn python with the command
4976+
# line option '-i' and the process name set to '<stdin>'.
4977+
# The directory of argv[0] must match the directory of the Python
4978+
# executable for the Popen() call to python to succeed as the directory
4979+
# path may be used by Py_GetPath() to build the default module search
4980+
# path.
4981+
stdin_fname = os.path.join(os.path.dirname(sys.executable), "<stdin>")
4982+
cmd_line = [stdin_fname, '-E', '-i']
4983+
cmd_line.extend(args)
4984+
4985+
# Set TERM=vt100, for the rationale see the comments in spawn_python() of
4986+
# test.support.script_helper.
4987+
env = kw.setdefault('env', dict(os.environ))
4988+
env['TERM'] = 'vt100'
4989+
return subprocess.Popen(cmd_line,
4990+
executable=sys.executable,
4991+
text=True,
4992+
stdin=subprocess.PIPE,
4993+
stdout=stdout, stderr=stderr,
4994+
**kw)
4995+
4996+
def run_on_interactive_mode(self, source):
4997+
"""Spawn a new Python interpreter, pass the given
4998+
input source code from the stdin and return the
4999+
result back. If the interpreter exits non-zero, it
5000+
raises a ValueError."""
5001+
5002+
process = self.spawn_repl()
5003+
process.stdin.write(source)
5004+
output = kill_python(process)
5005+
5006+
if process.returncode != 0:
5007+
raise ValueError("Process didn't exit properly.")
5008+
return output
5009+
5010+
@unittest.skipIf(not has_subprocess_support, "test requires subprocess")
5011+
def test_getsource(self):
5012+
output = self.run_on_interactive_mode(textwrap.dedent("""\
5013+
def f():
5014+
print(0)
5015+
return 1 + 2
5016+
5017+
import inspect
5018+
print(f"The source is: <<<{inspect.getsource(f)}>>>")
5019+
"""))
5020+
5021+
expected = "The source is: <<<def f():\n print(0)\n return 1 + 2\n>>>"
5022+
self.assertIn(expected, output)
5023+
5024+
5025+
5026+
49645027
if __name__ == "__main__":
49655028
unittest.main()

0 commit comments

Comments
 (0)