Skip to content

gh-57129: Add test for inspect.getsource in the REPL #111197

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 25, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 64 additions & 1 deletion Lib/test/test_inspect/test_inspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import shutil
import stat
import sys
import subprocess
import time
import types
import tempfile
Expand All @@ -35,7 +36,8 @@
from test.support import MISSING_C_DOCSTRINGS, ALWAYS_EQ
from test.support.import_helper import DirsOnSysPath, ready_to_import
from test.support.os_helper import TESTFN
from test.support.script_helper import assert_python_ok, assert_python_failure
from test.support.script_helper import assert_python_ok, assert_python_failure, kill_python
from test.support import has_subprocess_support, SuppressCrashReport
from test import support

from . import inspect_fodder as mod
Expand Down Expand Up @@ -4961,5 +4963,66 @@ def test_getsource_reload(self):
self.assertInspectEqual(path, module)


class TestRepl(unittest.TestCase):

def spawn_repl(self, *args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, **kw):
"""Run the Python REPL with the given arguments.

kw is extra keyword args to pass to subprocess.Popen. Returns a Popen
object.
"""

# To run the REPL without using a terminal, spawn python with the command
# line option '-i' and the process name set to '<stdin>'.
# The directory of argv[0] must match the directory of the Python
# executable for the Popen() call to python to succeed as the directory
# path may be used by Py_GetPath() to build the default module search
# path.
stdin_fname = os.path.join(os.path.dirname(sys.executable), "<stdin>")
cmd_line = [stdin_fname, '-E', '-i']
cmd_line.extend(args)

# Set TERM=vt100, for the rationale see the comments in spawn_python() of
# test.support.script_helper.
env = kw.setdefault('env', dict(os.environ))
env['TERM'] = 'vt100'
return subprocess.Popen(cmd_line,
executable=sys.executable,
text=True,
stdin=subprocess.PIPE,
stdout=stdout, stderr=stderr,
**kw)

def run_on_interactive_mode(self, source):
"""Spawn a new Python interpreter, pass the given
input source code from the stdin and return the
result back. If the interpreter exits non-zero, it
raises a ValueError."""

process = self.spawn_repl()
process.stdin.write(source)
output = kill_python(process)

if process.returncode != 0:
raise ValueError("Process didn't exit properly.")
return output

@unittest.skipIf(not has_subprocess_support, "test requires subprocess")
def test_getsource(self):
output = self.run_on_interactive_mode(textwrap.dedent("""\
def f():
print(0)
return 1 + 2

import inspect
print(f"The source is: <<<{inspect.getsource(f)}>>>")
"""))

expected = "The source is: <<<def f():\n print(0)\n return 1 + 2\n>>>"
self.assertIn(expected, output)




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