python/utils: add VerboseProcessError
This adds an Exception that extends the Python stdlib subprocess.CalledProcessError. The difference is that the str() method of this exception also adds the stdout/stderr logs. In effect, if this exception goes unhandled, Python will print the output in a visually distinct wrapper to the terminal so that it's easy to spot in a sea of traceback information. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Reviewed-by: Hanna Reitz <hreitz@redhat.com> Message-Id: <20220321201618.903471-3-jsnow@redhat.com> Signed-off-by: Hanna Reitz <hreitz@redhat.com>
This commit is contained in:
parent
be73231ba8
commit
062fd1dad2
@ -18,6 +18,7 @@ various tasks not directly related to the launching of a VM.
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
from subprocess import CalledProcessError
|
||||
import textwrap
|
||||
from typing import Optional
|
||||
|
||||
@ -26,6 +27,7 @@ from .accel import kvm_available, list_accel, tcg_available
|
||||
|
||||
|
||||
__all__ = (
|
||||
'VerboseProcessError',
|
||||
'add_visual_margin',
|
||||
'get_info_usernet_hostfwd_port',
|
||||
'kvm_available',
|
||||
@ -121,3 +123,40 @@ def add_visual_margin(
|
||||
os.linesep.join(_wrap(line) for line in content.splitlines()),
|
||||
_bar(None, top=False),
|
||||
))
|
||||
|
||||
|
||||
class VerboseProcessError(CalledProcessError):
|
||||
"""
|
||||
The same as CalledProcessError, but more verbose.
|
||||
|
||||
This is useful for debugging failed calls during test executions.
|
||||
The return code, signal (if any), and terminal output will be displayed
|
||||
on unhandled exceptions.
|
||||
"""
|
||||
def summary(self) -> str:
|
||||
"""Return the normal CalledProcessError str() output."""
|
||||
return super().__str__()
|
||||
|
||||
def __str__(self) -> str:
|
||||
lmargin = ' '
|
||||
width = -len(lmargin)
|
||||
sections = []
|
||||
|
||||
# Does self.stdout contain both stdout and stderr?
|
||||
has_combined_output = self.stderr is None
|
||||
|
||||
name = 'output' if has_combined_output else 'stdout'
|
||||
if self.stdout:
|
||||
sections.append(add_visual_margin(self.stdout, width, name))
|
||||
else:
|
||||
sections.append(f"{name}: N/A")
|
||||
|
||||
if self.stderr:
|
||||
sections.append(add_visual_margin(self.stderr, width, 'stderr'))
|
||||
elif not has_combined_output:
|
||||
sections.append("stderr: N/A")
|
||||
|
||||
return os.linesep.join((
|
||||
self.summary(),
|
||||
textwrap.indent(os.linesep.join(sections), prefix=lmargin),
|
||||
))
|
||||
|
Loading…
Reference in New Issue
Block a user