mirror of
https://github.com/anomalyco/opencode-sdk-python.git
synced 2026-04-28 12:39:54 +00:00
feat(api): update via SDK Studio
This commit is contained in:
parent
604017133e
commit
ff05a4adf0
130 changed files with 17166 additions and 1 deletions
277
tests/test_response.py
Normal file
277
tests/test_response.py
Normal file
|
|
@ -0,0 +1,277 @@
|
|||
import json
|
||||
from typing import Any, List, Union, cast
|
||||
from typing_extensions import Annotated
|
||||
|
||||
import httpx
|
||||
import pytest
|
||||
import pydantic
|
||||
|
||||
from opencode import Opencode, BaseModel, AsyncOpencode
|
||||
from opencode._response import (
|
||||
APIResponse,
|
||||
BaseAPIResponse,
|
||||
AsyncAPIResponse,
|
||||
BinaryAPIResponse,
|
||||
AsyncBinaryAPIResponse,
|
||||
extract_response_type,
|
||||
)
|
||||
from opencode._streaming import Stream
|
||||
from opencode._base_client import FinalRequestOptions
|
||||
|
||||
|
||||
class ConcreteBaseAPIResponse(APIResponse[bytes]): ...
|
||||
|
||||
|
||||
class ConcreteAPIResponse(APIResponse[List[str]]): ...
|
||||
|
||||
|
||||
class ConcreteAsyncAPIResponse(APIResponse[httpx.Response]): ...
|
||||
|
||||
|
||||
def test_extract_response_type_direct_classes() -> None:
|
||||
assert extract_response_type(BaseAPIResponse[str]) == str
|
||||
assert extract_response_type(APIResponse[str]) == str
|
||||
assert extract_response_type(AsyncAPIResponse[str]) == str
|
||||
|
||||
|
||||
def test_extract_response_type_direct_class_missing_type_arg() -> None:
|
||||
with pytest.raises(
|
||||
RuntimeError,
|
||||
match="Expected type <class 'opencode._response.AsyncAPIResponse'> to have a type argument at index 0 but it did not",
|
||||
):
|
||||
extract_response_type(AsyncAPIResponse)
|
||||
|
||||
|
||||
def test_extract_response_type_concrete_subclasses() -> None:
|
||||
assert extract_response_type(ConcreteBaseAPIResponse) == bytes
|
||||
assert extract_response_type(ConcreteAPIResponse) == List[str]
|
||||
assert extract_response_type(ConcreteAsyncAPIResponse) == httpx.Response
|
||||
|
||||
|
||||
def test_extract_response_type_binary_response() -> None:
|
||||
assert extract_response_type(BinaryAPIResponse) == bytes
|
||||
assert extract_response_type(AsyncBinaryAPIResponse) == bytes
|
||||
|
||||
|
||||
class PydanticModel(pydantic.BaseModel): ...
|
||||
|
||||
|
||||
def test_response_parse_mismatched_basemodel(client: Opencode) -> None:
|
||||
response = APIResponse(
|
||||
raw=httpx.Response(200, content=b"foo"),
|
||||
client=client,
|
||||
stream=False,
|
||||
stream_cls=None,
|
||||
cast_to=str,
|
||||
options=FinalRequestOptions.construct(method="get", url="/foo"),
|
||||
)
|
||||
|
||||
with pytest.raises(
|
||||
TypeError,
|
||||
match="Pydantic models must subclass our base model type, e.g. `from opencode import BaseModel`",
|
||||
):
|
||||
response.parse(to=PydanticModel)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_async_response_parse_mismatched_basemodel(async_client: AsyncOpencode) -> None:
|
||||
response = AsyncAPIResponse(
|
||||
raw=httpx.Response(200, content=b"foo"),
|
||||
client=async_client,
|
||||
stream=False,
|
||||
stream_cls=None,
|
||||
cast_to=str,
|
||||
options=FinalRequestOptions.construct(method="get", url="/foo"),
|
||||
)
|
||||
|
||||
with pytest.raises(
|
||||
TypeError,
|
||||
match="Pydantic models must subclass our base model type, e.g. `from opencode import BaseModel`",
|
||||
):
|
||||
await response.parse(to=PydanticModel)
|
||||
|
||||
|
||||
def test_response_parse_custom_stream(client: Opencode) -> None:
|
||||
response = APIResponse(
|
||||
raw=httpx.Response(200, content=b"foo"),
|
||||
client=client,
|
||||
stream=True,
|
||||
stream_cls=None,
|
||||
cast_to=str,
|
||||
options=FinalRequestOptions.construct(method="get", url="/foo"),
|
||||
)
|
||||
|
||||
stream = response.parse(to=Stream[int])
|
||||
assert stream._cast_to == int
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_async_response_parse_custom_stream(async_client: AsyncOpencode) -> None:
|
||||
response = AsyncAPIResponse(
|
||||
raw=httpx.Response(200, content=b"foo"),
|
||||
client=async_client,
|
||||
stream=True,
|
||||
stream_cls=None,
|
||||
cast_to=str,
|
||||
options=FinalRequestOptions.construct(method="get", url="/foo"),
|
||||
)
|
||||
|
||||
stream = await response.parse(to=Stream[int])
|
||||
assert stream._cast_to == int
|
||||
|
||||
|
||||
class CustomModel(BaseModel):
|
||||
foo: str
|
||||
bar: int
|
||||
|
||||
|
||||
def test_response_parse_custom_model(client: Opencode) -> None:
|
||||
response = APIResponse(
|
||||
raw=httpx.Response(200, content=json.dumps({"foo": "hello!", "bar": 2})),
|
||||
client=client,
|
||||
stream=False,
|
||||
stream_cls=None,
|
||||
cast_to=str,
|
||||
options=FinalRequestOptions.construct(method="get", url="/foo"),
|
||||
)
|
||||
|
||||
obj = response.parse(to=CustomModel)
|
||||
assert obj.foo == "hello!"
|
||||
assert obj.bar == 2
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_async_response_parse_custom_model(async_client: AsyncOpencode) -> None:
|
||||
response = AsyncAPIResponse(
|
||||
raw=httpx.Response(200, content=json.dumps({"foo": "hello!", "bar": 2})),
|
||||
client=async_client,
|
||||
stream=False,
|
||||
stream_cls=None,
|
||||
cast_to=str,
|
||||
options=FinalRequestOptions.construct(method="get", url="/foo"),
|
||||
)
|
||||
|
||||
obj = await response.parse(to=CustomModel)
|
||||
assert obj.foo == "hello!"
|
||||
assert obj.bar == 2
|
||||
|
||||
|
||||
def test_response_parse_annotated_type(client: Opencode) -> None:
|
||||
response = APIResponse(
|
||||
raw=httpx.Response(200, content=json.dumps({"foo": "hello!", "bar": 2})),
|
||||
client=client,
|
||||
stream=False,
|
||||
stream_cls=None,
|
||||
cast_to=str,
|
||||
options=FinalRequestOptions.construct(method="get", url="/foo"),
|
||||
)
|
||||
|
||||
obj = response.parse(
|
||||
to=cast("type[CustomModel]", Annotated[CustomModel, "random metadata"]),
|
||||
)
|
||||
assert obj.foo == "hello!"
|
||||
assert obj.bar == 2
|
||||
|
||||
|
||||
async def test_async_response_parse_annotated_type(async_client: AsyncOpencode) -> None:
|
||||
response = AsyncAPIResponse(
|
||||
raw=httpx.Response(200, content=json.dumps({"foo": "hello!", "bar": 2})),
|
||||
client=async_client,
|
||||
stream=False,
|
||||
stream_cls=None,
|
||||
cast_to=str,
|
||||
options=FinalRequestOptions.construct(method="get", url="/foo"),
|
||||
)
|
||||
|
||||
obj = await response.parse(
|
||||
to=cast("type[CustomModel]", Annotated[CustomModel, "random metadata"]),
|
||||
)
|
||||
assert obj.foo == "hello!"
|
||||
assert obj.bar == 2
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"content, expected",
|
||||
[
|
||||
("false", False),
|
||||
("true", True),
|
||||
("False", False),
|
||||
("True", True),
|
||||
("TrUe", True),
|
||||
("FalSe", False),
|
||||
],
|
||||
)
|
||||
def test_response_parse_bool(client: Opencode, content: str, expected: bool) -> None:
|
||||
response = APIResponse(
|
||||
raw=httpx.Response(200, content=content),
|
||||
client=client,
|
||||
stream=False,
|
||||
stream_cls=None,
|
||||
cast_to=str,
|
||||
options=FinalRequestOptions.construct(method="get", url="/foo"),
|
||||
)
|
||||
|
||||
result = response.parse(to=bool)
|
||||
assert result is expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"content, expected",
|
||||
[
|
||||
("false", False),
|
||||
("true", True),
|
||||
("False", False),
|
||||
("True", True),
|
||||
("TrUe", True),
|
||||
("FalSe", False),
|
||||
],
|
||||
)
|
||||
async def test_async_response_parse_bool(client: AsyncOpencode, content: str, expected: bool) -> None:
|
||||
response = AsyncAPIResponse(
|
||||
raw=httpx.Response(200, content=content),
|
||||
client=client,
|
||||
stream=False,
|
||||
stream_cls=None,
|
||||
cast_to=str,
|
||||
options=FinalRequestOptions.construct(method="get", url="/foo"),
|
||||
)
|
||||
|
||||
result = await response.parse(to=bool)
|
||||
assert result is expected
|
||||
|
||||
|
||||
class OtherModel(BaseModel):
|
||||
a: str
|
||||
|
||||
|
||||
@pytest.mark.parametrize("client", [False], indirect=True) # loose validation
|
||||
def test_response_parse_expect_model_union_non_json_content(client: Opencode) -> None:
|
||||
response = APIResponse(
|
||||
raw=httpx.Response(200, content=b"foo", headers={"Content-Type": "application/text"}),
|
||||
client=client,
|
||||
stream=False,
|
||||
stream_cls=None,
|
||||
cast_to=str,
|
||||
options=FinalRequestOptions.construct(method="get", url="/foo"),
|
||||
)
|
||||
|
||||
obj = response.parse(to=cast(Any, Union[CustomModel, OtherModel]))
|
||||
assert isinstance(obj, str)
|
||||
assert obj == "foo"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize("async_client", [False], indirect=True) # loose validation
|
||||
async def test_async_response_parse_expect_model_union_non_json_content(async_client: AsyncOpencode) -> None:
|
||||
response = AsyncAPIResponse(
|
||||
raw=httpx.Response(200, content=b"foo", headers={"Content-Type": "application/text"}),
|
||||
client=async_client,
|
||||
stream=False,
|
||||
stream_cls=None,
|
||||
cast_to=str,
|
||||
options=FinalRequestOptions.construct(method="get", url="/foo"),
|
||||
)
|
||||
|
||||
obj = await response.parse(to=cast(Any, Union[CustomModel, OtherModel]))
|
||||
assert isinstance(obj, str)
|
||||
assert obj == "foo"
|
||||
Loading…
Add table
Add a link
Reference in a new issue