5
5
Licensed to the PSF under a contributor agreement.
6
6
"""
7
7
8
+ import contextlib
8
9
import ensurepip
9
10
import os
10
11
import os .path
@@ -558,16 +559,10 @@ def do_test_with_pip(self, system_site_packages):
558
559
559
560
# Actually run the create command with all that unhelpful
560
561
# config in place to ensure we ignore it
561
- try :
562
+ with self . nicer_error () :
562
563
self .run_with_capture (venv .create , self .env_dir ,
563
564
system_site_packages = system_site_packages ,
564
565
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 ))
571
566
# Ensure pip is available in the virtual environment
572
567
envpy = os .path .join (os .path .realpath (self .env_dir ), self .bindir , self .exe )
573
568
# Ignore DeprecationWarning since pip code is not part of Python
@@ -588,13 +583,14 @@ def do_test_with_pip(self, system_site_packages):
588
583
# Check the private uninstall command provided for the Windows
589
584
# installers works (at least in a virtual environment)
590
585
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' ])
598
594
# We force everything to text, so unittest gives the detailed diff
599
595
# if we get unexpected results
600
596
err = err .decode ("latin-1" ) # Force to text, prevent decoding errors
@@ -620,10 +616,30 @@ def do_test_with_pip(self, system_site_packages):
620
616
if not system_site_packages :
621
617
self .assert_pip_not_installed ()
622
618
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
+
623
638
@requires_venv_with_pip ()
624
639
def test_with_pip (self ):
625
640
self .do_test_with_pip (False )
626
641
self .do_test_with_pip (True )
627
642
643
+
628
644
if __name__ == "__main__" :
629
645
unittest .main ()
0 commit comments