@@ -2269,30 +2269,37 @@ def _run_child(self, child, terminal_input):
22692269
22702270 return lines
22712271
2272- def check_input_tty (self , prompt , terminal_input , stdio_encoding = None ):
2272+ def check_input_tty (self , prompt , terminal_input , stdio_encoding = None , * ,
2273+ expected = None ,
2274+ stdin_errors = 'surrogateescape' ,
2275+ stdout_errors = 'replace' ):
22732276 if not sys .stdin .isatty () or not sys .stdout .isatty ():
22742277 self .skipTest ("stdin and stdout must be ttys" )
22752278 def child (wpipe ):
22762279 # Check the error handlers are accounted for
22772280 if stdio_encoding :
22782281 sys .stdin = io .TextIOWrapper (sys .stdin .detach (),
22792282 encoding = stdio_encoding ,
2280- errors = 'surrogateescape' )
2283+ errors = stdin_errors )
22812284 sys .stdout = io .TextIOWrapper (sys .stdout .detach (),
22822285 encoding = stdio_encoding ,
2283- errors = 'replace' )
2286+ errors = stdout_errors )
22842287 print ("tty =" , sys .stdin .isatty () and sys .stdout .isatty (), file = wpipe )
2285- print (ascii (input (prompt )), file = wpipe )
2288+ try :
2289+ print (ascii (input (prompt )), file = wpipe )
2290+ except BaseException as e :
2291+ print (ascii (f'{ e .__class__ .__name__ } : { e !s} ' ), file = wpipe )
22862292 lines = self .run_child (child , terminal_input + b"\r \n " )
22872293 # Check we did exercise the GNU readline path
22882294 self .assertIn (lines [0 ], {'tty = True' , 'tty = False' })
22892295 if lines [0 ] != 'tty = True' :
22902296 self .skipTest ("standard IO in should have been a tty" )
22912297 input_result = eval (lines [1 ]) # ascii() -> eval() roundtrip
2292- if stdio_encoding :
2293- expected = terminal_input .decode (stdio_encoding , 'surrogateescape' )
2294- else :
2295- expected = terminal_input .decode (sys .stdin .encoding ) # what else?
2298+ if expected is None :
2299+ if stdio_encoding :
2300+ expected = terminal_input .decode (stdio_encoding , 'surrogateescape' )
2301+ else :
2302+ expected = terminal_input .decode (sys .stdin .encoding ) # what else?
22962303 self .assertEqual (input_result , expected )
22972304
22982305 def test_input_tty (self ):
@@ -2313,13 +2320,32 @@ def skip_if_readline(self):
23132320 def test_input_tty_non_ascii (self ):
23142321 self .skip_if_readline ()
23152322 # Check stdin/stdout encoding is used when invoking PyOS_Readline()
2316- self .check_input_tty ("prompté" , b"quux\xe9 " , "utf-8" )
2323+ self .check_input_tty ("prompté" , b"quux\xc3 \xa9 " , "utf-8" )
23172324
23182325 def test_input_tty_non_ascii_unicode_errors (self ):
23192326 self .skip_if_readline ()
23202327 # Check stdin/stdout error handler is used when invoking PyOS_Readline()
23212328 self .check_input_tty ("prompté" , b"quux\xe9 " , "ascii" )
23222329
2330+ def test_input_tty_null_in_prompt (self ):
2331+ self .check_input_tty ("prompt\0 " , b"" ,
2332+ expected = 'ValueError: input: prompt string cannot contain '
2333+ 'null characters' )
2334+
2335+ def test_input_tty_nonencodable_prompt (self ):
2336+ self .skip_if_readline ()
2337+ self .check_input_tty ("prompté" , b"quux" , "ascii" , stdout_errors = 'strict' ,
2338+ expected = "UnicodeEncodeError: 'ascii' codec can't encode "
2339+ "character '\\ xe9' in position 6: ordinal not in "
2340+ "range(128)" )
2341+
2342+ def test_input_tty_nondecodable_input (self ):
2343+ self .skip_if_readline ()
2344+ self .check_input_tty ("prompt" , b"quux\xe9 " , "ascii" , stdin_errors = 'strict' ,
2345+ expected = "UnicodeDecodeError: 'ascii' codec can't decode "
2346+ "byte 0xe9 in position 4: ordinal not in "
2347+ "range(128)" )
2348+
23232349 def test_input_no_stdout_fileno (self ):
23242350 # Issue #24402: If stdin is the original terminal but stdout.fileno()
23252351 # fails, do not use the original stdout file descriptor
0 commit comments