Skip to content

Commit 59b63dd

Browse files
committed
pythongh-116402: Avoid readline in test_builtin TTY input tests
1 parent 2408a8a commit 59b63dd

File tree

1 file changed

+43
-27
lines changed

1 file changed

+43
-27
lines changed

Lib/test/test_builtin.py

Lines changed: 43 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
import asyncio
55
import builtins
66
import collections
7+
import contextlib
78
import decimal
89
import fractions
910
import gc
1011
import io
12+
import importlib
1113
import locale
1214
import math
1315
import os
@@ -2400,49 +2402,63 @@ def child(wpipe):
24002402
expected = terminal_input.decode(sys.stdin.encoding) # what else?
24012403
self.assertEqual(input_result, expected)
24022404

2403-
def test_input_tty(self):
2404-
# Test input() functionality when wired to a tty (the code path
2405-
# is different and invokes GNU readline if available).
2406-
self.check_input_tty("prompt", b"quux")
2407-
2408-
def skip_if_readline(self):
2405+
@contextlib.contextmanager
2406+
def detach_readline(self):
24092407
# bpo-13886: When the readline module is loaded, PyOS_Readline() uses
24102408
# the readline implementation. In some cases, the Python readline
24112409
# callback rlhandler() is called by readline with a string without
2412-
# non-ASCII characters. Skip tests on non-ASCII characters if the
2413-
# readline module is loaded, since test_builtin is not intended to test
2410+
# non-ASCII characters.
2411+
# Unlink readline temporarily from PyOS_Readline() for those tests,
2412+
# since test_builtin is not intended to test
24142413
# the readline module, but the builtins module.
2415-
if 'readline' in sys.modules:
2416-
self.skipTest("the readline module is loaded")
2414+
if "readline" in sys.modules:
2415+
try:
2416+
c = importlib.import_module("ctypes")
2417+
except ImportError:
2418+
self.skipTest("the readline module is loaded")
2419+
2420+
fp_api = "PyOS_ReadlineFunctionPointer"
2421+
prev_value = c.c_void_p.in_dll(c.pythonapi, fp_api).value
2422+
c.c_void_p.in_dll(c.pythonapi, fp_api).value = None
2423+
yield
2424+
c.c_void_p.in_dll(c.pythonapi, fp_api).value = prev_value
2425+
else:
2426+
yield
2427+
2428+
def test_input_tty(self):
2429+
# Test input() functionality when wired to a tty
2430+
with self.detach_readline():
2431+
self.check_input_tty("prompt", b"quux")
24172432

24182433
def test_input_tty_non_ascii(self):
2419-
self.skip_if_readline()
24202434
# Check stdin/stdout encoding is used when invoking PyOS_Readline()
2421-
self.check_input_tty("prompté", b"quux\xc3\xa9", "utf-8")
2435+
with self.detach_readline():
2436+
self.check_input_tty("prompté", b"quux\xc3\xa9", "utf-8")
24222437

24232438
def test_input_tty_non_ascii_unicode_errors(self):
2424-
self.skip_if_readline()
24252439
# Check stdin/stdout error handler is used when invoking PyOS_Readline()
2426-
self.check_input_tty("prompté", b"quux\xe9", "ascii")
2440+
with self.detach_readline():
2441+
self.check_input_tty("prompté", b"quux\xe9", "ascii")
24272442

24282443
def test_input_tty_null_in_prompt(self):
2429-
self.check_input_tty("prompt\0", b"",
2430-
expected='ValueError: input: prompt string cannot contain '
2431-
'null characters')
2444+
with self.detach_readline():
2445+
self.check_input_tty("prompt\0", b"",
2446+
expected='ValueError: input: prompt string cannot contain '
2447+
'null characters')
24322448

24332449
def test_input_tty_nonencodable_prompt(self):
2434-
self.skip_if_readline()
2435-
self.check_input_tty("prompté", b"quux", "ascii", stdout_errors='strict',
2436-
expected="UnicodeEncodeError: 'ascii' codec can't encode "
2437-
"character '\\xe9' in position 6: ordinal not in "
2438-
"range(128)")
2450+
with self.detach_readline():
2451+
self.check_input_tty("prompté", b"quux", "ascii", stdout_errors='strict',
2452+
expected="UnicodeEncodeError: 'ascii' codec can't encode "
2453+
"character '\\xe9' in position 6: ordinal not in "
2454+
"range(128)")
24392455

24402456
def test_input_tty_nondecodable_input(self):
2441-
self.skip_if_readline()
2442-
self.check_input_tty("prompt", b"quux\xe9", "ascii", stdin_errors='strict',
2443-
expected="UnicodeDecodeError: 'ascii' codec can't decode "
2444-
"byte 0xe9 in position 4: ordinal not in "
2445-
"range(128)")
2457+
with self.detach_readline():
2458+
self.check_input_tty("prompt", b"quux\xe9", "ascii", stdin_errors='strict',
2459+
expected="UnicodeDecodeError: 'ascii' codec can't decode "
2460+
"byte 0xe9 in position 4: ordinal not in "
2461+
"range(128)")
24462462

24472463
def test_input_no_stdout_fileno(self):
24482464
# Issue #24402: If stdin is the original terminal but stdout.fileno()

0 commit comments

Comments
 (0)