55Licensed to the PSF under a contributor agreement.
66"""
77
8+ import contextlib
89import ensurepip
910import os
1011import os .path
@@ -558,16 +559,10 @@ def do_test_with_pip(self, system_site_packages):
558559
559560 # Actually run the create command with all that unhelpful
560561 # config in place to ensure we ignore it
561- try :
562+ with self . nicer_error () :
562563 self .run_with_capture (venv .create , self .env_dir ,
563564 system_site_packages = system_site_packages ,
564565 with_pip = True )
565- except subprocess .CalledProcessError as exc :
566- # The output this produces can be a little hard to read,
567- # but at least it has all the details
568- details = exc .output .decode (errors = "replace" )
569- msg = "{}\n \n **Subprocess Output**\n {}"
570- self .fail (msg .format (exc , details ))
571566 # Ensure pip is available in the virtual environment
572567 envpy = os .path .join (os .path .realpath (self .env_dir ), self .bindir , self .exe )
573568 # Ignore DeprecationWarning since pip code is not part of Python
@@ -588,13 +583,14 @@ def do_test_with_pip(self, system_site_packages):
588583 # Check the private uninstall command provided for the Windows
589584 # installers works (at least in a virtual environment)
590585 with EnvironmentVarGuard () as envvars :
591- # It seems ensurepip._uninstall calls subprocesses which do not
592- # inherit the interpreter settings.
593- envvars ["PYTHONWARNINGS" ] = "ignore"
594- out , err = check_output ([envpy ,
595- '-W' , 'ignore::DeprecationWarning' ,
596- '-W' , 'ignore::ImportWarning' , '-I' ,
597- '-m' , 'ensurepip._uninstall' ])
586+ with self .nicer_error ():
587+ # It seems ensurepip._uninstall calls subprocesses which do not
588+ # inherit the interpreter settings.
589+ envvars ["PYTHONWARNINGS" ] = "ignore"
590+ out , err = check_output ([envpy ,
591+ '-W' , 'ignore::DeprecationWarning' ,
592+ '-W' , 'ignore::ImportWarning' , '-I' ,
593+ '-m' , 'ensurepip._uninstall' ])
598594 # We force everything to text, so unittest gives the detailed diff
599595 # if we get unexpected results
600596 err = err .decode ("latin-1" ) # Force to text, prevent decoding errors
@@ -620,10 +616,30 @@ def do_test_with_pip(self, system_site_packages):
620616 if not system_site_packages :
621617 self .assert_pip_not_installed ()
622618
619+ @contextlib .contextmanager
620+ def nicer_error (self ):
621+ """
622+ Capture output from a failed subprocess for easier debugging.
623+
624+ The output this handler produces can be a little hard to read,
625+ but at least it has all the details.
626+ """
627+ try :
628+ yield
629+ except subprocess .CalledProcessError as exc :
630+ out = exc .output .decode (errors = "replace" )
631+ err = exc .stderr .decode (errors = "replace" )
632+ self .fail (
633+ f"{ exc } \n \n "
634+ f"**Subprocess Output**\n { out } \n \n "
635+ f"**Subprocess Error**\n { err } "
636+ )
637+
623638 @requires_venv_with_pip ()
624639 def test_with_pip (self ):
625640 self .do_test_with_pip (False )
626641 self .do_test_with_pip (True )
627642
643+
628644if __name__ == "__main__" :
629645 unittest .main ()
0 commit comments