@@ -496,6 +496,52 @@ class StartupTests(TestBase):
496
496
# We want to ensure the initial state of subinterpreters
497
497
# matches expectations.
498
498
499
+ _subtest_count = 0
500
+
501
+ @contextlib .contextmanager
502
+ def subTest (self , * args ):
503
+ with super ().subTest (* args ) as ctx :
504
+ self ._subtest_count += 1
505
+ try :
506
+ yield ctx
507
+ finally :
508
+ if self ._debugged_in_subtest :
509
+ if self ._subtest_count == 1 :
510
+ # The first subtest adds a leading newline, so we
511
+ # compensate here by not printing a trailing newline.
512
+ print ('### end subtest debug ###' , end = '' )
513
+ else :
514
+ print ('### end subtest debug ###' )
515
+ self ._debugged_in_subtest = False
516
+
517
+ def debug (self , msg , * , header = None ):
518
+ if header :
519
+ self ._debug (f'--- { header } ---' )
520
+ if msg :
521
+ if msg .endswith (os .linesep ):
522
+ self ._debug (msg [:- len (os .linesep )])
523
+ else :
524
+ self ._debug (msg )
525
+ self ._debug ('<no newline>' )
526
+ self ._debug ('------' )
527
+ else :
528
+ self ._debug (msg )
529
+
530
+ _debugged = False
531
+ _debugged_in_subtest = False
532
+ def _debug (self , msg ):
533
+ if not self ._debugged :
534
+ print ()
535
+ self ._debugged = True
536
+ if self ._subtest is not None :
537
+ if True :
538
+ if not self ._debugged_in_subtest :
539
+ self ._debugged_in_subtest = True
540
+ print ('### start subtest debug ###' )
541
+ print (msg )
542
+ else :
543
+ print (msg )
544
+
499
545
def create_temp_dir (self ):
500
546
import tempfile
501
547
tmp = tempfile .mkdtemp (prefix = 'test_interpreters_' )
@@ -512,36 +558,42 @@ def write_script(self, *path, text):
512
558
outfile .write (dedent (text ))
513
559
return filename
514
560
515
- def run_cmd (self , cmd , * , cwd = None ):
561
+ @support .requires_subprocess ()
562
+ def run_python (self , argv , * , cwd = None ):
516
563
# This method is inspired by
517
564
# EmbeddingTestsMixin.run_embedded_interpreter() in test_embed.py.
518
565
import shlex
519
566
import subprocess
520
- assert cmd .startswith ('python3 ' ), repr (cmd )
521
- if cmd .startswith ('python3 ' ):
522
- cmd = cmd .replace ('python3' , sys .executable , 1 )
523
- argv = shlex .split (cmd )
524
- proc = subprocess .run (
525
- argv ,
526
- cwd = cwd ,
527
- capture_output = True ,
528
- text = True ,
529
- )
530
- if proc .stderr != '' :
531
- # This is a hack until _PyThreadState_MustExit() is fixed.
532
- proc .returncode = 1
567
+ if isinstance (argv , str ):
568
+ argv = shlex .split (argv )
569
+ argv = [sys .executable , * argv ]
570
+ try :
571
+ proc = subprocess .run (
572
+ argv ,
573
+ cwd = cwd ,
574
+ capture_output = True ,
575
+ text = True ,
576
+ )
577
+ except Exception as exc :
578
+ self .debug (f'# cmd: { shlex .join (argv )} ' )
579
+ if isinstance (exc , FileNotFoundError ) and not exc .filename :
580
+ if os .path .exists (argv [0 ]):
581
+ exists = 'exists'
582
+ else :
583
+ exists = 'does not exist'
584
+ self .debug (f'{ argv [0 ]} { exists } ' )
585
+ raise # re-raise
586
+ assert proc .stderr == '' or proc .returncode != 0 , proc .stderr
533
587
if proc .returncode != 0 and support .verbose :
534
- print (f'--- { cmd } failed ---' )
535
- print (f'stdout:\n { proc .stdout } ' )
536
- print (f'stderr:\n { proc .stderr } ' )
537
- print ('------' )
588
+ self .debug (f'# python3 { shlex .join (argv [1 :])} failed:' )
589
+ self .debug (proc .stdout , header = 'stdout' )
590
+ self .debug (proc .stderr , header = 'stderr' )
538
591
self .assertEqual (proc .returncode , 0 )
539
592
self .assertEqual (proc .stderr , '' )
540
593
return proc .stdout
541
594
542
595
def test_sys_path_0 (self ):
543
596
# The main interpreter's sys.path[0] should be used by subinterpreters.
544
-
545
597
script = '''
546
598
import sys
547
599
from test.support import interpreters
@@ -558,7 +610,6 @@ def test_sys_path_0(self):
558
610
}}, indent=4), flush=True)
559
611
""")
560
612
'''
561
-
562
613
# <tmp>/
563
614
# pkg/
564
615
# __init__.py
@@ -572,15 +623,15 @@ def test_sys_path_0(self):
572
623
self .write_script (cwd , 'script.py' , text = script )
573
624
574
625
cases = [
575
- ('python3 script.py' , cwd ),
576
- ('python3 -m script' , cwd ),
577
- ('python3 -m pkg' , cwd ),
578
- ('python3 -m pkg.script' , cwd ),
579
- ('python3 -c "import script"' , '' ),
626
+ ('script.py' , cwd ),
627
+ ('-m script' , cwd ),
628
+ ('-m pkg' , cwd ),
629
+ ('-m pkg.script' , cwd ),
630
+ ('-c "import script"' , '' ),
580
631
]
581
- for cmd , expected in cases :
582
- with self .subTest (cmd ):
583
- out = self .run_cmd ( cmd , cwd = cwd )
632
+ for argv , expected in cases :
633
+ with self .subTest (f'python3 { argv } ' ):
634
+ out = self .run_python ( argv , cwd = cwd )
584
635
data = json .loads (out )
585
636
sp0_main , sp0_sub = data ['main' ], data ['sub' ]
586
637
self .assertEqual (sp0_sub , sp0_main )
0 commit comments