From 8c6f90cc118138bb0da448d44876c7347c76c1e1 Mon Sep 17 00:00:00 2001 From: Albert Villanova del Moral <8515462+albertvillanova@users.noreply.github.com> Date: Tue, 11 Feb 2025 11:06:31 +0100 Subject: [PATCH] Test evaluate_delete (#519) --- src/smolagents/local_python_executor.py | 3 +- tests/test_local_python_executor.py | 68 ++++++++++++++++++++++++- 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/src/smolagents/local_python_executor.py b/src/smolagents/local_python_executor.py index 85b5317..5fe7401 100644 --- a/src/smolagents/local_python_executor.py +++ b/src/smolagents/local_python_executor.py @@ -1379,12 +1379,11 @@ def evaluate_python_code( is_final_answer = True return e.value, is_final_answer except Exception as e: - exception_type = type(e).__name__ state["_print_outputs"].value = truncate_content( str(state["_print_outputs"]), max_length=max_print_outputs_length ) raise InterpreterError( - f"Code execution failed at line '{ast.get_source_segment(code, node)}' due to: {exception_type}:{str(e)}" + f"Code execution failed at line '{ast.get_source_segment(code, node)}' due to: {type(e).__name__}: {e}" ) diff --git a/tests/test_local_python_executor.py b/tests/test_local_python_executor.py index 200c221..cab9e10 100644 --- a/tests/test_local_python_executor.py +++ b/tests/test_local_python_executor.py @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import ast import types import unittest from textwrap import dedent @@ -24,6 +25,7 @@ from smolagents.default_tools import BASE_PYTHON_TOOLS from smolagents.local_python_executor import ( InterpreterError, PrintContainer, + evaluate_delete, evaluate_python_code, fix_final_answer_code, get_safe_module, @@ -926,7 +928,7 @@ shift_intervals code = "import random;random._os.system('echo bad command passed')" with pytest.raises(InterpreterError) as e: evaluate_python_code(code) - assert "AttributeError:module 'random' has no attribute '_os'" in str(e) + assert "AttributeError: module 'random' has no attribute '_os'" in str(e) code = "import doctest;doctest.inspect.os.system('echo bad command passed')" with pytest.raises(InterpreterError): @@ -1090,6 +1092,70 @@ def test_evaluate_augassign_custom(operator, expected_result): assert result == expected_result +@pytest.mark.parametrize( + "code, expected_error_message", + [ + ( + dedent("""\ + x = 5 + del x + x + """), + "The variable `x` is not defined", + ), + ( + dedent("""\ + x = [1, 2, 3] + del x[2] + x[2] + """), + "Index 2 out of bounds for list of length 2", + ), + ( + dedent("""\ + x = {"key": "value"} + del x["key"] + x["key"] + """), + "Could not index {} with 'key'", + ), + ( + dedent("""\ + del x + """), + "Cannot delete name 'x': name is not defined", + ), + ], +) +def test_evaluate_python_code_with_evaluate_delete(code, expected_error_message): + state = {} + with pytest.raises(InterpreterError) as exception_info: + evaluate_python_code(code, {}, state=state) + assert expected_error_message in str(exception_info.value) + + +@pytest.mark.parametrize( + "code, state, expectation", + [ + ("del x", {"x": 1}, {}), + ("del x[1]", {"x": [1, 2, 3]}, {"x": [1, 3]}), + ("del x['key']", {"x": {"key": "value"}}, {"x": {}}), + ("del x", {}, InterpreterError("Cannot delete name 'x': name is not defined")), + ], +) +def test_evaluate_delete(code, state, expectation): + state["_operations_count"] = 0 + delete_node = ast.parse(code).body[0] + if isinstance(expectation, Exception): + with pytest.raises(type(expectation)) as exception_info: + evaluate_delete(delete_node, state, {}, {}, []) + assert str(expectation) in str(exception_info.value) + else: + evaluate_delete(delete_node, state, {}, {}, []) + del state["_operations_count"] + assert state == expectation + + def test_get_safe_module_handle_lazy_imports(): class FakeModule(types.ModuleType): def __init__(self, name):