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
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,19 @@
import logging
from typing import Any

from httpx import (
ConnectError,
HTTPStatusError,
NetworkError,
ReadTimeout,
TimeoutException,
WriteTimeout,
)

from opensandbox.api.execd.errors import UnexpectedStatus as ExecdUnexpectedStatus
from opensandbox.api.lifecycle.errors import (
UnexpectedStatus as LifecycleUnexpectedStatus,
)
from opensandbox.exceptions import (
InvalidArgumentException,
SandboxApiException,
Expand All @@ -40,6 +53,15 @@

logger = logging.getLogger(__name__)

UNEXPECTED_STATUS_TYPES = (LifecycleUnexpectedStatus, ExecdUnexpectedStatus)
HTTPX_NETWORK_ERROR_TYPES = (
ConnectError,
TimeoutException,
NetworkError,
ReadTimeout,
WriteTimeout,
)


class ExceptionConverter:
"""
Expand Down Expand Up @@ -124,24 +146,17 @@ def to_sandbox_exception(e: Exception) -> SandboxException:

def _is_unexpected_status_error(e: Exception) -> bool:
"""Check if exception is an openapi-python-client UnexpectedStatus error."""
return type(e).__name__ == "UnexpectedStatus"
return isinstance(e, UNEXPECTED_STATUS_TYPES)


def _is_httpx_status_error(e: Exception) -> bool:
"""Check if exception is an httpx HTTPStatusError."""
return type(e).__name__ == "HTTPStatusError"
return isinstance(e, HTTPStatusError)


def _is_httpx_network_error(e: Exception) -> bool:
"""Check if exception is an httpx network-related error."""
error_types = (
"ConnectError",
"TimeoutException",
"NetworkError",
"ReadTimeout",
"WriteTimeout",
)
return type(e).__name__ in error_types
return isinstance(e, HTTPX_NETWORK_ERROR_TYPES)


def _convert_unexpected_status_to_api_exception(e: Exception) -> SandboxApiException:
Expand Down
30 changes: 30 additions & 0 deletions sdks/sandbox/python/tests/test_converters_and_error_handling.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from datetime import datetime, timedelta

import pytest
from httpx import HTTPStatusError, Request, Response

from opensandbox.adapters.converter.exception_converter import (
ExceptionConverter,
Expand All @@ -36,6 +37,7 @@
from opensandbox.adapters.converter.sandbox_model_converter import (
SandboxModelConverter,
)
from opensandbox.api.lifecycle.errors import UnexpectedStatus
from opensandbox.exceptions import (
InvalidArgumentException,
SandboxApiException,
Expand Down Expand Up @@ -96,6 +98,34 @@ def test_exception_converter_maps_common_types() -> None:
assert isinstance(se2, SandboxInternalException)


def test_exception_converter_maps_generated_unexpected_status_to_api_exception() -> (
None
):
err = UnexpectedStatus(400, b'{"code":"X","message":"bad"}')

converted = ExceptionConverter.to_sandbox_exception(err)

assert isinstance(converted, SandboxApiException)
assert converted.status_code == 400
assert converted.error is not None
assert converted.error.code == "X"


def test_exception_converter_maps_httpx_status_error_to_api_exception() -> None:
request = Request("GET", "https://example.test")
response = Response(
502, request=request, content=b'{"code":"UPSTREAM","message":"gateway"}'
)
err = HTTPStatusError("bad gateway", request=request, response=response)

converted = ExceptionConverter.to_sandbox_exception(err)

assert isinstance(converted, SandboxApiException)
assert converted.status_code == 502
assert converted.error is not None
assert converted.error.code == "UPSTREAM"


def test_execution_converter_to_api_run_command_request() -> None:
from opensandbox.api.execd.types import UNSET

Expand Down