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
@@ -479,16 +480,10 @@ def do_test_with_pip(self, system_site_packages):
479
480
480
481
# Actually run the create command with all that unhelpful
481
482
# config in place to ensure we ignore it
482
- try :
483
+ with self . nicer_error () :
483
484
self .run_with_capture (venv .create , self .env_dir ,
484
485
system_site_packages = system_site_packages ,
485
486
with_pip = True )
486
- except subprocess .CalledProcessError as exc :
487
- # The output this produces can be a little hard to read,
488
- # but at least it has all the details
489
- details = exc .output .decode (errors = "replace" )
490
- msg = "{}\n \n **Subprocess Output**\n {}"
491
- self .fail (msg .format (exc , details ))
492
487
# Ensure pip is available in the virtual environment
493
488
envpy = os .path .join (os .path .realpath (self .env_dir ), self .bindir , self .exe )
494
489
# Ignore DeprecationWarning since pip code is not part of Python
@@ -508,9 +503,10 @@ 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
- out , err = check_output ([envpy ,
512
- '-W' , 'ignore::DeprecationWarning' , '-I' ,
513
- '-m' , 'ensurepip._uninstall' ])
506
+ with self .nicer_error ():
507
+ out , err = check_output ([envpy ,
508
+ '-W' , 'ignore::DeprecationWarning' , '-I' ,
509
+ '-m' , 'ensurepip._uninstall' ])
514
510
# We force everything to text, so unittest gives the detailed diff
515
511
# if we get unexpected results
516
512
err = err .decode ("latin-1" ) # Force to text, prevent decoding errors
@@ -536,12 +532,32 @@ def do_test_with_pip(self, system_site_packages):
536
532
if not system_site_packages :
537
533
self .assert_pip_not_installed ()
538
534
535
+ @contextlib .contextmanager
536
+ def nicer_error (self ):
537
+ """
538
+ Capture output from a failed subprocess for easier debugging.
539
+
540
+ The output this handler produces can be a little hard to read,
541
+ but at least it has all the details.
542
+ """
543
+ try :
544
+ yield
545
+ except subprocess .CalledProcessError as exc :
546
+ out = exc .output .decode (errors = "replace" )
547
+ err = exc .stderr .decode (errors = "replace" )
548
+ self .fail (
549
+ f"{ exc } \n \n "
550
+ f"**Subprocess Output**\n { out } \n \n "
551
+ f"**Subprocess Error**\n { err } "
552
+ )
553
+
539
554
# Issue #26610: pip/pep425tags.py requires ctypes
540
555
@unittest .skipUnless (ctypes , 'pip requires ctypes' )
541
556
@requires_zlib ()
542
557
def test_with_pip (self ):
543
558
self .do_test_with_pip (False )
544
559
self .do_test_with_pip (True )
545
560
561
+
546
562
if __name__ == "__main__" :
547
563
unittest .main ()
0 commit comments