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