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
@@ -478,16 +479,10 @@ def do_test_with_pip(self, system_site_packages):
478
479
479
480
# Actually run the create command with all that unhelpful
480
481
# config in place to ensure we ignore it
481
- try :
482
+ with self . nicer_error () :
482
483
self .run_with_capture (venv .create , self .env_dir ,
483
484
system_site_packages = system_site_packages ,
484
485
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 ))
491
486
# Ensure pip is available in the virtual environment
492
487
envpy = os .path .join (os .path .realpath (self .env_dir ), self .bindir , self .exe )
493
488
# Ignore DeprecationWarning since pip code is not part of Python
@@ -508,13 +503,14 @@ def do_test_with_pip(self, system_site_packages):
508
503
# Check the private uninstall command provided for the Windows
509
504
# installers works (at least in a virtual environment)
510
505
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' ])
518
514
# We force everything to text, so unittest gives the detailed diff
519
515
# if we get unexpected results
520
516
err = err .decode ("latin-1" ) # Force to text, prevent decoding errors
@@ -540,12 +536,32 @@ def do_test_with_pip(self, system_site_packages):
540
536
if not system_site_packages :
541
537
self .assert_pip_not_installed ()
542
538
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
+
543
558
# Issue #26610: pip/pep425tags.py requires ctypes
544
559
@unittest .skipUnless (ctypes , 'pip requires ctypes' )
545
560
@requires_zlib ()
546
561
def test_with_pip (self ):
547
562
self .do_test_with_pip (False )
548
563
self .do_test_with_pip (True )
549
564
565
+
550
566
if __name__ == "__main__" :
551
567
unittest .main ()
0 commit comments