external metric: graceful timeout handling

This commit is contained in:
Jörn-Michael Miehe 2023-09-02 01:05:01 +00:00
parent badc870c52
commit cac6129282

View file

@ -10,8 +10,10 @@ def _hwdata() -> Iterator[ReportData]:
def parse_output(exe: os.PathLike) -> ReportData: def parse_output(exe: os.PathLike) -> ReportData:
try: try:
# check exe is executable # check exe is executable
# => AssertionError
assert os.access(exe, os.X_OK) assert os.access(exe, os.X_OK)
try:
# run exe # run exe
# => TimeoutExpired: execution took too long # => TimeoutExpired: execution took too long
execution = subprocess.run( execution = subprocess.run(
@ -20,21 +22,31 @@ def _hwdata() -> Iterator[ReportData]:
timeout=SETTINGS.external.timeout, timeout=SETTINGS.external.timeout,
) )
stdout = execution.stdout
returncode = execution.returncode
except subprocess.TimeoutExpired as e:
# output might still be valid
assert (stdout := e.stdout) is not None
returncode = 0
# look at the first four output lines # look at the first four output lines
# => UnicodeDecodeError: output is not decodable # => UnicodeDecodeError: output is not decodable
output = execution.stdout.decode().split("\n")[:4] output = stdout.decode().split("\n")[:4]
# extract and check name (fail if empty) # extract and check name (fail if empty)
# => IndexError, AssertionError
assert (name := "".join( assert (name := "".join(
char char
for char in output[0] for char in output[0]
if char.isprintable() if char.isprintable()
)[:100]) != "" )[:100]) != ""
except (AssertionError, # check exit status
subprocess.TimeoutExpired, # => AssertionError
UnicodeDecodeError, assert returncode == 0
IndexError):
except (AssertionError, UnicodeDecodeError, IndexError):
return ReportData.from_settings( return ReportData.from_settings(
name=os.path.basename(exe)[:100], name=os.path.basename(exe)[:100],
value=100, value=100,
@ -42,22 +54,22 @@ def _hwdata() -> Iterator[ReportData]:
) )
try: try:
# check exit status
assert execution.returncode == 0
# check output length # check output length
# => AssertionError
assert len(output) == 4 assert len(output) == 4
# extract threshold and value # extract threshold and value
# => ValueError
threshold = float(output[1]) threshold = float(output[1])
value = float(output[3]) value = float(output[3])
# extract and check inversion # extract and check inversion
# => AssertionError
assert (inverted := output[2].strip().lower()) in ( assert (inverted := output[2].strip().lower()) in (
"normal", "inverted", "normal", "inverted",
) )
except (ValueError, AssertionError): except (AssertionError, ValueError):
return ReportData.from_settings( return ReportData.from_settings(
name=name, name=name,
value=100, value=100,