Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions internal/cmd/evaluator.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ func newEvaluatorUploadCmd() *cobra.Command {
}
re := regexp.MustCompile(`\bdef\s+` + regexp.QuoteMeta(funcName) + `\s*\(`)
sourceStr = re.ReplaceAllString(sourceStr, "def "+evalFuncName+"(")
sourceStr = stripPythonReturnAnnotation(sourceStr, evalFuncName)
case "javascript":
sourceStr = extractJSFunction(string(source), funcName)
if sourceStr == "" {
Expand Down Expand Up @@ -438,6 +439,21 @@ func extractPythonFunction(source string, funcName string) string {
return strings.Join(lines[startIdx:endIdx], "\n") + "\n"
}

// stripPythonReturnAnnotation removes a return-type annotation from the def line of an
// already-extracted, already-renamed function (e.g. `def perform_eval(run) -> dict | None:`
// becomes `def perform_eval(run):`).
//
// The evaluator service's function finder does not handle PEP 604 union return annotations
// (e.g. `-> dict | None`): uploading such a function fails with "Code evaluator does not
// contain function with name perform_eval" even though the function is present. A plain
// annotation (`-> dict`) or no annotation works. The annotation is irrelevant to execution,
// so we drop it. Only single-line def signatures are handled (the common case); a multi-line
// signature is left untouched.
func stripPythonReturnAnnotation(source, funcName string) string {
re := regexp.MustCompile(`(?m)^(def ` + regexp.QuoteMeta(funcName) + `\(.*\))\s*->.*?:(\s*(?:#.*)?)$`)
return re.ReplaceAllString(source, "$1:$2")
}

// detectLanguage returns the API language value and the canonical eval function
// name based on the file extension.
func detectLanguage(filename string) (language, evalFuncName string) {
Expand Down
43 changes: 43 additions & 0 deletions internal/cmd/evaluator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,49 @@ func TestExtractPythonFunction_EmptySource(t *testing.T) {
}
}

// ---------- stripPythonReturnAnnotation ----------

func TestStripPythonReturnAnnotation_Union(t *testing.T) {
// PEP 604 union return annotation: the evaluator service's function finder
// can't handle it, so it must be stripped.
source := "def perform_eval(run) -> dict | None:\n return {\"score\": 1}\n"
result := stripPythonReturnAnnotation(source, "perform_eval")
if !contains(result, "def perform_eval(run):") {
t.Errorf("union return annotation should be stripped, got:\n%s", result)
}
if contains(result, "->") {
t.Error("result should not contain a return annotation")
}
if !contains(result, `return {"score": 1}`) {
t.Error("body should be preserved")
}
}

func TestStripPythonReturnAnnotation_Plain(t *testing.T) {
source := "def perform_eval(run) -> dict:\n return {\"score\": 1}\n"
result := stripPythonReturnAnnotation(source, "perform_eval")
if !contains(result, "def perform_eval(run):") {
t.Errorf("plain return annotation should be stripped, got:\n%s", result)
}
}

func TestStripPythonReturnAnnotation_WithParamsAndComment(t *testing.T) {
// params plus a trailing comment after the colon
source := "def perform_eval(run, example) -> dict | None: # noqa\n return {}\n"
result := stripPythonReturnAnnotation(source, "perform_eval")
if !contains(result, "def perform_eval(run, example):") {
t.Errorf("should strip annotation and keep params, got:\n%s", result)
}
}

func TestStripPythonReturnAnnotation_NoAnnotationUnchanged(t *testing.T) {
source := "def perform_eval(run):\n return {\"score\": 1}\n"
result := stripPythonReturnAnnotation(source, "perform_eval")
if result != source {
t.Errorf("source without an annotation should be unchanged, got:\n%s", result)
}
}

// ---------- extractJSFunction ----------

func TestExtractJSFunction_FunctionDeclaration(t *testing.T) {
Expand Down