The problem
A model generated several candidate implementations of a function, each as source code. To tell which are right, run them against test cases, and rank them by how many tests they pass. Along the way, learn from every failure: a wrong answer, an exception, a program that does not even load. The error messages are what a repair step would give back to the model.
One candidate
run_candidate(source, func_name, tests): tests is a list of (args, expected) pairs, where args is a tuple. Execute source with exec in a fresh namespace, get func_name from it, and call it on every test. Return a dict:
"passed": the number of tests whose result== expected;"total": the number of tests;"errors": a list of short strings, one per failing test:"test <i>: wrong answer <result!r>"or"test <i>: <ExceptionName>: <message>";- if the code does not load, or does not define the function, a single error
"load: <ExceptionName>: <message>", withpassed = 0.
Example.
func_name = "add", testsadd(1, 2) = 3,add(0, 0) = 0,add(-1, 1) = 0.
source result return a + bpassed: 3, no errorsreturn a - bpassed: 1; errorstest 0: wrong answer -1andtest 2: wrong answer -2missing colon after def add(a, b)passed: 0; one errorload: SyntaxError: ...return a + b + undefined_namepassed: 0; three errorstest i: NameError: name 'undefined_name' is not defineddefines plus, notaddpassed: 0; one errorload: KeyError: 'add'
Ranking
rank_candidates(sources, func_name, tests) returns the indices of the candidates sorted by number of tests passed, best first, ties by index. For the five candidates above the passed counts are , so the order is [0, 1, 2, 3, 4].
What to implement
run_candidate(source, func_name, tests): the dict above.rank_candidates(sources, func_name, tests): the indices, best first.
Requirements
- Nothing a candidate does may crash your function: catch every
Exception. - Use a new namespace dict for every candidate, so they cannot see each other's definitions.
- This is not a sandbox:
execruns the code with your program's permissions. Real systems run each candidate in an isolated process with time and memory limits (see the theory page).
Hint
A missing function is a KeyError on the namespace; turn it into the "load: ..." error. type(exc).__name__ gives the exception's name.