55Licensed to the PSF under a contributor agreement. 
66""" 
77
8+ import  contextlib 
89import  ensurepip 
910import  os 
1011import  os .path 
@@ -478,16 +479,10 @@ def do_test_with_pip(self, system_site_packages):
478479
479480                # Actually run the create command with all that unhelpful 
480481                # config in place to ensure we ignore it 
481-                 try :
482+                 with   self . nicer_error () :
482483                    self .run_with_capture (venv .create , self .env_dir ,
483484                                          system_site_packages = system_site_packages ,
484485                                          with_pip = True )
485-                 except  subprocess .CalledProcessError  as  exc :
486-                     # The output this produces can be a little hard to read, 
487-                     # but at least it has all the details 
488-                     details  =  exc .output .decode (errors = "replace" )
489-                     msg  =  "{}\n \n **Subprocess Output**\n {}" 
490-                     self .fail (msg .format (exc , details ))
491486        # Ensure pip is available in the virtual environment 
492487        envpy  =  os .path .join (os .path .realpath (self .env_dir ), self .bindir , self .exe )
493488        # Ignore DeprecationWarning since pip code is not part of Python 
@@ -508,13 +503,14 @@ def do_test_with_pip(self, system_site_packages):
508503        # Check the private uninstall command provided for the Windows 
509504        # installers works (at least in a virtual environment) 
510505        with  EnvironmentVarGuard () as  envvars :
511-             # It seems ensurepip._uninstall calls subprocesses which do not 
512-             # inherit the interpreter settings. 
513-             envvars ["PYTHONWARNINGS" ] =  "ignore" 
514-             out , err  =  check_output ([envpy ,
515-                 '-W' , 'ignore::DeprecationWarning' ,
516-                 '-W' , 'ignore::ImportWarning' , '-I' ,
517-                 '-m' , 'ensurepip._uninstall' ])
506+             with  self .nicer_error ():
507+                 # It seems ensurepip._uninstall calls subprocesses which do not 
508+                 # inherit the interpreter settings. 
509+                 envvars ["PYTHONWARNINGS" ] =  "ignore" 
510+                 out , err  =  check_output ([envpy ,
511+                     '-W' , 'ignore::DeprecationWarning' ,
512+                     '-W' , 'ignore::ImportWarning' , '-I' ,
513+                     '-m' , 'ensurepip._uninstall' ])
518514        # We force everything to text, so unittest gives the detailed diff 
519515        # if we get unexpected results 
520516        err  =  err .decode ("latin-1" ) # Force to text, prevent decoding errors 
@@ -540,12 +536,32 @@ def do_test_with_pip(self, system_site_packages):
540536        if  not  system_site_packages :
541537            self .assert_pip_not_installed ()
542538
539+     @contextlib .contextmanager  
540+     def  nicer_error (self ):
541+         """ 
542+         Capture output from a failed subprocess for easier debugging. 
543+ 
544+         The output this handler produces can be a little hard to read, 
545+         but at least it has all the details. 
546+         """ 
547+         try :
548+             yield 
549+         except  subprocess .CalledProcessError  as  exc :
550+             out  =  exc .output .decode (errors = "replace" )
551+             err  =  exc .stderr .decode (errors = "replace" )
552+             self .fail (
553+                 f"{ exc } \n \n " 
554+                 f"**Subprocess Output**\n { out } \n \n " 
555+                 f"**Subprocess Error**\n { err }  
556+             )
557+ 
543558    # Issue #26610: pip/pep425tags.py requires ctypes 
544559    @unittest .skipUnless (ctypes , 'pip requires ctypes' ) 
545560    @requires_zlib () 
546561    def  test_with_pip (self ):
547562        self .do_test_with_pip (False )
548563        self .do_test_with_pip (True )
549564
565+ 
550566if  __name__  ==  "__main__" :
551567    unittest .main ()
0 commit comments