@@ -77,13 +77,14 @@ def _sanitize_message(string: str) -> str:
7777 return string .replace ('%' , '%%' )
7878
7979
80- def extract_outcome_and_text (sandbox : Sandbox ) -> tuple [float , list [str ]]:
80+ def extract_outcome_and_text (sandbox : Sandbox ) -> tuple [float , list [str ], str | None ]:
8181 """Extract the outcome and the text from the a standard manager output.
8282
8383 sandbox: the sandbox whose last execution was a manager writing
8484 a standard manager output.
8585
86- return: outcome and text.
86+ return: outcome, contestant-facing text and admin-facing text
87+ (not translated).
8788
8889 raise (ValueError): if cannot decode the data.
8990 raise (FileNotFoundError): if any of the sandbox stdout or stderr file
@@ -108,6 +109,23 @@ def extract_outcome_and_text(sandbox: Sandbox) -> tuple[float, list[str]]:
108109 logger .error ("Manager stderr (text) is malformed. %r" , error )
109110 raise error
110111
112+ # Parse special commands
113+ admin_text = None
114+ for line in stderr_file .readlines ():
115+ line = line .strip ()
116+ if not line :
117+ continue
118+
119+ PREFIX = "ADMIN_MESSAGE:"
120+ if line .startswith (PREFIX ):
121+ line = _sanitize_message (line [len (PREFIX ):].strip ())
122+ if admin_text is not None :
123+ admin_text = admin_text + " " + line
124+ else :
125+ admin_text = line
126+ else :
127+ logger .warning (f"Unknown special manager command `{ line } `" )
128+
111129 try :
112130 outcome = float (outcome )
113131 except ValueError :
@@ -125,7 +143,7 @@ def extract_outcome_and_text(sandbox: Sandbox) -> tuple[float, list[str]]:
125143 logger .warning ("Manager asked to translate text, but string "
126144 "'%s' is not recognized." % remaining )
127145
128- return outcome , [text ]
146+ return outcome , [text ], admin_text
129147
130148
131149def trusted_step (
@@ -196,7 +214,7 @@ def checker_step(
196214 correct_output_digest : str ,
197215 output_filename : str ,
198216 extra_args : list [str ] | None = None
199- ) -> tuple [bool , float | None , list [str ] | None ]:
217+ ) -> tuple [bool , float | None , list [str ] | None , str | None ]:
200218 """Run the explicit checker given by the admins
201219
202220 sandbox: the sandbox to run the checker in; should already
@@ -213,7 +231,8 @@ def checker_step(
213231 extra_args: extra arguments to pass to the checker.
214232
215233 return: success (true if the checker was able to check the solution
216- successfully), outcome and text (both None if success is False).
234+ successfully), outcome, text and admin_text (all None if success
235+ is False).
217236
218237 """
219238 # Check that the file we are going to inject in the sandbox are not already
@@ -224,12 +243,12 @@ def checker_step(
224243 if sandbox .file_exists (filename ):
225244 logger .error ("File %s already in the sandbox for the checker." ,
226245 filename )
227- return False , None , None
246+ return False , None , None , None
228247
229248 # Copy the checker in the sandbox, after making sure it was provided.
230249 if checker_digest is None :
231250 logger .error ("Configuration error: missing checker in task managers." )
232- return False , None , None
251+ return False , None , None , None
233252 sandbox .create_file_from_storage (CHECKER_FILENAME , checker_digest ,
234253 executable = True )
235254
@@ -247,17 +266,17 @@ def checker_step(
247266 if not box_success or not success :
248267 logger .error ("Sandbox failed during checker step. "
249268 "See previous logs for the reason." )
250- return False , None , None
269+ return False , None , None , None
251270
252271 # Extract outcome and text assuming a standard manager output.
253272 try :
254- outcome , text = extract_outcome_and_text (sandbox )
273+ outcome , text , admin_text = extract_outcome_and_text (sandbox )
255274 except ValueError as e :
256275 logger .error ("Invalid output from checker: %s" , e )
257- return False , None , None
276+ return False , None , None , None
258277 except FileNotFoundError as e :
259278 # This should not happen, as the redirect is handled by the sandbox.
260279 logger .error ("Missing stdout or stderr file from checker: %s" , e )
261- return False , None , None
280+ return False , None , None , None
262281
263- return True , outcome , text
282+ return True , outcome , text , admin_text
0 commit comments