44import asyncio
55import builtins
66import collections
7+ import contextlib
78import decimal
89import fractions
910import gc
3031from operator import neg
3132from test import support
3233from test .support import (cpython_only , swap_attr , maybe_get_event_loop_policy )
34+ from test .support .import_helper import import_module
3335from test .support .os_helper import (EnvironmentVarGuard , TESTFN , unlink )
3436from test .support .script_helper import assert_python_ok
3537from test .support .warnings_helper import check_warnings
@@ -2369,7 +2371,8 @@ def child(wpipe):
23692371 print (ascii (input (prompt )), file = wpipe )
23702372 except BaseException as e :
23712373 print (ascii (f'{ e .__class__ .__name__ } : { e !s} ' ), file = wpipe )
2372- lines = self .run_child (child , terminal_input + b"\r \n " )
2374+ with self .detach_readline ():
2375+ lines = self .run_child (child , terminal_input + b"\r \n " )
23732376 # Check we did exercise the GNU readline path
23742377 self .assertIn (lines [0 ], {'tty = True' , 'tty = False' })
23752378 if lines [0 ] != 'tty = True' :
@@ -2382,28 +2385,36 @@ def child(wpipe):
23822385 expected = terminal_input .decode (sys .stdin .encoding ) # what else?
23832386 self .assertEqual (input_result , expected )
23842387
2385- def test_input_tty (self ):
2386- # Test input() functionality when wired to a tty (the code path
2387- # is different and invokes GNU readline if available).
2388- self .check_input_tty ("prompt" , b"quux" )
2389-
2390- def skip_if_readline (self ):
2388+ @contextlib .contextmanager
2389+ def detach_readline (self ):
23912390 # bpo-13886: When the readline module is loaded, PyOS_Readline() uses
23922391 # the readline implementation. In some cases, the Python readline
23932392 # callback rlhandler() is called by readline with a string without
2394- # non-ASCII characters. Skip tests on non-ASCII characters if the
2395- # readline module is loaded, since test_builtin is not intended to test
2393+ # non-ASCII characters.
2394+ # Unlink readline temporarily from PyOS_Readline() for those tests,
2395+ # since test_builtin is not intended to test
23962396 # the readline module, but the builtins module.
2397- if 'readline' in sys .modules :
2398- self .skipTest ("the readline module is loaded" )
2397+ if "readline" in sys .modules :
2398+ c = import_module ("ctypes" )
2399+ fp_api = "PyOS_ReadlineFunctionPointer"
2400+ prev_value = c .c_void_p .in_dll (c .pythonapi , fp_api ).value
2401+ c .c_void_p .in_dll (c .pythonapi , fp_api ).value = None
2402+ try :
2403+ yield
2404+ finally :
2405+ c .c_void_p .in_dll (c .pythonapi , fp_api ).value = prev_value
2406+ else :
2407+ yield
2408+
2409+ def test_input_tty (self ):
2410+ # Test input() functionality when wired to a tty
2411+ self .check_input_tty ("prompt" , b"quux" )
23992412
24002413 def test_input_tty_non_ascii (self ):
2401- self .skip_if_readline ()
24022414 # Check stdin/stdout encoding is used when invoking PyOS_Readline()
24032415 self .check_input_tty ("prompté" , b"quux\xc3 \xa9 " , "utf-8" )
24042416
24052417 def test_input_tty_non_ascii_unicode_errors (self ):
2406- self .skip_if_readline ()
24072418 # Check stdin/stdout error handler is used when invoking PyOS_Readline()
24082419 self .check_input_tty ("prompté" , b"quux\xe9 " , "ascii" )
24092420
@@ -2413,14 +2424,12 @@ def test_input_tty_null_in_prompt(self):
24132424 'null characters' )
24142425
24152426 def test_input_tty_nonencodable_prompt (self ):
2416- self .skip_if_readline ()
24172427 self .check_input_tty ("prompté" , b"quux" , "ascii" , stdout_errors = 'strict' ,
24182428 expected = "UnicodeEncodeError: 'ascii' codec can't encode "
24192429 "character '\\ xe9' in position 6: ordinal not in "
24202430 "range(128)" )
24212431
24222432 def test_input_tty_nondecodable_input (self ):
2423- self .skip_if_readline ()
24242433 self .check_input_tty ("prompt" , b"quux\xe9 " , "ascii" , stdin_errors = 'strict' ,
24252434 expected = "UnicodeDecodeError: 'ascii' codec can't decode "
24262435 "byte 0xe9 in position 4: ordinal not in "
0 commit comments