Skip to content

Commit 6066f45

Browse files
authored
pythongh-93975: Nicer error reporting in test_venv (pythonGH-93959)
- pythongh-93957: Provide nicer error reporting from subprocesses in test_venv.EnsurePipTest.test_with_pip. - Update changelog This change does three things: 1. Extract a function for trapping output in subprocesses. 2. Emit both stdout and stderr when encountering an error. 3. Apply the change to `ensurepip._uninstall` check.
1 parent dd78aae commit 6066f45

File tree

2 files changed

+32
-14
lines changed

2 files changed

+32
-14
lines changed

Lib/test/test_venv.py

+30-14
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
Licensed to the PSF under a contributor agreement.
66
"""
77

8+
import contextlib
89
import ensurepip
910
import os
1011
import 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+
628644
if __name__ == "__main__":
629645
unittest.main()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Provide nicer error reporting from subprocesses in
2+
test_venv.EnsurePipTest.test_with_pip.

0 commit comments

Comments
 (0)