Files
openai--openai-agents-python/tests/sandbox/test_client_options.py
T
2026-07-13 12:39:17 +08:00

110 lines
3.7 KiB
Python

from __future__ import annotations
import importlib
from typing import Literal
import pytest
from agents.extensions.sandbox.cloudflare import CloudflareSandboxClientOptions
from agents.extensions.sandbox.daytona import DaytonaSandboxClientOptions
from agents.extensions.sandbox.e2b import E2BSandboxClientOptions
from agents.sandbox.config import DEFAULT_PYTHON_SANDBOX_IMAGE
from agents.sandbox.sandboxes import DockerSandboxClientOptions, UnixLocalSandboxClientOptions
from agents.sandbox.session import BaseSandboxClientOptions
def test_sandbox_client_options_parse_uses_registered_builtin_type() -> None:
parsed = BaseSandboxClientOptions.parse(
{
"type": "docker",
"image": DEFAULT_PYTHON_SANDBOX_IMAGE,
"exposed_ports": [8080],
}
)
assert parsed == DockerSandboxClientOptions(
image=DEFAULT_PYTHON_SANDBOX_IMAGE, exposed_ports=(8080,)
)
def test_sandbox_client_options_parse_passthrough_existing_instance() -> None:
options = UnixLocalSandboxClientOptions(exposed_ports=(8080,))
parsed = BaseSandboxClientOptions.parse(options)
assert parsed is options
def test_sandbox_client_options_exclude_unset_preserves_type_discriminator() -> None:
try:
modal_module = importlib.import_module("agents.extensions.sandbox.modal")
except ModuleNotFoundError:
pytest.skip("modal is not installed")
payload = modal_module.ModalSandboxClientOptions(app_name="sandbox-tests").model_dump(
exclude_unset=True
)
assert payload == {
"type": "modal",
"app_name": "sandbox-tests",
"sandbox_create_timeout_s": None,
"workspace_persistence": "tar",
"snapshot_filesystem_timeout_s": None,
"snapshot_filesystem_restore_timeout_s": None,
"exposed_ports": (),
"gpu": None,
"timeout": 300,
"use_sleep_cmd": True,
"image_builder_version": "2025.06",
"idle_timeout": None,
}
@pytest.mark.parametrize(
"options",
[
DockerSandboxClientOptions(image=DEFAULT_PYTHON_SANDBOX_IMAGE, exposed_ports=(8080,)),
UnixLocalSandboxClientOptions(exposed_ports=(8080,)),
E2BSandboxClientOptions(sandbox_type="e2b", template="base"),
DaytonaSandboxClientOptions(image=DEFAULT_PYTHON_SANDBOX_IMAGE),
CloudflareSandboxClientOptions(worker_url="https://example.com"),
],
)
def test_sandbox_client_options_roundtrip_preserves_concrete_type(
options: BaseSandboxClientOptions,
) -> None:
payload = options.model_dump(mode="json")
restored = BaseSandboxClientOptions.parse(payload)
assert restored == options
assert type(restored) is type(options)
def test_sandbox_client_options_parse_rejects_unknown_type() -> None:
with pytest.raises(ValueError, match="unknown sandbox client options type `unknown`"):
BaseSandboxClientOptions.parse({"type": "unknown"})
def test_sandbox_client_options_parse_rejects_invalid_payload() -> None:
with pytest.raises(
TypeError,
match="sandbox client options payload must be a BaseSandboxClientOptions or object payload",
):
BaseSandboxClientOptions.parse("docker")
def test_duplicate_sandbox_client_options_type_registration_raises() -> None:
with pytest.raises(TypeError, match="already registered"):
class DuplicateDockerSandboxClientOptions(BaseSandboxClientOptions):
type: Literal["docker"] = "docker"
def test_sandbox_client_options_subclasses_require_type_discriminator_default() -> None:
with pytest.raises(TypeError, match="must define a non-empty string default for `type`"):
class MissingTypeSandboxClientOptions(BaseSandboxClientOptions):
pass