mirror of
https://github.com/hanzoai/python-sdk.git
synced 2026-10-23 20:23:00 +00:00
feat(api): api update
This commit is contained in:
@@ -7,12 +7,17 @@ on:
|
||||
- 'integrated/**'
|
||||
- 'stl-preview-head/**'
|
||||
- 'stl-preview-base/**'
|
||||
pull_request:
|
||||
branches-ignore:
|
||||
- 'stl-preview-head/**'
|
||||
- 'stl-preview-base/**'
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
timeout-minutes: 10
|
||||
name: lint
|
||||
runs-on: ${{ github.repository == 'stainless-sdks/hanzo-ai-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
|
||||
if: github.event_name == 'push' || github.event.pull_request.head.repo.fork
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
@@ -30,10 +35,10 @@ jobs:
|
||||
- name: Run lints
|
||||
run: ./scripts/lint
|
||||
|
||||
upload:
|
||||
if: github.repository == 'stainless-sdks/hanzo-ai-python'
|
||||
build:
|
||||
if: github.repository == 'stainless-sdks/hanzo-ai-python' && (github.event_name == 'push' || github.event.pull_request.head.repo.fork)
|
||||
timeout-minutes: 10
|
||||
name: upload
|
||||
name: build
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
@@ -41,6 +46,20 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install Rye
|
||||
run: |
|
||||
curl -sSf https://rye.astral.sh/get | bash
|
||||
echo "$HOME/.rye/shims" >> $GITHUB_PATH
|
||||
env:
|
||||
RYE_VERSION: '0.44.0'
|
||||
RYE_INSTALL_OPTION: '--yes'
|
||||
|
||||
- name: Install dependencies
|
||||
run: rye sync --all-features
|
||||
|
||||
- name: Run build
|
||||
run: rye build
|
||||
|
||||
- name: Get GitHub OIDC Token
|
||||
id: github-oidc
|
||||
uses: actions/github-script@v6
|
||||
@@ -58,6 +77,7 @@ jobs:
|
||||
timeout-minutes: 10
|
||||
name: test
|
||||
runs-on: ${{ github.repository == 'stainless-sdks/hanzo-ai-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
|
||||
if: github.event_name == 'push' || github.event.pull_request.head.repo.fork
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
configured_endpoints: 188
|
||||
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/hanzo-industries-inc%2Fhanzo-ai-ec4be99f95dc46e9442eb60f233b2bff271d6f5bf57d7c61a52bc4804f55bbd1.yml
|
||||
openapi_spec_hash: 87bc62c36bb6028ffd1f3e54a2809099
|
||||
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/hanzo-industries-inc%2Fhanzo-ai-2d6e1036fb1eea7e95cafc281141ead9ef77796e43711b17edccaab67c5e791a.yml
|
||||
openapi_spec_hash: 12501774d0127be4ec1812d613a58e97
|
||||
config_hash: 830747463ff4d018b5633ce511e88558
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# Hanzo Python API library
|
||||
|
||||
[](https://pypi.org/project/hanzoai/)
|
||||
<!-- prettier-ignore -->
|
||||
[)](https://pypi.org/project/hanzoai/)
|
||||
|
||||
The Hanzo Python library provides convenient access to the Hanzo REST API from any Python 3.8+
|
||||
application. The library includes type definitions for all request params and response fields,
|
||||
@@ -64,6 +65,36 @@ asyncio.run(main())
|
||||
|
||||
Functionality between the synchronous and asynchronous clients is otherwise identical.
|
||||
|
||||
### With aiohttp
|
||||
|
||||
By default, the async client uses `httpx` for HTTP requests. However, for improved concurrency performance you may also use `aiohttp` as the HTTP backend.
|
||||
|
||||
You can enable this by installing `aiohttp`:
|
||||
|
||||
```sh
|
||||
# install from PyPI
|
||||
pip install hanzoai[aiohttp]
|
||||
```
|
||||
|
||||
Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`:
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from hanzoai import DefaultAioHttpClient
|
||||
from hanzoai import AsyncHanzo
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
async with AsyncHanzo(
|
||||
api_key="My API Key",
|
||||
http_client=DefaultAioHttpClient(),
|
||||
) as client:
|
||||
response = await client.get_home()
|
||||
|
||||
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
## Using types
|
||||
|
||||
Nested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev) which also provide helper methods for things like:
|
||||
@@ -172,7 +203,7 @@ client.with_options(max_retries=5).get_home()
|
||||
### Timeouts
|
||||
|
||||
By default requests time out after 1 minute. You can configure this with a `timeout` option,
|
||||
which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/#fine-tuning-the-configuration) object:
|
||||
which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object:
|
||||
|
||||
```python
|
||||
from hanzoai import Hanzo
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
errors=()
|
||||
|
||||
if [ -z "${PYPI_TOKEN}" ]; then
|
||||
errors+=("The HANZO_PYPI_TOKEN secret has not been set. Please set it in either this repository's secrets or your organization secrets.")
|
||||
errors+=("The PYPI_TOKEN secret has not been set. Please set it in either this repository's secrets or your organization secrets.")
|
||||
fi
|
||||
|
||||
lenErrors=${#errors[@]}
|
||||
|
||||
+5
-1
@@ -24,6 +24,7 @@ classifiers = [
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
"Programming Language :: Python :: 3.13",
|
||||
"Operating System :: OS Independent",
|
||||
"Operating System :: POSIX",
|
||||
"Operating System :: MacOS",
|
||||
@@ -37,6 +38,8 @@ classifiers = [
|
||||
Homepage = "https://github.com/hanzoai/python-sdk"
|
||||
Repository = "https://github.com/hanzoai/python-sdk"
|
||||
|
||||
[project.optional-dependencies]
|
||||
aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.8"]
|
||||
|
||||
[tool.rye]
|
||||
managed = true
|
||||
@@ -54,6 +57,7 @@ dev-dependencies = [
|
||||
"importlib-metadata>=6.7.0",
|
||||
"rich>=13.7.1",
|
||||
"nest_asyncio==1.6.0",
|
||||
"pytest-xdist>=3.6.1",
|
||||
]
|
||||
|
||||
[tool.rye.scripts]
|
||||
@@ -125,7 +129,7 @@ replacement = '[\1](https://github.com/hanzoai/python-sdk/tree/main/\g<2>)'
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = ["tests"]
|
||||
addopts = "--tb=short"
|
||||
addopts = "--tb=short -n auto"
|
||||
xfail_strict = true
|
||||
asyncio_mode = "auto"
|
||||
asyncio_default_fixture_loop_scope = "session"
|
||||
|
||||
+33
-2
@@ -10,6 +10,13 @@
|
||||
# universal: false
|
||||
|
||||
-e file:.
|
||||
aiohappyeyeballs==2.6.1
|
||||
# via aiohttp
|
||||
aiohttp==3.12.8
|
||||
# via hanzoai
|
||||
# via httpx-aiohttp
|
||||
aiosignal==1.3.2
|
||||
# via aiohttp
|
||||
annotated-types==0.6.0
|
||||
# via pydantic
|
||||
anyio==4.4.0
|
||||
@@ -17,6 +24,10 @@ anyio==4.4.0
|
||||
# via httpx
|
||||
argcomplete==3.1.2
|
||||
# via nox
|
||||
async-timeout==5.0.1
|
||||
# via aiohttp
|
||||
attrs==25.3.0
|
||||
# via aiohttp
|
||||
certifi==2023.7.22
|
||||
# via httpcore
|
||||
# via httpx
|
||||
@@ -30,18 +41,27 @@ distro==1.8.0
|
||||
exceptiongroup==1.2.2
|
||||
# via anyio
|
||||
# via pytest
|
||||
execnet==2.1.1
|
||||
# via pytest-xdist
|
||||
filelock==3.12.4
|
||||
# via virtualenv
|
||||
h11==0.14.0
|
||||
frozenlist==1.6.2
|
||||
# via aiohttp
|
||||
# via aiosignal
|
||||
h11==0.16.0
|
||||
# via httpcore
|
||||
httpcore==1.0.2
|
||||
httpcore==1.0.9
|
||||
# via httpx
|
||||
httpx==0.28.1
|
||||
# via hanzoai
|
||||
# via httpx-aiohttp
|
||||
# via respx
|
||||
httpx-aiohttp==0.1.8
|
||||
# via hanzoai
|
||||
idna==3.4
|
||||
# via anyio
|
||||
# via httpx
|
||||
# via yarl
|
||||
importlib-metadata==7.0.0
|
||||
iniconfig==2.0.0
|
||||
# via pytest
|
||||
@@ -49,6 +69,9 @@ markdown-it-py==3.0.0
|
||||
# via rich
|
||||
mdurl==0.1.2
|
||||
# via markdown-it-py
|
||||
multidict==6.4.4
|
||||
# via aiohttp
|
||||
# via yarl
|
||||
mypy==1.14.1
|
||||
mypy-extensions==1.0.0
|
||||
# via mypy
|
||||
@@ -63,6 +86,9 @@ platformdirs==3.11.0
|
||||
# via virtualenv
|
||||
pluggy==1.5.0
|
||||
# via pytest
|
||||
propcache==0.3.1
|
||||
# via aiohttp
|
||||
# via yarl
|
||||
pydantic==2.10.3
|
||||
# via hanzoai
|
||||
pydantic-core==2.27.1
|
||||
@@ -72,7 +98,9 @@ pygments==2.18.0
|
||||
pyright==1.1.399
|
||||
pytest==8.3.3
|
||||
# via pytest-asyncio
|
||||
# via pytest-xdist
|
||||
pytest-asyncio==0.24.0
|
||||
pytest-xdist==3.7.0
|
||||
python-dateutil==2.8.2
|
||||
# via time-machine
|
||||
pytz==2023.3.post1
|
||||
@@ -94,11 +122,14 @@ tomli==2.0.2
|
||||
typing-extensions==4.12.2
|
||||
# via anyio
|
||||
# via hanzoai
|
||||
# via multidict
|
||||
# via mypy
|
||||
# via pydantic
|
||||
# via pydantic-core
|
||||
# via pyright
|
||||
virtualenv==20.24.5
|
||||
# via nox
|
||||
yarl==1.20.0
|
||||
# via aiohttp
|
||||
zipp==3.17.0
|
||||
# via importlib-metadata
|
||||
|
||||
+29
-2
@@ -10,11 +10,22 @@
|
||||
# universal: false
|
||||
|
||||
-e file:.
|
||||
aiohappyeyeballs==2.6.1
|
||||
# via aiohttp
|
||||
aiohttp==3.12.8
|
||||
# via hanzoai
|
||||
# via httpx-aiohttp
|
||||
aiosignal==1.3.2
|
||||
# via aiohttp
|
||||
annotated-types==0.6.0
|
||||
# via pydantic
|
||||
anyio==4.4.0
|
||||
# via hanzoai
|
||||
# via httpx
|
||||
async-timeout==5.0.1
|
||||
# via aiohttp
|
||||
attrs==25.3.0
|
||||
# via aiohttp
|
||||
certifi==2023.7.22
|
||||
# via httpcore
|
||||
# via httpx
|
||||
@@ -22,15 +33,28 @@ distro==1.8.0
|
||||
# via hanzoai
|
||||
exceptiongroup==1.2.2
|
||||
# via anyio
|
||||
h11==0.14.0
|
||||
frozenlist==1.6.2
|
||||
# via aiohttp
|
||||
# via aiosignal
|
||||
h11==0.16.0
|
||||
# via httpcore
|
||||
httpcore==1.0.2
|
||||
httpcore==1.0.9
|
||||
# via httpx
|
||||
httpx==0.28.1
|
||||
# via hanzoai
|
||||
# via httpx-aiohttp
|
||||
httpx-aiohttp==0.1.8
|
||||
# via hanzoai
|
||||
idna==3.4
|
||||
# via anyio
|
||||
# via httpx
|
||||
# via yarl
|
||||
multidict==6.4.4
|
||||
# via aiohttp
|
||||
# via yarl
|
||||
propcache==0.3.1
|
||||
# via aiohttp
|
||||
# via yarl
|
||||
pydantic==2.10.3
|
||||
# via hanzoai
|
||||
pydantic-core==2.27.1
|
||||
@@ -41,5 +65,8 @@ sniffio==1.3.0
|
||||
typing-extensions==4.12.2
|
||||
# via anyio
|
||||
# via hanzoai
|
||||
# via multidict
|
||||
# via pydantic
|
||||
# via pydantic-core
|
||||
yarl==1.20.0
|
||||
# via aiohttp
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
set -exuo pipefail
|
||||
|
||||
RESPONSE=$(curl -X POST "$URL" \
|
||||
FILENAME=$(basename dist/*.whl)
|
||||
|
||||
RESPONSE=$(curl -X POST "$URL?filename=$FILENAME" \
|
||||
-H "Authorization: Bearer $AUTH" \
|
||||
-H "Content-Type: application/json")
|
||||
|
||||
@@ -12,13 +14,13 @@ if [[ "$SIGNED_URL" == "null" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
UPLOAD_RESPONSE=$(tar -cz . | curl -v -X PUT \
|
||||
-H "Content-Type: application/gzip" \
|
||||
--data-binary @- "$SIGNED_URL" 2>&1)
|
||||
UPLOAD_RESPONSE=$(curl -v -X PUT \
|
||||
-H "Content-Type: binary/octet-stream" \
|
||||
--data-binary "@dist/$FILENAME" "$SIGNED_URL" 2>&1)
|
||||
|
||||
if echo "$UPLOAD_RESPONSE" | grep -q "HTTP/[0-9.]* 200"; then
|
||||
echo -e "\033[32mUploaded build to Stainless storage.\033[0m"
|
||||
echo -e "\033[32mInstallation: pip install 'https://pkg.stainless.com/s/hanzo-ai-python/$SHA'\033[0m"
|
||||
echo -e "\033[32mInstallation: pip install 'https://pkg.stainless.com/s/hanzo-ai-python/$SHA/$FILENAME'\033[0m"
|
||||
else
|
||||
echo -e "\033[31mFailed to upload artifact.\033[0m"
|
||||
exit 1
|
||||
|
||||
@@ -37,7 +37,7 @@ from ._exceptions import (
|
||||
UnprocessableEntityError,
|
||||
APIResponseValidationError,
|
||||
)
|
||||
from ._base_client import DefaultHttpxClient, DefaultAsyncHttpxClient
|
||||
from ._base_client import DefaultHttpxClient, DefaultAioHttpClient, DefaultAsyncHttpxClient
|
||||
from ._utils._logs import setup_logging as _setup_logging
|
||||
|
||||
__all__ = [
|
||||
@@ -80,6 +80,7 @@ __all__ = [
|
||||
"DEFAULT_CONNECTION_LIMITS",
|
||||
"DefaultHttpxClient",
|
||||
"DefaultAsyncHttpxClient",
|
||||
"DefaultAioHttpClient",
|
||||
]
|
||||
|
||||
if not _t.TYPE_CHECKING:
|
||||
|
||||
@@ -529,6 +529,15 @@ class BaseClient(Generic[_HttpxClientT, _DefaultStreamT]):
|
||||
# work around https://github.com/encode/httpx/discussions/2880
|
||||
kwargs["extensions"] = {"sni_hostname": prepared_url.host.replace("_", "-")}
|
||||
|
||||
is_body_allowed = options.method.lower() != "get"
|
||||
|
||||
if is_body_allowed:
|
||||
kwargs["json"] = json_data if is_given(json_data) else None
|
||||
kwargs["files"] = files
|
||||
else:
|
||||
headers.pop("Content-Type", None)
|
||||
kwargs.pop("data", None)
|
||||
|
||||
# TODO: report this error to httpx
|
||||
return self._client.build_request( # pyright: ignore[reportUnknownMemberType]
|
||||
headers=headers,
|
||||
@@ -540,8 +549,6 @@ class BaseClient(Generic[_HttpxClientT, _DefaultStreamT]):
|
||||
# so that passing a `TypedDict` doesn't cause an error.
|
||||
# https://github.com/microsoft/pyright/issues/3526#event-6715453066
|
||||
params=self.qs.stringify(cast(Mapping[str, Any], params)) if params else None,
|
||||
json=json_data if is_given(json_data) else None,
|
||||
files=files,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
@@ -1071,7 +1078,14 @@ class SyncAPIClient(BaseClient[httpx.Client, Stream[Any]]):
|
||||
) -> ResponseT:
|
||||
origin = get_origin(cast_to) or cast_to
|
||||
|
||||
if inspect.isclass(origin) and issubclass(origin, BaseAPIResponse):
|
||||
if (
|
||||
inspect.isclass(origin)
|
||||
and issubclass(origin, BaseAPIResponse)
|
||||
# we only want to actually return the custom BaseAPIResponse class if we're
|
||||
# returning the raw response, or if we're not streaming SSE, as if we're streaming
|
||||
# SSE then `cast_to` doesn't actively reflect the type we need to parse into
|
||||
and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER)))
|
||||
):
|
||||
if not issubclass(origin, APIResponse):
|
||||
raise TypeError(f"API Response types must subclass {APIResponse}; Received {origin}")
|
||||
|
||||
@@ -1282,6 +1296,24 @@ class _DefaultAsyncHttpxClient(httpx.AsyncClient):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
|
||||
try:
|
||||
import httpx_aiohttp
|
||||
except ImportError:
|
||||
|
||||
class _DefaultAioHttpClient(httpx.AsyncClient):
|
||||
def __init__(self, **_kwargs: Any) -> None:
|
||||
raise RuntimeError("To use the aiohttp client you must have installed the package with the `aiohttp` extra")
|
||||
else:
|
||||
|
||||
class _DefaultAioHttpClient(httpx_aiohttp.HttpxAiohttpClient): # type: ignore
|
||||
def __init__(self, **kwargs: Any) -> None:
|
||||
kwargs.setdefault("timeout", DEFAULT_TIMEOUT)
|
||||
kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS)
|
||||
kwargs.setdefault("follow_redirects", True)
|
||||
|
||||
super().__init__(**kwargs)
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
DefaultAsyncHttpxClient = httpx.AsyncClient
|
||||
"""An alias to `httpx.AsyncClient` that provides the same defaults that this SDK
|
||||
@@ -1290,8 +1322,12 @@ if TYPE_CHECKING:
|
||||
This is useful because overriding the `http_client` with your own instance of
|
||||
`httpx.AsyncClient` will result in httpx's defaults being used, not ours.
|
||||
"""
|
||||
|
||||
DefaultAioHttpClient = httpx.AsyncClient
|
||||
"""An alias to `httpx.AsyncClient` that changes the default HTTP transport to `aiohttp`."""
|
||||
else:
|
||||
DefaultAsyncHttpxClient = _DefaultAsyncHttpxClient
|
||||
DefaultAioHttpClient = _DefaultAioHttpClient
|
||||
|
||||
|
||||
class AsyncHttpxClientWrapper(DefaultAsyncHttpxClient):
|
||||
@@ -1574,7 +1610,14 @@ class AsyncAPIClient(BaseClient[httpx.AsyncClient, AsyncStream[Any]]):
|
||||
) -> ResponseT:
|
||||
origin = get_origin(cast_to) or cast_to
|
||||
|
||||
if inspect.isclass(origin) and issubclass(origin, BaseAPIResponse):
|
||||
if (
|
||||
inspect.isclass(origin)
|
||||
and issubclass(origin, BaseAPIResponse)
|
||||
# we only want to actually return the custom BaseAPIResponse class if we're
|
||||
# returning the raw response, or if we're not streaming SSE, as if we're streaming
|
||||
# SSE then `cast_to` doesn't actively reflect the type we need to parse into
|
||||
and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER)))
|
||||
):
|
||||
if not issubclass(origin, AsyncAPIResponse):
|
||||
raise TypeError(f"API Response types must subclass {AsyncAPIResponse}; Received {origin}")
|
||||
|
||||
|
||||
@@ -2,9 +2,10 @@ from __future__ import annotations
|
||||
|
||||
import os
|
||||
import inspect
|
||||
from typing import TYPE_CHECKING, Any, Type, Union, Generic, TypeVar, Callable, cast
|
||||
from typing import TYPE_CHECKING, Any, Type, Union, Generic, TypeVar, Callable, Optional, cast
|
||||
from datetime import date, datetime
|
||||
from typing_extensions import (
|
||||
List,
|
||||
Unpack,
|
||||
Literal,
|
||||
ClassVar,
|
||||
@@ -366,7 +367,7 @@ def _construct_field(value: object, field: FieldInfo, key: str) -> object:
|
||||
if type_ is None:
|
||||
raise RuntimeError(f"Unexpected field type is None for {key}")
|
||||
|
||||
return construct_type(value=value, type_=type_)
|
||||
return construct_type(value=value, type_=type_, metadata=getattr(field, "metadata", None))
|
||||
|
||||
|
||||
def is_basemodel(type_: type) -> bool:
|
||||
@@ -420,7 +421,7 @@ def construct_type_unchecked(*, value: object, type_: type[_T]) -> _T:
|
||||
return cast(_T, construct_type(value=value, type_=type_))
|
||||
|
||||
|
||||
def construct_type(*, value: object, type_: object) -> object:
|
||||
def construct_type(*, value: object, type_: object, metadata: Optional[List[Any]] = None) -> object:
|
||||
"""Loose coercion to the expected type with construction of nested values.
|
||||
|
||||
If the given value does not match the expected type then it is returned as-is.
|
||||
@@ -438,8 +439,10 @@ def construct_type(*, value: object, type_: object) -> object:
|
||||
type_ = type_.__value__ # type: ignore[unreachable]
|
||||
|
||||
# unwrap `Annotated[T, ...]` -> `T`
|
||||
if is_annotated_type(type_):
|
||||
meta: tuple[Any, ...] = get_args(type_)[1:]
|
||||
if metadata is not None:
|
||||
meta: tuple[Any, ...] = tuple(metadata)
|
||||
elif is_annotated_type(type_):
|
||||
meta = get_args(type_)[1:]
|
||||
type_ = extract_type_arg(type_, 0)
|
||||
else:
|
||||
meta = tuple()
|
||||
|
||||
@@ -46,7 +46,9 @@ class TestSpeech:
|
||||
|
||||
|
||||
class TestAsyncSpeech:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -52,7 +52,9 @@ class TestTranscriptions:
|
||||
|
||||
|
||||
class TestAsyncTranscriptions:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -69,7 +69,9 @@ class TestCancel:
|
||||
|
||||
|
||||
class TestAsyncCancel:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
+3
-1
@@ -46,7 +46,9 @@ class TestRedis:
|
||||
|
||||
|
||||
class TestAsyncRedis:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -54,7 +54,9 @@ class TestCompletions:
|
||||
|
||||
|
||||
class TestAsyncCompletions:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -173,7 +173,9 @@ class TestPassThroughEndpoint:
|
||||
|
||||
|
||||
class TestAsyncPassThroughEndpoint:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -60,7 +60,9 @@ class TestChat:
|
||||
|
||||
|
||||
class TestAsyncChat:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -70,7 +70,9 @@ class TestContent:
|
||||
|
||||
|
||||
class TestAsyncContent:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -60,7 +60,9 @@ class TestCancel:
|
||||
|
||||
|
||||
class TestAsyncCancel:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -167,7 +167,9 @@ class TestJobs:
|
||||
|
||||
|
||||
class TestAsyncJobs:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -130,7 +130,9 @@ class TestSpend:
|
||||
|
||||
|
||||
class TestAsyncSpend:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -46,7 +46,9 @@ class TestGenerations:
|
||||
|
||||
|
||||
class TestAsyncGenerations:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -54,7 +54,9 @@ class TestInfo:
|
||||
|
||||
|
||||
class TestAsyncInfo:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -196,7 +196,9 @@ class TestUpdate:
|
||||
|
||||
|
||||
class TestAsyncUpdate:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -60,7 +60,9 @@ class TestChat:
|
||||
|
||||
|
||||
class TestAsyncChat:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -102,7 +102,9 @@ class TestDeployments:
|
||||
|
||||
|
||||
class TestAsyncDeployments:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -87,7 +87,9 @@ class TestInfo:
|
||||
|
||||
|
||||
class TestAsyncInfo:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -60,7 +60,9 @@ class TestInputItems:
|
||||
|
||||
|
||||
class TestAsyncInputItems:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -122,7 +122,9 @@ class TestCallback:
|
||||
|
||||
|
||||
class TestAsyncCallback:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -92,7 +92,9 @@ class TestModel:
|
||||
|
||||
|
||||
class TestAsyncModel:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -46,7 +46,9 @@ class TestActive:
|
||||
|
||||
|
||||
class TestAsyncActive:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -52,7 +52,9 @@ class TestAdd:
|
||||
|
||||
|
||||
class TestAsyncAdd:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -228,7 +228,9 @@ class TestAnthropic:
|
||||
|
||||
|
||||
class TestAsyncAnthropic:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -228,7 +228,9 @@ class TestAssemblyai:
|
||||
|
||||
|
||||
class TestAsyncAssemblyai:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -116,7 +116,9 @@ class TestAssistants:
|
||||
|
||||
|
||||
class TestAsyncAssistants:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -228,7 +228,9 @@ class TestAzure:
|
||||
|
||||
|
||||
class TestAsyncAzure:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -341,7 +341,9 @@ class TestBatches:
|
||||
|
||||
|
||||
class TestAsyncBatches:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -228,7 +228,9 @@ class TestBedrock:
|
||||
|
||||
|
||||
class TestAsyncBedrock:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -248,7 +248,9 @@ class TestBudget:
|
||||
|
||||
|
||||
class TestAsyncBudget:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -103,7 +103,9 @@ class TestCache:
|
||||
|
||||
|
||||
class TestAsyncCache:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -46,7 +46,9 @@ class TestClient:
|
||||
|
||||
|
||||
class TestAsyncClient:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -228,7 +228,9 @@ class TestCohere:
|
||||
|
||||
|
||||
class TestAsyncCohere:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -54,7 +54,9 @@ class TestCompletions:
|
||||
|
||||
|
||||
class TestAsyncCompletions:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -136,7 +136,9 @@ class TestCredentials:
|
||||
|
||||
|
||||
class TestAsyncCredentials:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -295,7 +295,9 @@ class TestCustomer:
|
||||
|
||||
|
||||
class TestAsyncCustomer:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -52,7 +52,9 @@ class TestDelete:
|
||||
|
||||
|
||||
class TestAsyncDelete:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -54,7 +54,9 @@ class TestEmbeddings:
|
||||
|
||||
|
||||
class TestAsyncEmbeddings:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -102,7 +102,9 @@ class TestEngines:
|
||||
|
||||
|
||||
class TestAsyncEngines:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -228,7 +228,9 @@ class TestEuAssemblyai:
|
||||
|
||||
|
||||
class TestAsyncEuAssemblyai:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -234,7 +234,9 @@ class TestFiles:
|
||||
|
||||
|
||||
class TestAsyncFiles:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -228,7 +228,9 @@ class TestGemini:
|
||||
|
||||
|
||||
class TestAsyncGemini:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -47,7 +47,9 @@ class TestGuardrails:
|
||||
|
||||
|
||||
class TestAsyncGuardrails:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -172,7 +172,9 @@ class TestHealth:
|
||||
|
||||
|
||||
class TestAsyncHealth:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -467,7 +467,9 @@ class TestKey:
|
||||
|
||||
|
||||
class TestAsyncKey:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -228,7 +228,9 @@ class TestLangfuse:
|
||||
|
||||
|
||||
class TestAsyncLangfuse:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -146,7 +146,9 @@ class TestModel:
|
||||
|
||||
|
||||
class TestAsyncModel:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -54,7 +54,9 @@ class TestModelGroup:
|
||||
|
||||
|
||||
class TestAsyncModelGroup:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -55,7 +55,9 @@ class TestModels:
|
||||
|
||||
|
||||
class TestAsyncModels:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -46,7 +46,9 @@ class TestModerations:
|
||||
|
||||
|
||||
class TestAsyncModerations:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -228,7 +228,9 @@ class TestOpenAI:
|
||||
|
||||
|
||||
class TestAsyncOpenAI:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -326,7 +326,9 @@ class TestOrganization:
|
||||
|
||||
|
||||
class TestAsyncOrganization:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -47,7 +47,9 @@ class TestProvider:
|
||||
|
||||
|
||||
class TestAsyncProvider:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -102,7 +102,9 @@ class TestRerank:
|
||||
|
||||
|
||||
class TestAsyncRerank:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -130,7 +130,9 @@ class TestResponses:
|
||||
|
||||
|
||||
class TestAsyncResponses:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -46,7 +46,9 @@ class TestRoutes:
|
||||
|
||||
|
||||
class TestAsyncRoutes:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -46,7 +46,9 @@ class TestSettings:
|
||||
|
||||
|
||||
class TestAsyncSettings:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -137,7 +137,9 @@ class TestSpend:
|
||||
|
||||
|
||||
class TestAsyncSpend:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -541,7 +541,9 @@ class TestTeam:
|
||||
|
||||
|
||||
class TestAsyncTeam:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -46,7 +46,9 @@ class TestTest:
|
||||
|
||||
|
||||
class TestAsyncTest:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -88,7 +88,9 @@ class TestThreads:
|
||||
|
||||
|
||||
class TestAsyncThreads:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -260,7 +260,9 @@ class TestUser:
|
||||
|
||||
|
||||
class TestAsyncUser:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -137,7 +137,9 @@ class TestUtils:
|
||||
|
||||
|
||||
class TestAsyncUtils:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -228,7 +228,9 @@ class TestVertexAI:
|
||||
|
||||
|
||||
class TestAsyncVertexAI:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -102,7 +102,9 @@ class TestMessages:
|
||||
|
||||
|
||||
class TestAsyncMessages:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
@@ -60,7 +60,9 @@ class TestRuns:
|
||||
|
||||
|
||||
class TestAsyncRuns:
|
||||
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
|
||||
parametrize = pytest.mark.parametrize(
|
||||
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
|
||||
)
|
||||
|
||||
@pytest.mark.skip()
|
||||
@parametrize
|
||||
|
||||
+38
-5
@@ -1,13 +1,17 @@
|
||||
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, Iterator, AsyncIterator
|
||||
|
||||
import httpx
|
||||
import pytest
|
||||
from pytest_asyncio import is_async_test
|
||||
|
||||
from hanzoai import Hanzo, AsyncHanzo
|
||||
from hanzoai import Hanzo, AsyncHanzo, DefaultAioHttpClient
|
||||
from hanzoai._utils import is_dict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from _pytest.fixtures import FixtureRequest # pyright: ignore[reportPrivateImportUsage]
|
||||
@@ -25,6 +29,19 @@ def pytest_collection_modifyitems(items: list[pytest.Function]) -> None:
|
||||
for async_test in pytest_asyncio_tests:
|
||||
async_test.add_marker(session_scope_marker, append=False)
|
||||
|
||||
# We skip tests that use both the aiohttp client and respx_mock as respx_mock
|
||||
# doesn't support custom transports.
|
||||
for item in items:
|
||||
if "async_client" not in item.fixturenames or "respx_mock" not in item.fixturenames:
|
||||
continue
|
||||
|
||||
if not hasattr(item, "callspec"):
|
||||
continue
|
||||
|
||||
async_client_param = item.callspec.params.get("async_client")
|
||||
if is_dict(async_client_param) and async_client_param.get("http_client") == "aiohttp":
|
||||
item.add_marker(pytest.mark.skip(reason="aiohttp client is not compatible with respx_mock"))
|
||||
|
||||
|
||||
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
|
||||
|
||||
@@ -43,9 +60,25 @@ def client(request: FixtureRequest) -> Iterator[Hanzo]:
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
async def async_client(request: FixtureRequest) -> AsyncIterator[AsyncHanzo]:
|
||||
strict = getattr(request, "param", True)
|
||||
if not isinstance(strict, bool):
|
||||
raise TypeError(f"Unexpected fixture parameter type {type(strict)}, expected {bool}")
|
||||
param = getattr(request, "param", True)
|
||||
|
||||
async with AsyncHanzo(base_url=base_url, api_key=api_key, _strict_response_validation=strict) as client:
|
||||
# defaults
|
||||
strict = True
|
||||
http_client: None | httpx.AsyncClient = None
|
||||
|
||||
if isinstance(param, bool):
|
||||
strict = param
|
||||
elif is_dict(param):
|
||||
strict = param.get("strict", True)
|
||||
assert isinstance(strict, bool)
|
||||
|
||||
http_client_type = param.get("http_client", "httpx")
|
||||
if http_client_type == "aiohttp":
|
||||
http_client = DefaultAioHttpClient()
|
||||
else:
|
||||
raise TypeError(f"Unexpected fixture parameter type {type(param)}, expected bool or dict")
|
||||
|
||||
async with AsyncHanzo(
|
||||
base_url=base_url, api_key=api_key, _strict_response_validation=strict, http_client=http_client
|
||||
) as client:
|
||||
yield client
|
||||
|
||||
+58
-13
@@ -24,12 +24,13 @@ from pydantic import ValidationError
|
||||
from hanzoai import Hanzo, AsyncHanzo, APIResponseValidationError
|
||||
from hanzoai._types import Omit
|
||||
from hanzoai._models import BaseModel, FinalRequestOptions
|
||||
from hanzoai._constants import RAW_RESPONSE_HEADER
|
||||
from hanzoai._exceptions import HanzoError, APIStatusError, APITimeoutError, APIResponseValidationError
|
||||
from hanzoai._base_client import (
|
||||
DEFAULT_TIMEOUT,
|
||||
HTTPX_DEFAULT_TIMEOUT,
|
||||
BaseClient,
|
||||
DefaultHttpxClient,
|
||||
DefaultAsyncHttpxClient,
|
||||
make_request_options,
|
||||
)
|
||||
|
||||
@@ -190,6 +191,7 @@ class TestHanzo:
|
||||
copy_param = copy_signature.parameters.get(name)
|
||||
assert copy_param is not None, f"copy() signature is missing the {name} param"
|
||||
|
||||
@pytest.mark.skipif(sys.version_info >= (3, 10), reason="fails because of a memory leak that started from 3.12")
|
||||
def test_copy_build_request(self) -> None:
|
||||
options = FinalRequestOptions(method="get", url="/foo")
|
||||
|
||||
@@ -460,7 +462,7 @@ class TestHanzo:
|
||||
def test_multipart_repeating_array(self, client: Hanzo) -> None:
|
||||
request = client._build_request(
|
||||
FinalRequestOptions.construct(
|
||||
method="get",
|
||||
method="post",
|
||||
url="/foo",
|
||||
headers={"Content-Type": "multipart/form-data; boundary=6b7ba517decee4a450543ea6ae821c82"},
|
||||
json_data={"array": ["foo", "bar"]},
|
||||
@@ -717,22 +719,21 @@ class TestHanzo:
|
||||
|
||||
@mock.patch("hanzoai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
|
||||
@pytest.mark.respx(base_url=base_url)
|
||||
def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter) -> None:
|
||||
def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter, client: Hanzo) -> None:
|
||||
respx_mock.get("/").mock(side_effect=httpx.TimeoutException("Test timeout error"))
|
||||
|
||||
with pytest.raises(APITimeoutError):
|
||||
self.client.get("/", cast_to=httpx.Response, options={"headers": {RAW_RESPONSE_HEADER: "stream"}})
|
||||
client.with_streaming_response.get_home().__enter__()
|
||||
|
||||
assert _get_open_connections(self.client) == 0
|
||||
|
||||
@mock.patch("hanzoai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
|
||||
@pytest.mark.respx(base_url=base_url)
|
||||
def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter) -> None:
|
||||
def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter, client: Hanzo) -> None:
|
||||
respx_mock.get("/").mock(return_value=httpx.Response(500))
|
||||
|
||||
with pytest.raises(APIStatusError):
|
||||
self.client.get("/", cast_to=httpx.Response, options={"headers": {RAW_RESPONSE_HEADER: "stream"}})
|
||||
|
||||
client.with_streaming_response.get_home().__enter__()
|
||||
assert _get_open_connections(self.client) == 0
|
||||
|
||||
@pytest.mark.parametrize("failures_before_success", [0, 2, 4])
|
||||
@@ -810,6 +811,28 @@ class TestHanzo:
|
||||
|
||||
assert response.http_request.headers.get("x-stainless-retry-count") == "42"
|
||||
|
||||
def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
# Test that the proxy environment variables are set correctly
|
||||
monkeypatch.setenv("HTTPS_PROXY", "https://example.org")
|
||||
|
||||
client = DefaultHttpxClient()
|
||||
|
||||
mounts = tuple(client._mounts.items())
|
||||
assert len(mounts) == 1
|
||||
assert mounts[0][0].pattern == "https://"
|
||||
|
||||
@pytest.mark.filterwarnings("ignore:.*deprecated.*:DeprecationWarning")
|
||||
def test_default_client_creation(self) -> None:
|
||||
# Ensure that the client can be initialized without any exceptions
|
||||
DefaultHttpxClient(
|
||||
verify=True,
|
||||
cert=None,
|
||||
trust_env=True,
|
||||
http1=True,
|
||||
http2=False,
|
||||
limits=httpx.Limits(max_connections=100, max_keepalive_connections=20),
|
||||
)
|
||||
|
||||
@pytest.mark.respx(base_url=base_url)
|
||||
def test_follow_redirects(self, respx_mock: MockRouter) -> None:
|
||||
# Test that the default follow_redirects=True allows following redirects
|
||||
@@ -973,6 +996,7 @@ class TestAsyncHanzo:
|
||||
copy_param = copy_signature.parameters.get(name)
|
||||
assert copy_param is not None, f"copy() signature is missing the {name} param"
|
||||
|
||||
@pytest.mark.skipif(sys.version_info >= (3, 10), reason="fails because of a memory leak that started from 3.12")
|
||||
def test_copy_build_request(self) -> None:
|
||||
options = FinalRequestOptions(method="get", url="/foo")
|
||||
|
||||
@@ -1245,7 +1269,7 @@ class TestAsyncHanzo:
|
||||
def test_multipart_repeating_array(self, async_client: AsyncHanzo) -> None:
|
||||
request = async_client._build_request(
|
||||
FinalRequestOptions.construct(
|
||||
method="get",
|
||||
method="post",
|
||||
url="/foo",
|
||||
headers={"Content-Type": "multipart/form-data; boundary=6b7ba517decee4a450543ea6ae821c82"},
|
||||
json_data={"array": ["foo", "bar"]},
|
||||
@@ -1516,22 +1540,21 @@ class TestAsyncHanzo:
|
||||
|
||||
@mock.patch("hanzoai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
|
||||
@pytest.mark.respx(base_url=base_url)
|
||||
async def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter) -> None:
|
||||
async def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter, async_client: AsyncHanzo) -> None:
|
||||
respx_mock.get("/").mock(side_effect=httpx.TimeoutException("Test timeout error"))
|
||||
|
||||
with pytest.raises(APITimeoutError):
|
||||
await self.client.get("/", cast_to=httpx.Response, options={"headers": {RAW_RESPONSE_HEADER: "stream"}})
|
||||
await async_client.with_streaming_response.get_home().__aenter__()
|
||||
|
||||
assert _get_open_connections(self.client) == 0
|
||||
|
||||
@mock.patch("hanzoai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
|
||||
@pytest.mark.respx(base_url=base_url)
|
||||
async def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter) -> None:
|
||||
async def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter, async_client: AsyncHanzo) -> None:
|
||||
respx_mock.get("/").mock(return_value=httpx.Response(500))
|
||||
|
||||
with pytest.raises(APIStatusError):
|
||||
await self.client.get("/", cast_to=httpx.Response, options={"headers": {RAW_RESPONSE_HEADER: "stream"}})
|
||||
|
||||
await async_client.with_streaming_response.get_home().__aenter__()
|
||||
assert _get_open_connections(self.client) == 0
|
||||
|
||||
@pytest.mark.parametrize("failures_before_success", [0, 2, 4])
|
||||
@@ -1659,6 +1682,28 @@ class TestAsyncHanzo:
|
||||
|
||||
time.sleep(0.1)
|
||||
|
||||
async def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
# Test that the proxy environment variables are set correctly
|
||||
monkeypatch.setenv("HTTPS_PROXY", "https://example.org")
|
||||
|
||||
client = DefaultAsyncHttpxClient()
|
||||
|
||||
mounts = tuple(client._mounts.items())
|
||||
assert len(mounts) == 1
|
||||
assert mounts[0][0].pattern == "https://"
|
||||
|
||||
@pytest.mark.filterwarnings("ignore:.*deprecated.*:DeprecationWarning")
|
||||
async def test_default_client_creation(self) -> None:
|
||||
# Ensure that the client can be initialized without any exceptions
|
||||
DefaultAsyncHttpxClient(
|
||||
verify=True,
|
||||
cert=None,
|
||||
trust_env=True,
|
||||
http1=True,
|
||||
http2=False,
|
||||
limits=httpx.Limits(max_connections=100, max_keepalive_connections=20),
|
||||
)
|
||||
|
||||
@pytest.mark.respx(base_url=base_url)
|
||||
async def test_follow_redirects(self, respx_mock: MockRouter) -> None:
|
||||
# Test that the default follow_redirects=True allows following redirects
|
||||
|
||||
@@ -889,3 +889,48 @@ def test_discriminated_union_case() -> None:
|
||||
)
|
||||
|
||||
assert isinstance(m, ModelB)
|
||||
|
||||
|
||||
def test_nested_discriminated_union() -> None:
|
||||
class InnerType1(BaseModel):
|
||||
type: Literal["type_1"]
|
||||
|
||||
class InnerModel(BaseModel):
|
||||
inner_value: str
|
||||
|
||||
class InnerType2(BaseModel):
|
||||
type: Literal["type_2"]
|
||||
some_inner_model: InnerModel
|
||||
|
||||
class Type1(BaseModel):
|
||||
base_type: Literal["base_type_1"]
|
||||
value: Annotated[
|
||||
Union[
|
||||
InnerType1,
|
||||
InnerType2,
|
||||
],
|
||||
PropertyInfo(discriminator="type"),
|
||||
]
|
||||
|
||||
class Type2(BaseModel):
|
||||
base_type: Literal["base_type_2"]
|
||||
|
||||
T = Annotated[
|
||||
Union[
|
||||
Type1,
|
||||
Type2,
|
||||
],
|
||||
PropertyInfo(discriminator="base_type"),
|
||||
]
|
||||
|
||||
model = construct_type(
|
||||
type_=T,
|
||||
value={
|
||||
"base_type": "base_type_1",
|
||||
"value": {
|
||||
"type": "type_2",
|
||||
},
|
||||
},
|
||||
)
|
||||
assert isinstance(model, Type1)
|
||||
assert isinstance(model.value, InnerType2)
|
||||
|
||||
Reference in New Issue
Block a user