From 6335afb0108fad0c0b76b1c0c1acd1fc49dec698 Mon Sep 17 00:00:00 2001 From: Graham Neubig Date: Tue, 20 May 2025 17:47:07 -0400 Subject: [PATCH] Fix environment variable casting for dict and list types (#8494) Co-authored-by: openhands --- openhands/core/config/sandbox_config.py | 2 +- openhands/core/config/utils.py | 5 +++- tests/unit/test_config_dict_casting.py | 39 +++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 tests/unit/test_config_dict_casting.py diff --git a/openhands/core/config/sandbox_config.py b/openhands/core/config/sandbox_config.py index 050d978914..ad5e395b27 100644 --- a/openhands/core/config/sandbox_config.py +++ b/openhands/core/config/sandbox_config.py @@ -37,7 +37,7 @@ class SandboxConfig(BaseModel): Must be one of [1, 2, 4, 8]. Will only be used if the runtime is remote. enable_gpu: Whether to enable GPU. docker_runtime_kwargs: Additional keyword arguments to pass to the Docker runtime when running containers. - This should be a JSON string that will be parsed into a dictionary. + This should be a Python dictionary literal string that will be parsed into a dictionary. trusted_dirs: List of directories that can be trusted to run the OpenHands CLI. vscode_port: The port to use for VSCode. If None, a random port will be chosen. This is useful when deploying OpenHands in a remote machine where you need to expose a specific port. diff --git a/openhands/core/config/utils.py b/openhands/core/config/utils.py index 78301414aa..27393acafa 100644 --- a/openhands/core/config/utils.py +++ b/openhands/core/config/utils.py @@ -91,7 +91,10 @@ def load_from_env( cast_value = str(value).lower() in ['true', '1'] # parse dicts and lists like SANDBOX_RUNTIME_STARTUP_ENV_VARS and SANDBOX_RUNTIME_EXTRA_BUILD_ARGS │ elif ( - get_origin(field_type) is dict or get_origin(field_type) is list + get_origin(field_type) is dict + or get_origin(field_type) is list + or field_type is dict + or field_type is list ): cast_value = literal_eval(value) else: diff --git a/tests/unit/test_config_dict_casting.py b/tests/unit/test_config_dict_casting.py new file mode 100644 index 0000000000..eaf0aeabef --- /dev/null +++ b/tests/unit/test_config_dict_casting.py @@ -0,0 +1,39 @@ +import os + +import pytest + +from openhands.core.config import AppConfig, load_from_env + + +def test_load_from_env_with_dict(monkeypatch, default_config): + """Test loading dict values from environment variables, particularly DOCKER_RUNTIME_KWARGS.""" + # Set the environment variable with a dict-formatted string using Python literal syntax + monkeypatch.setenv( + 'SANDBOX_DOCKER_RUNTIME_KWARGS', + '{' + + ' "mem_limit": "2g",' + + ' "cpu_count": 2,' + + ' "environment": {"TEST_VAR": "test_value"}' + + '}', + ) + + # Load configuration from environment + load_from_env(default_config, os.environ) + + # Verify that the dict was correctly parsed + assert isinstance(default_config.sandbox.docker_runtime_kwargs, dict) + assert default_config.sandbox.docker_runtime_kwargs.get('mem_limit') == '2g' + assert default_config.sandbox.docker_runtime_kwargs.get('cpu_count') == 2 + assert isinstance( + default_config.sandbox.docker_runtime_kwargs.get('environment'), dict + ) + assert ( + default_config.sandbox.docker_runtime_kwargs.get('environment').get('TEST_VAR') + == 'test_value' + ) + + +@pytest.fixture +def default_config(): + # Fixture to provide a default AppConfig instance + yield AppConfig()