From d6959b5f3b99148b0ae3a53442eea0b09a150946 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dean=20Qui=C3=B1anola?= Date: Sat, 14 Mar 2026 21:51:58 -0700 Subject: [PATCH 1/2] fix(stubs): handle None return from void @remote functions (AE-2374) handle_response raised ValueError when response.result was None, blocking all void @remote functions (fire-and-forget, setup). Now returns None for void functions and supports json_result fallback path. --- src/runpod_flash/stubs/live_serverless.py | 8 ++++--- tests/unit/test_stub_live_serverless.py | 26 ++++++++++++++++++----- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/runpod_flash/stubs/live_serverless.py b/src/runpod_flash/stubs/live_serverless.py index 7ba09cd6..3ca74355 100644 --- a/src/runpod_flash/stubs/live_serverless.py +++ b/src/runpod_flash/stubs/live_serverless.py @@ -139,9 +139,11 @@ def handle_response(self, response: FunctionResponse): print(line) if response.success: - if response.result is None: - raise ValueError("Response result is None") - return cloudpickle.loads(base64.b64decode(response.result)) + if response.result is not None: + return cloudpickle.loads(base64.b64decode(response.result)) + if response.json_result is not None: + return response.json_result + return None else: raise Exception(f"Remote execution failed: {response.error}") diff --git a/tests/unit/test_stub_live_serverless.py b/tests/unit/test_stub_live_serverless.py index fc2f7125..72c2179b 100644 --- a/tests/unit/test_stub_live_serverless.py +++ b/tests/unit/test_stub_live_serverless.py @@ -178,12 +178,28 @@ def test_handle_response_invalid(self, stub): with pytest.raises(ValueError, match="Invalid response"): stub.handle_response(response) - def test_handle_response_none_result(self, stub): - """handle_response raises ValueError when success but result is None.""" - response = FunctionResponse(success=True, result=None) + def test_handle_response_void_function_returns_none(self, stub): + """handle_response returns None for void functions (no result or json_result).""" + response = FunctionResponse(success=True, result=None, json_result=None) - with pytest.raises(ValueError, match="result is None"): - stub.handle_response(response) + result = stub.handle_response(response) + assert result is None + + def test_handle_response_json_result(self, stub): + """handle_response returns json_result when result is None but json_result is set.""" + response = FunctionResponse( + success=True, result=None, json_result={"key": "value"} + ) + + result = stub.handle_response(response) + assert result == {"key": "value"} + + def test_handle_response_json_result_none_value(self, stub): + """handle_response returns None when json_result is explicitly None (void json function).""" + response = FunctionResponse(success=True, result=None, json_result=None) + + result = stub.handle_response(response) + assert result is None def test_handle_response_prints_stdout(self, stub, capsys): """handle_response prints stdout lines.""" From a5c3b0431077369793e87daedcbc06cbb4f8effa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dean=20Qui=C3=B1anola?= Date: Sat, 14 Mar 2026 22:03:37 -0700 Subject: [PATCH 2/2] test(stubs): remove duplicate test, add scalar and priority coverage --- tests/unit/test_stub_live_serverless.py | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/tests/unit/test_stub_live_serverless.py b/tests/unit/test_stub_live_serverless.py index 72c2179b..55a77597 100644 --- a/tests/unit/test_stub_live_serverless.py +++ b/tests/unit/test_stub_live_serverless.py @@ -185,8 +185,8 @@ def test_handle_response_void_function_returns_none(self, stub): result = stub.handle_response(response) assert result is None - def test_handle_response_json_result(self, stub): - """handle_response returns json_result when result is None but json_result is set.""" + def test_handle_response_json_result_dict(self, stub): + """handle_response returns json_result dict when result is None.""" response = FunctionResponse( success=True, result=None, json_result={"key": "value"} ) @@ -194,12 +194,23 @@ def test_handle_response_json_result(self, stub): result = stub.handle_response(response) assert result == {"key": "value"} - def test_handle_response_json_result_none_value(self, stub): - """handle_response returns None when json_result is explicitly None (void json function).""" - response = FunctionResponse(success=True, result=None, json_result=None) + def test_handle_response_json_result_scalar(self, stub): + """handle_response returns json_result scalar without deserialization.""" + response = FunctionResponse(success=True, result=None, json_result=42) result = stub.handle_response(response) - assert result is None + assert result == 42 + + def test_handle_response_result_takes_priority_over_json_result(self, stub): + """handle_response prefers cloudpickle result over json_result when both set.""" + result_data = "from_cloudpickle" + encoded = base64.b64encode(cloudpickle.dumps(result_data)).decode() + response = FunctionResponse( + success=True, result=encoded, json_result="from_json" + ) + + result = stub.handle_response(response) + assert result == "from_cloudpickle" def test_handle_response_prints_stdout(self, stub, capsys): """handle_response prints stdout lines."""