initial commit
This commit is contained in:
54
src/archipelago_tester/pipeline/generation/report.py
Normal file
54
src/archipelago_tester/pipeline/generation/report.py
Normal file
@@ -0,0 +1,54 @@
|
||||
"""Reading what a driver reported."""
|
||||
|
||||
import json
|
||||
|
||||
|
||||
class DriverReport:
|
||||
"""The JSON one driver run wrote to stdout."""
|
||||
|
||||
def __init__(self, result):
|
||||
self.result = result
|
||||
|
||||
@staticmethod
|
||||
def tail(text, lines=20):
|
||||
return "\n".join(text.splitlines()[-lines:])
|
||||
|
||||
@staticmethod
|
||||
def last_json_object(text):
|
||||
"""The driver's report, however it ended up on the line.
|
||||
|
||||
Not "the last line starting with {": worlds write to raw stdout
|
||||
during generation, and one that writes without a trailing
|
||||
newline leaves its output glued to the front of the report -
|
||||
Super Metroid's randomizer emits a bare "*" per retry, so the
|
||||
report arrives as "*{...}" and would read as no report at all.
|
||||
"""
|
||||
for line in reversed(text.splitlines()):
|
||||
line = line.strip()
|
||||
start = line.find("{")
|
||||
while start != -1:
|
||||
try:
|
||||
return json.loads(line[start:])
|
||||
except json.JSONDecodeError:
|
||||
start = line.find("{", start + 1)
|
||||
return None
|
||||
|
||||
@property
|
||||
def data(self):
|
||||
return self.last_json_object(self.result.stdout)
|
||||
|
||||
def parsed(self):
|
||||
"""The report, or a failure built from what it printed."""
|
||||
report = self.data
|
||||
if report is not None:
|
||||
report.setdefault("stderr_tail", self.tail(self.result.stderr))
|
||||
return report
|
||||
return {
|
||||
"game": None,
|
||||
"outcome": "failed",
|
||||
"detail": ("no JSON report on stdout "
|
||||
f"(exit code {self.result.returncode})"),
|
||||
"elapsed_seconds": None,
|
||||
"stdout_tail": self.tail(self.result.stdout),
|
||||
"stderr_tail": self.tail(self.result.stderr),
|
||||
}
|
||||
Reference in New Issue
Block a user