From 02fb529b42f1ea8fd90f329c2db4c607ba04645c Mon Sep 17 00:00:00 2001 From: Anton Dubovik Date: Thu, 4 Dec 2025 17:39:55 +0000 Subject: [PATCH 1/8] chore: fix integration tests --- .markdownlint.json | 4 ++ README.md | 66 +++++++++++-------- tests/integration/configuration.py | 5 ++ tests/integration/fixtures.py | 2 +- tests/integration/test_async_completions.py | 3 +- tests/integration/test_sync_completions.py | 5 +- .../test_completions_streaming_tool_call.py | 5 +- .../test_completions_streaming_vanilla.py | 5 +- tests/utils/chunks.py | 4 +- 9 files changed, 64 insertions(+), 35 deletions(-) create mode 100644 .markdownlint.json create mode 100644 tests/integration/configuration.py diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 0000000..cb84254 --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,4 @@ +{ + "MD013": false, + "MD033": false +} \ No newline at end of file diff --git a/README.md b/README.md index 4857823..0ebeecc 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,40 @@ -# AI DIAL Client (Python) +

+ DIAL Client SDK +

+

+

+ + About DIALX + +

+

+ + Discord + +

+ +- [AI DIAL Client (Python)](#ai-dial-client-python) + - [Authentication](#authentication) + - [API Keys](#api-keys) + - [Bearer Token](#bearer-token) + - [List Deployments](#list-deployments) + - [Make Completions Requests](#make-completions-requests) + - [Without Streaming](#without-streaming) + - [With Streaming](#with-streaming) + - [Working with Files](#working-with-files) + - [Working with URLs](#working-with-urls) + - [Uploading Files](#uploading-files) + - [Downloading Files](#downloading-files) + - [Deleting Files](#deleting-files) + - [Accessing Metadata](#accessing-metadata) + - [Applications](#applications) + - [List Applications](#list-applications) + - [Get Application by Id](#get-application-by-id) + - [Client Pool](#client-pool) + - [Synchronous Client Pool](#synchronous-client-pool) + - [Asynchronous Client Pool](#asynchronous-client-pool) -## Table of Contents - -- [Authentication](#authentication) - - [API Keys](#api-keys) - - [Bearer Token](#bearer-token) -- [List Deployments](#list-deployments) -- [Make Chat Completions Requests](#make-completions-requests) - - [Without Streaming](#without-streaming) - - [With Streaming](#with-streaming) -- [Working with Files](#working-with-files) - - [Working with URLs](#working-with-urls) - - [Uploading Files](#uploading-files) - - [Downloading Files](#downloading-files) - - [Deleting Files](#deleting-files) - - [Accessing Metadata](#accessing-metadata) -- [Applications](#applications) - - [List Applications](#list-applications) - - [Get Application by Id](#get-application-by-id) -- [Client Pool](#client-pool) - - [Synchronous Client Pool](#synchronous-client-pool) - - [Asynchronous Client Pool](#asynchronous-client-pool) +# AI DIAL Client (Python) ## Authentication @@ -139,7 +153,7 @@ Synchronous: client = Dial(api_key="your-api-key", base_url="https://your-dial-instance.com") completion = client.chat.completions.create( - deployment_name="gpt-35-turbo", + deployment_name="gpt-4o", stream=False, messages=[ { @@ -159,7 +173,7 @@ async_client = AsyncDial( api_key="your-api-key", base_url="https://your-dial-instance.com" ) completion = await async_client.chat.completions.create( - deployment_name="gpt-35-turbo", + deployment_name="gpt-4o", stream=False, messages=[ { @@ -212,7 +226,7 @@ Synchronous: client = Dial(api_key="your-api-key", base_url="https://your-dial-instance.com") completion = client.chat.completions.create( - deployment_name="gpt-35-turbo", + deployment_name="gpt-4o", # Specify a stream parameter stream=True, messages=[ @@ -235,7 +249,7 @@ async_client = AsyncDial( api_key="your-api-key", base_url="https://your-dial-instance.com" ) completion = await async_client.chat.completions.create( - deployment_name="gpt-35-turbo", + deployment_name="gpt-4o", # Specify a stream parameter stream=True, messages=[ diff --git a/tests/integration/configuration.py b/tests/integration/configuration.py new file mode 100644 index 0000000..d9b333c --- /dev/null +++ b/tests/integration/configuration.py @@ -0,0 +1,5 @@ +import os + +INTEGRATION_TEST_DEPLOYMENT_NAME = os.getenv( + "INTEGRATION_TEST_DEPLOYMENT_NAME", "gpt-4o" +) diff --git a/tests/integration/fixtures.py b/tests/integration/fixtures.py index 7927dd6..1b772ef 100644 --- a/tests/integration/fixtures.py +++ b/tests/integration/fixtures.py @@ -35,7 +35,7 @@ def async_client(dial_url, dial_api_key): def test_deployment(sync_client: Dial) -> str: deployments = sync_client.deployments.list() assert len(deployments) - deployment = next((d for d in deployments if d.id.startswith("gpt-"))) + deployment = next((d for d in deployments if d.id.startswith("gpt-4o"))) assert deployment return deployment.id diff --git a/tests/integration/test_async_completions.py b/tests/integration/test_async_completions.py index 6246877..d9e1c90 100644 --- a/tests/integration/test_async_completions.py +++ b/tests/integration/test_async_completions.py @@ -2,6 +2,7 @@ from aidial_client import AsyncDial from aidial_client._exception import DialException +from tests.integration.configuration import INTEGRATION_TEST_DEPLOYMENT_NAME from tests.integration.fixtures import * # noqa @@ -14,7 +15,7 @@ async def test_async_default_api_version( ): with pytest.raises(DialException): await async_client.chat.completions.create( - deployment_name="gpt-35-turbo", + deployment_name=INTEGRATION_TEST_DEPLOYMENT_NAME, stream=False, messages=[ { diff --git a/tests/integration/test_sync_completions.py b/tests/integration/test_sync_completions.py index a35b61c..7a95061 100644 --- a/tests/integration/test_sync_completions.py +++ b/tests/integration/test_sync_completions.py @@ -2,6 +2,7 @@ from aidial_client import Dial from aidial_client._exception import DialException +from tests.integration.configuration import INTEGRATION_TEST_DEPLOYMENT_NAME from tests.integration.fixtures import * # type: ignore # noqa @@ -36,7 +37,7 @@ def test_default_api_version( ): with pytest.raises(DialException): sync_client.chat.completions.create( - deployment_name="gpt-35-turbo", + deployment_name=INTEGRATION_TEST_DEPLOYMENT_NAME, stream=False, messages=[ { @@ -51,7 +52,7 @@ def test_default_api_version( api_version="2024-02-15-preview", ) client_with_default_api_version.chat.completions.create( - deployment_name="gpt-35-turbo", + deployment_name=INTEGRATION_TEST_DEPLOYMENT_NAME, stream=False, messages=[ { diff --git a/tests/resources/completions/test_completions_streaming_tool_call.py b/tests/resources/completions/test_completions_streaming_tool_call.py index a5b6cfb..21f77d6 100644 --- a/tests/resources/completions/test_completions_streaming_tool_call.py +++ b/tests/resources/completions/test_completions_streaming_tool_call.py @@ -5,6 +5,7 @@ from aidial_client.types.chat import ChatCompletionChunk, ToolParam from tests.client_mock import get_async_client_mock, get_client_mock +from tests.integration.configuration import INTEGRATION_TEST_DEPLOYMENT_NAME from tests.utils.chunks import create_mock_chunk, create_sse_data_field _TOOL_DEFINITION: ToolParam = { @@ -172,7 +173,7 @@ def test_sync_streaming_tool_call(): ) response = client.chat.completions.create( - deployment_name="gpt-35-turbo", + deployment_name=INTEGRATION_TEST_DEPLOYMENT_NAME, messages=[{"role": "user", "content": "what's the weather in Paris?"}], tools=[_TOOL_DEFINITION], stream=True, @@ -190,7 +191,7 @@ async def test_async_streaming_tool_call(): stream_chunks_mock=_STREAM_CHUNKS_MOCK, ) response = await async_client.chat.completions.create( - deployment_name="gpt-35-turbo", + deployment_name=INTEGRATION_TEST_DEPLOYMENT_NAME, messages=[{"role": "user", "content": "what's the weather in Paris?"}], tools=[_TOOL_DEFINITION], stream=True, diff --git a/tests/resources/completions/test_completions_streaming_vanilla.py b/tests/resources/completions/test_completions_streaming_vanilla.py index dcb8492..341b862 100644 --- a/tests/resources/completions/test_completions_streaming_vanilla.py +++ b/tests/resources/completions/test_completions_streaming_vanilla.py @@ -5,6 +5,7 @@ from aidial_client.types.chat import ChatCompletionChunk from tests.client_mock import get_async_client_mock, get_client_mock +from tests.integration.configuration import INTEGRATION_TEST_DEPLOYMENT_NAME from tests.utils.chunks import create_mock_chunk, create_sse_data_field STREAM_CHUNKS_MOCK: List[bytes] = [ @@ -53,7 +54,7 @@ def test_sync_streaming(): ) response = client.chat.completions.create( - deployment_name="gpt-35-turbo", + deployment_name=INTEGRATION_TEST_DEPLOYMENT_NAME, messages=[{"role": "user", "content": "2+3="}], stream=True, ) @@ -70,7 +71,7 @@ async def test_async_streaming(): stream_chunks_mock=STREAM_CHUNKS_MOCK, ) response = await async_client.chat.completions.create( - deployment_name="gpt-35-turbo", + deployment_name=INTEGRATION_TEST_DEPLOYMENT_NAME, messages=[{"role": "user", "content": "2+3="}], stream=True, ) diff --git a/tests/utils/chunks.py b/tests/utils/chunks.py index eee4ca9..29d9d0f 100644 --- a/tests/utils/chunks.py +++ b/tests/utils/chunks.py @@ -1,6 +1,8 @@ import json from typing import Optional, Union +from tests.integration.configuration import INTEGRATION_TEST_DEPLOYMENT_NAME + def create_mock_chunk( *, @@ -19,7 +21,7 @@ def create_mock_chunk( } ], "created": 1723806872, - "model": "gpt-35-turbo", + "model": INTEGRATION_TEST_DEPLOYMENT_NAME, "object": "chat.completion.chunk", "system_fingerprint": None, **({} if usage is None else {"usage": usage}), From 6b25d9f3008dae99c255b1bc2207c9ce7c4b1348 Mon Sep 17 00:00:00 2001 From: Anton Dubovik Date: Fri, 24 Jul 2026 17:23:41 +0100 Subject: [PATCH 2/8] feat: moving things around --- .env.template | 5 +++++ tests/integration/configuration.py | 4 +--- tests/integration/test_async_completions.py | 4 ++-- tests/integration/test_sync_completions.py | 6 +++--- .../completions/test_completions_streaming_tool_call.py | 6 +++--- .../completions/test_completions_streaming_vanilla.py | 6 +++--- tests/utils/chunks.py | 4 ++-- 7 files changed, 19 insertions(+), 16 deletions(-) diff --git a/.env.template b/.env.template index ab27178..41d7fb3 100644 --- a/.env.template +++ b/.env.template @@ -1,2 +1,7 @@ POETRY=poetry POETRY_PYTHON=python + +# For integration tests +DIAL_URL=dial-url +DIAL_API_KEY=dial-api-key +DIAL_MODEL=gpt-5.2 diff --git a/tests/integration/configuration.py b/tests/integration/configuration.py index d9b333c..61e2052 100644 --- a/tests/integration/configuration.py +++ b/tests/integration/configuration.py @@ -1,5 +1,3 @@ import os -INTEGRATION_TEST_DEPLOYMENT_NAME = os.getenv( - "INTEGRATION_TEST_DEPLOYMENT_NAME", "gpt-4o" -) +DIAL_MODEL = os.getenv("DIAL_MODEL", "gpt-4o") diff --git a/tests/integration/test_async_completions.py b/tests/integration/test_async_completions.py index cae1bd7..d840039 100644 --- a/tests/integration/test_async_completions.py +++ b/tests/integration/test_async_completions.py @@ -2,7 +2,7 @@ from aidial_client import AsyncDial from aidial_client._exception import DialException -from tests.integration.configuration import INTEGRATION_TEST_DEPLOYMENT_NAME +from tests.integration.configuration import DIAL_MODEL from tests.integration.fixtures import * # noqa @@ -15,7 +15,7 @@ async def test_async_default_api_version( ): with pytest.raises(DialException): await async_client.chat.completions.create( - deployment_name=INTEGRATION_TEST_DEPLOYMENT_NAME, + deployment_name=DIAL_MODEL, stream=False, messages=[ { diff --git a/tests/integration/test_sync_completions.py b/tests/integration/test_sync_completions.py index 3aa4c88..1309d44 100644 --- a/tests/integration/test_sync_completions.py +++ b/tests/integration/test_sync_completions.py @@ -2,7 +2,7 @@ from aidial_client import Dial from aidial_client._exception import DialException -from tests.integration.configuration import INTEGRATION_TEST_DEPLOYMENT_NAME +from tests.integration.configuration import DIAL_MODEL from tests.integration.fixtures import * # type: ignore # noqa @@ -37,7 +37,7 @@ def test_default_api_version( ): with pytest.raises(DialException): sync_client.chat.completions.create( - deployment_name=INTEGRATION_TEST_DEPLOYMENT_NAME, + deployment_name=DIAL_MODEL, stream=False, messages=[ { @@ -52,7 +52,7 @@ def test_default_api_version( api_version="2024-02-15-preview", ) client_with_default_api_version.chat.completions.create( - deployment_name=INTEGRATION_TEST_DEPLOYMENT_NAME, + deployment_name=DIAL_MODEL, stream=False, messages=[ { diff --git a/tests/resources/completions/test_completions_streaming_tool_call.py b/tests/resources/completions/test_completions_streaming_tool_call.py index f871360..3bf27ce 100644 --- a/tests/resources/completions/test_completions_streaming_tool_call.py +++ b/tests/resources/completions/test_completions_streaming_tool_call.py @@ -5,7 +5,7 @@ from aidial_client.types.chat import ChatCompletionChunk, ToolParam from tests.client_mock import get_async_client_mock, get_client_mock -from tests.integration.configuration import INTEGRATION_TEST_DEPLOYMENT_NAME +from tests.integration.configuration import DIAL_MODEL from tests.utils.chunks import create_mock_chunk, create_sse_data_field _TOOL_DEFINITION: ToolParam = { @@ -174,7 +174,7 @@ def test_sync_streaming_tool_call(): ) response = client.chat.completions.create( - deployment_name=INTEGRATION_TEST_DEPLOYMENT_NAME, + deployment_name=DIAL_MODEL, messages=[{"role": "user", "content": "what's the weather in Paris?"}], tools=[_TOOL_DEFINITION], stream=True, @@ -192,7 +192,7 @@ async def test_async_streaming_tool_call(): stream_chunks_mock=_STREAM_CHUNKS_MOCK, ) response = await async_client.chat.completions.create( - deployment_name=INTEGRATION_TEST_DEPLOYMENT_NAME, + deployment_name=DIAL_MODEL, messages=[{"role": "user", "content": "what's the weather in Paris?"}], tools=[_TOOL_DEFINITION], stream=True, diff --git a/tests/resources/completions/test_completions_streaming_vanilla.py b/tests/resources/completions/test_completions_streaming_vanilla.py index 79ce13b..9499660 100644 --- a/tests/resources/completions/test_completions_streaming_vanilla.py +++ b/tests/resources/completions/test_completions_streaming_vanilla.py @@ -5,7 +5,7 @@ from aidial_client.types.chat import ChatCompletionChunk from tests.client_mock import get_async_client_mock, get_client_mock -from tests.integration.configuration import INTEGRATION_TEST_DEPLOYMENT_NAME +from tests.integration.configuration import DIAL_MODEL from tests.utils.chunks import create_mock_chunk, create_sse_data_field STREAM_CHUNKS_MOCK: list[bytes] = [ @@ -54,7 +54,7 @@ def test_sync_streaming(): ) response = client.chat.completions.create( - deployment_name=INTEGRATION_TEST_DEPLOYMENT_NAME, + deployment_name=DIAL_MODEL, messages=[{"role": "user", "content": "2+3="}], stream=True, ) @@ -71,7 +71,7 @@ async def test_async_streaming(): stream_chunks_mock=STREAM_CHUNKS_MOCK, ) response = await async_client.chat.completions.create( - deployment_name=INTEGRATION_TEST_DEPLOYMENT_NAME, + deployment_name=DIAL_MODEL, messages=[{"role": "user", "content": "2+3="}], stream=True, ) diff --git a/tests/utils/chunks.py b/tests/utils/chunks.py index 95ef6ca..cb82c6d 100644 --- a/tests/utils/chunks.py +++ b/tests/utils/chunks.py @@ -1,6 +1,6 @@ import json -from tests.integration.configuration import INTEGRATION_TEST_DEPLOYMENT_NAME +from tests.integration.configuration import DIAL_MODEL def create_mock_chunk( @@ -20,7 +20,7 @@ def create_mock_chunk( } ], "created": 1723806872, - "model": INTEGRATION_TEST_DEPLOYMENT_NAME, + "model": DIAL_MODEL, "object": "chat.completion.chunk", "system_fingerprint": None, **({} if usage is None else {"usage": usage}), From 96c51c4248d9f7d95c098abea6f03d2e3f3f1d61 Mon Sep 17 00:00:00 2001 From: Anton Dubovik Date: Fri, 24 Jul 2026 17:31:34 +0100 Subject: [PATCH 3/8] test: move integration DIAL_* fixtures into conftest Fold fixtures.py into an auto-discovered conftest.py and replace the DIAL_MODEL constant (configuration.py) with a required dial_model fixture. Add assert messages to the DIAL_* env fixtures. Co-Authored-By: Claude Opus 4.8 --- tests/integration/configuration.py | 3 --- tests/integration/{fixtures.py => conftest.py} | 11 +++++++++-- tests/integration/test_async_completions.py | 5 ++--- tests/integration/test_async_files.py | 1 - tests/integration/test_async_prompts.py | 1 - tests/integration/test_sync_completions.py | 8 +++----- tests/integration/test_sync_files.py | 1 - tests/integration/test_sync_prompts.py | 1 - 8 files changed, 14 insertions(+), 17 deletions(-) delete mode 100644 tests/integration/configuration.py rename tests/integration/{fixtures.py => conftest.py} (81%) diff --git a/tests/integration/configuration.py b/tests/integration/configuration.py deleted file mode 100644 index 61e2052..0000000 --- a/tests/integration/configuration.py +++ /dev/null @@ -1,3 +0,0 @@ -import os - -DIAL_MODEL = os.getenv("DIAL_MODEL", "gpt-4o") diff --git a/tests/integration/fixtures.py b/tests/integration/conftest.py similarity index 81% rename from tests/integration/fixtures.py rename to tests/integration/conftest.py index edaf49a..02728bd 100644 --- a/tests/integration/fixtures.py +++ b/tests/integration/conftest.py @@ -11,17 +11,24 @@ @pytest.fixture def dial_url() -> str: url = os.getenv("DIAL_URL") - assert url + assert url, "DIAL_URL environment variable is not set" return url @pytest.fixture def dial_api_key() -> str: api_key = os.getenv("DIAL_API_KEY") - assert api_key + assert api_key, "DIAL_API_KEY environment variable is not set" return api_key +@pytest.fixture +def dial_model() -> str: + model = os.getenv("DIAL_MODEL") + assert model, "DIAL_MODEL environment variable is not set" + return model + + @pytest.fixture def sync_client(dial_url, dial_api_key): return Dial(base_url=dial_url, api_key=dial_api_key) diff --git a/tests/integration/test_async_completions.py b/tests/integration/test_async_completions.py index d840039..33bda2a 100644 --- a/tests/integration/test_async_completions.py +++ b/tests/integration/test_async_completions.py @@ -2,8 +2,6 @@ from aidial_client import AsyncDial from aidial_client._exception import DialException -from tests.integration.configuration import DIAL_MODEL -from tests.integration.fixtures import * # noqa @pytest.mark.asyncio @@ -11,11 +9,12 @@ async def test_async_default_api_version( async_client: AsyncDial, dial_url: str, dial_api_key: str, + dial_model: str, test_deployment: str, ): with pytest.raises(DialException): await async_client.chat.completions.create( - deployment_name=DIAL_MODEL, + deployment_name=dial_model, stream=False, messages=[ { diff --git a/tests/integration/test_async_files.py b/tests/integration/test_async_files.py index 1b5f3b1..4415ca8 100644 --- a/tests/integration/test_async_files.py +++ b/tests/integration/test_async_files.py @@ -5,7 +5,6 @@ from aidial_client import AsyncDial, DialException from aidial_client._exception import EtagMismatchError from aidial_client.types.metadata import FileItem -from tests.integration.fixtures import * # type: ignore # noqa current_file_path = os.path.abspath(__file__) file_name = "test-file-async" diff --git a/tests/integration/test_async_prompts.py b/tests/integration/test_async_prompts.py index 1ede0ec..a8b01b4 100644 --- a/tests/integration/test_async_prompts.py +++ b/tests/integration/test_async_prompts.py @@ -7,7 +7,6 @@ from aidial_client._exception import EtagMismatchError, ResourceNotFoundError from aidial_client.types.metadata import PromptItem from aidial_client.types.prompt import Prompt -from tests.integration.fixtures import * # type: ignore # noqa PROMPT_FOLDER = "test-folder-artifacts" diff --git a/tests/integration/test_sync_completions.py b/tests/integration/test_sync_completions.py index 1309d44..10efaf6 100644 --- a/tests/integration/test_sync_completions.py +++ b/tests/integration/test_sync_completions.py @@ -2,8 +2,6 @@ from aidial_client import Dial from aidial_client._exception import DialException -from tests.integration.configuration import DIAL_MODEL -from tests.integration.fixtures import * # type: ignore # noqa def test_completions_without_streaming(sync_client: Dial, test_deployment: str): @@ -33,11 +31,11 @@ def test_completions_without_streaming(sync_client: Dial, test_deployment: str): def test_default_api_version( - sync_client: Dial, dial_url: str, dial_api_key: str + sync_client: Dial, dial_url: str, dial_api_key: str, dial_model: str ): with pytest.raises(DialException): sync_client.chat.completions.create( - deployment_name=DIAL_MODEL, + deployment_name=dial_model, stream=False, messages=[ { @@ -52,7 +50,7 @@ def test_default_api_version( api_version="2024-02-15-preview", ) client_with_default_api_version.chat.completions.create( - deployment_name=DIAL_MODEL, + deployment_name=dial_model, stream=False, messages=[ { diff --git a/tests/integration/test_sync_files.py b/tests/integration/test_sync_files.py index 03b0177..9b0357b 100644 --- a/tests/integration/test_sync_files.py +++ b/tests/integration/test_sync_files.py @@ -5,7 +5,6 @@ from aidial_client import Dial, DialException from aidial_client._exception import EtagMismatchError from aidial_client.types.metadata import FileItem -from tests.integration.fixtures import * # type: ignore # noqa current_file_path = os.path.abspath(__file__) file_name = "test-file" diff --git a/tests/integration/test_sync_prompts.py b/tests/integration/test_sync_prompts.py index 55a17bd..eadb546 100644 --- a/tests/integration/test_sync_prompts.py +++ b/tests/integration/test_sync_prompts.py @@ -7,7 +7,6 @@ from aidial_client._exception import EtagMismatchError, ResourceNotFoundError from aidial_client.types.metadata import PromptItem from aidial_client.types.prompt import Prompt -from tests.integration.fixtures import * # type: ignore # noqa PROMPT_FOLDER = "test-folder-artifacts" From 1e150c56c54c2833d1689c526543ad2f63b5c74d Mon Sep 17 00:00:00 2001 From: Anton Dubovik Date: Fri, 24 Jul 2026 17:36:37 +0100 Subject: [PATCH 4/8] feat: use DIAL_MODEL everywhere in integration tests --- tests/integration/conftest.py | 9 --------- tests/integration/test_async_completions.py | 21 +++++++++------------ tests/integration/test_sync_completions.py | 12 ++++-------- 3 files changed, 13 insertions(+), 29 deletions(-) diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index 02728bd..757c288 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -39,15 +39,6 @@ def async_client(dial_url, dial_api_key): return AsyncDial(base_url=dial_url, api_key=dial_api_key) -@pytest.fixture -def test_deployment(sync_client: Dial) -> str: - deployments = sync_client.deployments.list() - assert len(deployments) - deployment = next(d for d in deployments if d.id.startswith("gpt-4o")) - assert deployment - return deployment.id - - @pytest.fixture def absent_test_file(sync_client): def _save_delete_file(p): diff --git a/tests/integration/test_async_completions.py b/tests/integration/test_async_completions.py index 33bda2a..a62a3f0 100644 --- a/tests/integration/test_async_completions.py +++ b/tests/integration/test_async_completions.py @@ -10,7 +10,6 @@ async def test_async_default_api_version( dial_url: str, dial_api_key: str, dial_model: str, - test_deployment: str, ): with pytest.raises(DialException): await async_client.chat.completions.create( @@ -29,7 +28,7 @@ async def test_async_default_api_version( api_version="2024-02-15-preview", ) await client_with_default_api_version.chat.completions.create( - deployment_name=test_deployment, + deployment_name=dial_model, stream=False, messages=[ { @@ -42,10 +41,10 @@ async def test_async_default_api_version( @pytest.mark.asyncio async def test_completions_without_streaming( - async_client: AsyncDial, test_deployment: str + async_client: AsyncDial, dial_model: str ): completion = await async_client.chat.completions.create( - deployment_name=test_deployment, + deployment_name=dial_model, stream=False, messages=[ { @@ -70,13 +69,11 @@ async def test_completions_without_streaming( @pytest.mark.asyncio -async def test_completions_with_streaming(async_client: AsyncDial): - deployments = await async_client.deployments.list() - assert len(deployments) - deployment = next(d for d in deployments if d.id.startswith("gpt-")) - assert deployment +async def test_completions_with_streaming( + async_client: AsyncDial, dial_model: str +): completion = await async_client.chat.completions.create( - deployment_name=deployment.id, + deployment_name=dial_model, stream=True, messages=[ { @@ -109,10 +106,10 @@ async def test_completions_with_streaming(async_client: AsyncDial): @pytest.mark.asyncio async def test_error_during_streaming( - async_client: AsyncDial, test_deployment: str + async_client: AsyncDial, dial_model: str ): completion = await async_client.chat.completions.create( - deployment_name=test_deployment, + deployment_name=dial_model, stream=True, messages=[ { diff --git a/tests/integration/test_sync_completions.py b/tests/integration/test_sync_completions.py index 10efaf6..bf24bfb 100644 --- a/tests/integration/test_sync_completions.py +++ b/tests/integration/test_sync_completions.py @@ -4,9 +4,9 @@ from aidial_client._exception import DialException -def test_completions_without_streaming(sync_client: Dial, test_deployment: str): +def test_completions_without_streaming(sync_client: Dial, dial_model: str): completion = sync_client.chat.completions.create( - deployment_name=test_deployment, + deployment_name=dial_model, stream=False, messages=[ { @@ -61,13 +61,9 @@ def test_default_api_version( ) -def test_completions_with_streaming(sync_client: Dial): - deployments = sync_client.deployments.list() - assert len(deployments) - deployment = next(d for d in deployments if d.id.startswith("gpt-")) - assert deployment +def test_completions_with_streaming(sync_client: Dial, dial_model: str): completion = sync_client.chat.completions.create( - deployment_name=deployment.id, + deployment_name=dial_model, stream=True, messages=[ { From 54edaf9df70f79b7f1f4a08805a9644fcd44bb4c Mon Sep 17 00:00:00 2001 From: Anton Dubovik Date: Fri, 24 Jul 2026 17:39:46 +0100 Subject: [PATCH 5/8] docs: fix markdownlint warnings in README Co-Authored-By: Claude Opus 4.8 --- README.md | 61 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 3bc2db7..ccefd30 100644 --- a/README.md +++ b/README.md @@ -15,41 +15,41 @@ - [Usage](#usage) - [Authentication](#authentication) - - [API Keys](#api-keys) - - [Bearer Token](#bearer-token) + - [API Keys](#api-keys) + - [Bearer Token](#bearer-token) - [Lifecycle Management](#lifecycle-management) - [Deployments](#deployments) - - [List Deployments](#list-deployments) - - [Get Deployment by Id](#get-deployment-by-id) - - [Get Deployment Configuration](#get-deployment-configuration) + - [List Deployments](#list-deployments) + - [Get Deployment by Id](#get-deployment-by-id) + - [Get Deployment Configuration](#get-deployment-configuration) - [Make Chat Completions Requests](#make-completions-requests) - - [Without Streaming](#without-streaming) - - [With Streaming](#with-streaming) + - [Without Streaming](#without-streaming) + - [With Streaming](#with-streaming) - [Working with Files](#working-with-files) - - [Working with URLs](#working-with-urls) - - [Uploading Files](#uploading-files) - - [Downloading Files](#downloading-files) - - [Deleting Files](#deleting-files) - - [Accessing Metadata](#accessing-metadata) + - [Working with URLs](#working-with-urls) + - [Uploading Files](#uploading-files) + - [Downloading Files](#downloading-files) + - [Deleting Files](#deleting-files) + - [Accessing Metadata](#accessing-metadata) - [Prompts](#prompts) - - [Get Prompt](#get-prompt) - - [Get Prompt Metadata](#get-prompt-metadata) + - [Get Prompt](#get-prompt) + - [Get Prompt Metadata](#get-prompt-metadata) - [Applications](#applications) - - [List Applications](#list-applications) - - [Get Application by Id](#get-application-by-id) + - [List Applications](#list-applications) + - [Get Application by Id](#get-application-by-id) - [Models](#models) - - [Get Model by Name](#get-model-by-name) + - [Get Model by Name](#get-model-by-name) - [User](#user) - - [Get Authenticated User Info](#get-authenticated-user-info) + - [Get Authenticated User Info](#get-authenticated-user-info) - [Toolsets](#toolsets) - - [Get Toolset by Id](#get-toolset-by-id) + - [Get Toolset by Id](#get-toolset-by-id) - [Resource Permissions](#resource-permissions) - - [Grant Permissions](#grant-permissions) + - [Grant Permissions](#grant-permissions) - [Client Channel](#client-channel) - - [Sign In to Toolsets](#sign-in-to-toolsets) + - [Sign In to Toolsets](#sign-in-to-toolsets) - [Client Pool](#client-pool) - - [Synchronous Client Pool](#synchronous-client-pool) - - [Asynchronous Client Pool](#asynchronous-client-pool) + - [Synchronous Client Pool](#synchronous-client-pool) + - [Asynchronous Client Pool](#asynchronous-client-pool) - [Development](#development) - [Pre-requisites](#pre-requisites) - [Setup](#setup) @@ -58,8 +58,8 @@ ## Usage -This section outlines how to use the AI DIAL Python client to interact with the DIAL Core API. -It covers authentication methods, making chat completion requests, working with files, managing applications, +This section outlines how to use the AI DIAL Python client to interact with the DIAL Core API. +It covers authentication methods, making chat completion requests, working with files, managing applications, and utilizing client pools for efficient connection management. ### Authentication @@ -466,8 +466,8 @@ ChatCompletionChunk( Files are AI DIAL resources that operate with URL-like objects. Use `pathlib.PurePosixPath` or `str` to create to create new URL-like objects or to get a `string` representation of them. -* Use `client.my_files_home()` to upload a file into your bucket in the AI DIAL storage. -* Use `await async_client.my_files_home()` to get the URL of your bucket and then use it to upload files. +- Use `client.my_files_home()` to upload a file into your bucket in the AI DIAL storage. +- Use `await async_client.my_files_home()` to get the URL of your bucket and then use it to upload files. The following example demonstrates how you can use the path-like object returned by `my_files_home()` function: @@ -602,7 +602,6 @@ await result.awrite_to("./some-local-file.txt") Use `delete()` to remove files from your storage bucket: - ```python await sync_client.files.delete( url=sync_client.my_files_home() / "relative_folder/my-file.txt" @@ -1095,7 +1094,6 @@ second_client = client_pool.create_client( ) ``` - ## Development To set up the development environment and run the project, follow the instructions below. @@ -1106,18 +1104,21 @@ The following tools are required to work with the project: 1. `Make` 2. `Python 3.10` -3. `Poetry 2.*`. Installation guidance can be found [here](https://python-poetry.org/docs/#installation) +3. `Poetry 2.*`. See the [Poetry installation guide](https://python-poetry.org/docs/#installation) ### Setup 1. Create `.env` file in the root of the project. Copy `.env.template` file data to the `.env` and customize the values if needed. You can customize python and poetry locations. 2. Create and activate virtual environment + ```bash make init_env source .venv/bin/activate ``` + 3. Install dependencies + ```bash make install ``` From 1952f260104df2c022a64d11b6f4837544411040 Mon Sep 17 00:00:00 2001 From: Anton Dubovik Date: Mon, 27 Jul 2026 10:11:26 +0100 Subject: [PATCH 6/8] chore: fix build --- .vscode/settings.json | 2 ++ tests/integration/test_async_completions.py | 4 +--- .../test_completions_streaming_tool_call.py | 10 ++++------ .../test_completions_streaming_vanilla.py | 18 +++++++----------- tests/utils/chunks.py | 4 +--- 5 files changed, 15 insertions(+), 23 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 672ecfd..dbd3805 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -23,4 +23,6 @@ "files.insertFinalNewline": true, "files.trimFinalNewlines": true, "files.trimTrailingWhitespace": true, + "python-envs.defaultEnvManager": "ms-python.python:poetry", + "python-envs.defaultPackageManager": "ms-python.python:poetry", } diff --git a/tests/integration/test_async_completions.py b/tests/integration/test_async_completions.py index a62a3f0..4052f6f 100644 --- a/tests/integration/test_async_completions.py +++ b/tests/integration/test_async_completions.py @@ -105,9 +105,7 @@ async def test_completions_with_streaming( @pytest.mark.asyncio -async def test_error_during_streaming( - async_client: AsyncDial, dial_model: str -): +async def test_error_during_streaming(async_client: AsyncDial, dial_model: str): completion = await async_client.chat.completions.create( deployment_name=dial_model, stream=True, diff --git a/tests/resources/completions/test_completions_streaming_tool_call.py b/tests/resources/completions/test_completions_streaming_tool_call.py index 3bf27ce..6808448 100644 --- a/tests/resources/completions/test_completions_streaming_tool_call.py +++ b/tests/resources/completions/test_completions_streaming_tool_call.py @@ -1,13 +1,13 @@ -import inspect from collections.abc import Iterable import pytest from aidial_client.types.chat import ChatCompletionChunk, ToolParam from tests.client_mock import get_async_client_mock, get_client_mock -from tests.integration.configuration import DIAL_MODEL from tests.utils.chunks import create_mock_chunk, create_sse_data_field +_DIAL_MODEL = "gpt-4o" + _TOOL_DEFINITION: ToolParam = { "type": "function", "function": { @@ -174,7 +174,7 @@ def test_sync_streaming_tool_call(): ) response = client.chat.completions.create( - deployment_name=DIAL_MODEL, + deployment_name=_DIAL_MODEL, messages=[{"role": "user", "content": "what's the weather in Paris?"}], tools=[_TOOL_DEFINITION], stream=True, @@ -192,14 +192,12 @@ async def test_async_streaming_tool_call(): stream_chunks_mock=_STREAM_CHUNKS_MOCK, ) response = await async_client.chat.completions.create( - deployment_name=DIAL_MODEL, + deployment_name=_DIAL_MODEL, messages=[{"role": "user", "content": "what's the weather in Paris?"}], tools=[_TOOL_DEFINITION], stream=True, ) - assert inspect.isasyncgen(response) chunks = [chunk async for chunk in response] assert all(isinstance(chunk, ChatCompletionChunk) for chunk in chunks) _validate_chunks(chunks) - _validate_chunks(chunks) diff --git a/tests/resources/completions/test_completions_streaming_vanilla.py b/tests/resources/completions/test_completions_streaming_vanilla.py index 9499660..2a0d7ec 100644 --- a/tests/resources/completions/test_completions_streaming_vanilla.py +++ b/tests/resources/completions/test_completions_streaming_vanilla.py @@ -1,14 +1,12 @@ -import inspect -from collections.abc import Iterable - import pytest from aidial_client.types.chat import ChatCompletionChunk from tests.client_mock import get_async_client_mock, get_client_mock -from tests.integration.configuration import DIAL_MODEL from tests.utils.chunks import create_mock_chunk, create_sse_data_field -STREAM_CHUNKS_MOCK: list[bytes] = [ +_DIAL_MODEL = "gpt-4o" + +_STREAM_CHUNKS_MOCK: list[bytes] = [ create_sse_data_field( create_mock_chunk(delta={"content": "", "role": "assistant"}) ) @@ -50,15 +48,14 @@ def _validate_chunks(chunks: list[ChatCompletionChunk]): def test_sync_streaming(): client = get_client_mock( status_code=200, - stream_chunks_mock=STREAM_CHUNKS_MOCK, + stream_chunks_mock=_STREAM_CHUNKS_MOCK, ) response = client.chat.completions.create( - deployment_name=DIAL_MODEL, + deployment_name=_DIAL_MODEL, messages=[{"role": "user", "content": "2+3="}], stream=True, ) - assert isinstance(response, Iterable) chunks = list(response) assert all(isinstance(chunk, ChatCompletionChunk) for chunk in chunks) _validate_chunks(chunks) @@ -68,15 +65,14 @@ def test_sync_streaming(): async def test_async_streaming(): async_client = get_async_client_mock( status_code=200, - stream_chunks_mock=STREAM_CHUNKS_MOCK, + stream_chunks_mock=_STREAM_CHUNKS_MOCK, ) response = await async_client.chat.completions.create( - deployment_name=DIAL_MODEL, + deployment_name=_DIAL_MODEL, messages=[{"role": "user", "content": "2+3="}], stream=True, ) - assert inspect.isasyncgen(response) chunks = [chunk async for chunk in response] assert all(isinstance(chunk, ChatCompletionChunk) for chunk in chunks) _validate_chunks(chunks) diff --git a/tests/utils/chunks.py b/tests/utils/chunks.py index cb82c6d..fcb92d3 100644 --- a/tests/utils/chunks.py +++ b/tests/utils/chunks.py @@ -1,7 +1,5 @@ import json -from tests.integration.configuration import DIAL_MODEL - def create_mock_chunk( *, @@ -20,7 +18,7 @@ def create_mock_chunk( } ], "created": 1723806872, - "model": DIAL_MODEL, + "model": "gpt-4o", "object": "chat.completion.chunk", "system_fingerprint": None, **({} if usage is None else {"usage": usage}), From 2a4490736d5ec939bd4297d8886da28f02207e9c Mon Sep 17 00:00:00 2001 From: Anton Dubovik Date: Mon, 27 Jul 2026 10:19:59 +0100 Subject: [PATCH 7/8] feat: split bloated tests --- tests/integration/test_async_completions.py | 32 ++++++--------------- tests/integration/test_sync_completions.py | 9 ++++-- 2 files changed, 14 insertions(+), 27 deletions(-) diff --git a/tests/integration/test_async_completions.py b/tests/integration/test_async_completions.py index 4052f6f..4fc634a 100644 --- a/tests/integration/test_async_completions.py +++ b/tests/integration/test_async_completions.py @@ -5,11 +5,8 @@ @pytest.mark.asyncio -async def test_async_default_api_version( - async_client: AsyncDial, - dial_url: str, - dial_api_key: str, - dial_model: str, +async def test_async_missing_api_version_raises( + async_client: AsyncDial, dial_model: str ): with pytest.raises(DialException): await async_client.chat.completions.create( @@ -22,6 +19,12 @@ async def test_async_default_api_version( } ], ) + + +@pytest.mark.asyncio +async def test_async_client_default_api_version( + dial_url: str, dial_api_key: str, dial_model: str +): client_with_default_api_version = AsyncDial( base_url=dial_url, api_key=dial_api_key, @@ -102,22 +105,3 @@ async def test_completions_with_streaming( last_chunk.usage.completion_tokens + last_chunk.usage.prompt_tokens == last_chunk.usage.total_tokens ) - - -@pytest.mark.asyncio -async def test_error_during_streaming(async_client: AsyncDial, dial_model: str): - completion = await async_client.chat.completions.create( - deployment_name=dial_model, - stream=True, - messages=[ - { - "role": "system", - "content": "2+3=", - } - ], - max_tokens=20, - api_version="2024-02-15-preview", - ) - - async for chunk in completion: - print(chunk) diff --git a/tests/integration/test_sync_completions.py b/tests/integration/test_sync_completions.py index bf24bfb..b29f8c9 100644 --- a/tests/integration/test_sync_completions.py +++ b/tests/integration/test_sync_completions.py @@ -30,9 +30,7 @@ def test_completions_without_streaming(sync_client: Dial, dial_model: str): ) -def test_default_api_version( - sync_client: Dial, dial_url: str, dial_api_key: str, dial_model: str -): +def test_missing_api_version_raises(sync_client: Dial, dial_model: str): with pytest.raises(DialException): sync_client.chat.completions.create( deployment_name=dial_model, @@ -44,6 +42,11 @@ def test_default_api_version( } ], ) + + +def test_client_default_api_version( + dial_url: str, dial_api_key: str, dial_model: str +): client_with_default_api_version = Dial( base_url=dial_url, api_key=dial_api_key, From 1b8e867b96dd64f36de342f35711c826a6c7a8cd Mon Sep 17 00:00:00 2001 From: Anton Dubovik Date: Mon, 27 Jul 2026 10:24:09 +0100 Subject: [PATCH 8/8] chore: update README --- README.md | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ccefd30..73a432d 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ - [List Deployments](#list-deployments) - [Get Deployment by Id](#get-deployment-by-id) - [Get Deployment Configuration](#get-deployment-configuration) - - [Make Chat Completions Requests](#make-completions-requests) + - [Make Chat Completions Requests](#make-chat-completions-requests) - [Without Streaming](#without-streaming) - [With Streaming](#with-streaming) - [Working with Files](#working-with-files) @@ -30,10 +30,13 @@ - [Uploading Files](#uploading-files) - [Downloading Files](#downloading-files) - [Deleting Files](#deleting-files) + - [Moving and Copying Files](#moving-and-copying-files) - [Accessing Metadata](#accessing-metadata) - [Prompts](#prompts) + - [Save Prompt](#save-prompt) - [Get Prompt](#get-prompt) - [Get Prompt Metadata](#get-prompt-metadata) + - [Delete Prompt](#delete-prompt) - [Applications](#applications) - [List Applications](#list-applications) - [Get Application by Id](#get-application-by-id) @@ -53,8 +56,9 @@ - [Development](#development) - [Pre-requisites](#pre-requisites) - [Setup](#setup) - - [Main commands](#main-commands) - [Git hooks](#git-hooks) + - [Main commands](#main-commands) + - [Integration tests](#integration-tests) ## Usage @@ -284,7 +288,7 @@ The response is a plain `dict` whose shape is entirely deployment-specific: } ``` -### Make Completions Requests +### Make Chat Completions Requests #### Without Streaming @@ -1148,3 +1152,13 @@ make install_git_hooks | `make integration_test` | Run integration tests | | `make coverage` | Generate test coverage report | | `make help` | Show available commands | + +### Integration tests + +`make integration_test` runs against a real DIAL deployment and requires the following environment variables: + +| Variable | Description | +|----------------|----------------------------------------------------| +| `DIAL_URL` | Base URL of the DIAL Core service | +| `DIAL_API_KEY` | API key used to authenticate requests in DIAL Core | +| `DIAL_MODEL` | Name of a chat model deployment to run tests with |