@@ -205,62 +205,84 @@ def test_excepthook(self):
205205    # Python/pythonrun.c::PyErr_PrintEx() is tricky. 
206206
207207
208+ def  raise_system_exit (* args , ** kwargs ):
209+     raise  SystemExit (* args , ** kwargs )
210+ 
211+ 
208212class  SysModuleTest (unittest .TestCase ):
209213
210214    def  tearDown (self ):
211215        test .support .reap_children ()
212216
213217    def  test_exit (self ):
214-         # call with two arguments 
218+         # call with two arguments is only forbidden for sys.exit()  
215219        self .assertRaises (TypeError , sys .exit , 42 , 42 )
220+         with  self .subTest ('sys.exit' ):
221+             self .do_test_exit (sys .exit )
222+         with  self .subTest ('raise SystemExit' ):
223+             self .do_test_exit (raise_system_exit )
216224
225+     def  do_test_exit (self , sys_exit_raiser ):
217226        # call without argument 
218227        with  self .assertRaises (SystemExit ) as  cm :
219-             sys . exit ()
228+             sys_exit_raiser ()
220229        self .assertIsNone (cm .exception .code )
230+         with  self .assertRaises (SystemExit ) as  cm :
231+             sys_exit_raiser (None )
232+         self .assertIsNone (cm .exception .code )
233+ 
234+         # call with integer argument 
235+         with  self .assertRaises (SystemExit ) as  cm :
236+             sys_exit_raiser (42 )
237+         self .assertEqual (cm .exception .code , 42 )
238+ 
239+         # gh-133548: call with tuple argument with one entry 
240+         with  self .assertRaises (SystemExit ) as  cm :
241+             sys_exit_raiser ((42 ,))
242+         self .assertEqual (cm .exception .code , (42 ,))
243+ 
244+         # call with string argument 
245+         with  self .assertRaises (SystemExit ) as  cm :
246+             sys_exit_raiser ("exit" )
247+         self .assertEqual (cm .exception .code , "exit" )
248+ 
249+         # call with tuple argument with two entries 
250+         with  self .assertRaises (SystemExit ) as  cm :
251+             sys_exit_raiser ((42 , 42 ))
252+         self .assertEqual (cm .exception .args , ((42 , 42 ),))
253+         self .assertEqual (cm .exception .code , (42 , 42 ))
254+ 
255+     def  test_exit_message (self ):
256+         with  self .subTest ('sys.exit' ):
257+             self .do_test_exit_message ("sys.exit" )
258+         with  self .subTest ('raise SystemExit' ):
259+             self .do_test_exit_message ("raise SystemExit" )
260+ 
261+     def  do_test_exit_message (self , call_statement ):
262+         def  sys_exit_impl (value = '' , prolog = '' ):
263+             return  f'import sys\n { prolog } \n { call_statement } { value }  
221264
222-         rc , out , err  =  assert_python_ok ('-c' , 'import sys; sys.exit()' )
265+         rc , out , err  =  assert_python_ok ('-c' , sys_exit_impl () )
223266        self .assertEqual (rc , 0 )
224267        self .assertEqual (out , b'' )
225268        self .assertEqual (err , b'' )
226269
227270        # gh-125842: Windows uses 32-bit unsigned integers for exit codes 
228271        # so a -1 exit code is sometimes interpreted as 0xffff_ffff. 
229-         rc , out , err  =  assert_python_failure ('-c' , 'import sys; sys.exit (0xffff_ffff)' 
272+         rc , out , err  =  assert_python_failure ('-c' , sys_exit_impl (0xffff_ffff ))
230273        self .assertIn (rc , (- 1 , 0xff , 0xffff_ffff ))
231274        self .assertEqual (out , b'' )
232275        self .assertEqual (err , b'' )
233276
234277        # Overflow results in a -1 exit code, which may be converted to 0xff 
235278        # or 0xffff_ffff. 
236-         rc , out , err  =  assert_python_failure ('-c' , 'import sys; sys.exit (2**128)' 
279+         rc , out , err  =  assert_python_failure ('-c' , sys_exit_impl (2 ** 128 ))
237280        self .assertIn (rc , (- 1 , 0xff , 0xffff_ffff ))
238281        self .assertEqual (out , b'' )
239282        self .assertEqual (err , b'' )
240283
241-         # call with integer argument 
242-         with  self .assertRaises (SystemExit ) as  cm :
243-             sys .exit (42 )
244-         self .assertEqual (cm .exception .code , 42 )
245- 
246-         # call with tuple argument with one entry 
247-         # entry will be unpacked 
248-         with  self .assertRaises (SystemExit ) as  cm :
249-             sys .exit ((42 ,))
250-         self .assertEqual (cm .exception .code , 42 )
251- 
252-         # call with string argument 
253-         with  self .assertRaises (SystemExit ) as  cm :
254-             sys .exit ("exit" )
255-         self .assertEqual (cm .exception .code , "exit" )
256- 
257-         # call with tuple argument with two entries 
258-         with  self .assertRaises (SystemExit ) as  cm :
259-             sys .exit ((17 , 23 ))
260-         self .assertEqual (cm .exception .code , (17 , 23 ))
261- 
262-         # test that the exit machinery handles SystemExits properly 
263-         rc , out , err  =  assert_python_failure ('-c' , 'raise SystemExit(47)' )
284+         # test that the exit machinery handles custom codes properly 
285+         rc , out , err  =  assert_python_failure ('-c' , sys_exit_impl (47 ))
264286        self .assertEqual (rc , 47 )
265287        self .assertEqual (out , b'' )
266288        self .assertEqual (err , b'' )
@@ -274,20 +296,20 @@ def check_exit_message(code, expected, **env_vars):
274296        # test that stderr buffer is flushed before the exit message is written 
275297        # into stderr 
276298        check_exit_message (
277-             r'import sys; sys.stderr.write("unflushed,"); sys.exit("message")' ,
278-             b"unflushed,message" )
299+             sys_exit_impl ("'message'" , 'sys.stderr.write("unflushed,")' ),
300+             b"unflushed,message" 
301+         )
279302
280303        # test that the exit message is written with backslashreplace error 
281304        # handler to stderr 
282-         check_exit_message (
283-             r'import sys; sys.exit("surrogates:\uDCFF")' ,
284-             b"surrogates:\\ udcff" )
305+         check_exit_message (sys_exit_impl (r"'surrogates:\uDCFF'" ),
306+                            b"surrogates:\\ udcff" )
285307
286308        # test that the unicode message is encoded to the stderr encoding 
287309        # instead of the default encoding (utf8) 
288-         check_exit_message (
289-             r'import sys; sys.exit("h\xe9")' , 
290-              b"h \xe9 " ,  PYTHONIOENCODING = 'latin-1' ) 
310+         check_exit_message (sys_exit_impl ( r"'h\xe9'" ),  b"h \xe9 " , 
311+                             PYTHONIOENCODING = 'latin-1' ) 
312+ 
291313
292314    @support .requires_subprocess () 
293315    def  test_exit_codes_under_repl (self ):
0 commit comments