aidial-client 0.11.0.dev1__tar.gz → 0.11.0.dev2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/PKG-INFO +1 -1
  2. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/_auth.py +23 -17
  3. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/_client.py +21 -25
  4. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/_client_pool.py +6 -8
  5. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/_exception.py +5 -5
  6. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/_http_client/_async.py +12 -23
  7. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/_http_client/_base.py +11 -14
  8. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/_http_client/_sse.py +9 -6
  9. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/_http_client/_sync.py +12 -14
  10. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/_internal_types/_generic.py +9 -11
  11. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/_internal_types/_http_request.py +24 -28
  12. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/_internal_types/_json_rpc.py +14 -12
  13. aidial_client-0.11.0.dev2/aidial_client/_utils/_dict.py +5 -0
  14. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/_utils/_openai.py +1 -1
  15. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/_utils/_response_processing.py +6 -6
  16. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/_utils/_type_guard.py +2 -3
  17. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/helpers/storage_resource.py +6 -6
  18. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/resources/application.py +2 -3
  19. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/resources/bucket.py +2 -3
  20. aidial_client-0.11.0.dev2/aidial_client/resources/chat/completions.py +374 -0
  21. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/resources/client_channel.py +13 -13
  22. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/resources/deployments.py +5 -5
  23. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/resources/files.py +26 -29
  24. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/resources/metadata.py +4 -6
  25. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/resources/prompts.py +17 -19
  26. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/resources/resource_permissions.py +8 -6
  27. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/types/application.py +5 -5
  28. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/types/bucket.py +1 -2
  29. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/types/chat/addon.py +1 -3
  30. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/types/chat/function.py +2 -4
  31. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/types/chat/legacy/application_request.py +5 -5
  32. aidial_client-0.11.0.dev2/aidial_client/types/chat/legacy/chat_completion.py +167 -0
  33. aidial_client-0.11.0.dev2/aidial_client/types/chat/request.py +42 -0
  34. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/types/chat/request_param.py +19 -19
  35. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/types/chat/response.py +31 -31
  36. aidial_client-0.11.0.dev2/aidial_client/types/deployment.py +56 -0
  37. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/types/file.py +3 -6
  38. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/types/metadata.py +15 -15
  39. aidial_client-0.11.0.dev2/aidial_client/types/model.py +46 -0
  40. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/types/prompt.py +1 -3
  41. aidial_client-0.11.0.dev2/aidial_client/types/toolset.py +22 -0
  42. aidial_client-0.11.0.dev2/pyproject.toml +93 -0
  43. aidial_client-0.11.0.dev1/aidial_client/_utils/_dict.py +0 -5
  44. aidial_client-0.11.0.dev1/aidial_client/resources/chat/completions.py +0 -398
  45. aidial_client-0.11.0.dev1/aidial_client/types/chat/legacy/chat_completion.py +0 -168
  46. aidial_client-0.11.0.dev1/aidial_client/types/chat/request.py +0 -44
  47. aidial_client-0.11.0.dev1/aidial_client/types/deployment.py +0 -56
  48. aidial_client-0.11.0.dev1/aidial_client/types/model.py +0 -48
  49. aidial_client-0.11.0.dev1/aidial_client/types/toolset.py +0 -24
  50. aidial_client-0.11.0.dev1/pyproject.toml +0 -97
  51. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/LICENSE +0 -0
  52. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/README.md +0 -0
  53. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/__init__.py +0 -0
  54. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/_compatibility/__init__.py +0 -0
  55. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/_compatibility/openai.py +0 -0
  56. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/_compatibility/pydantic.py +0 -0
  57. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/_compatibility/pydantic_v1.py +0 -0
  58. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/_constants.py +0 -0
  59. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/_http_client/__init__.py +0 -0
  60. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/_internal_types/__init__.py +0 -0
  61. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/_internal_types/_defaults.py +0 -0
  62. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/_internal_types/_model.py +0 -0
  63. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/_log.py +0 -0
  64. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/_utils/__init__.py +0 -0
  65. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/_utils/_alias.py +0 -0
  66. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/helpers/__init__.py +0 -0
  67. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/helpers/_url.py +0 -0
  68. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/py.typed +0 -0
  69. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/resources/__init__.py +0 -0
  70. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/resources/base.py +0 -0
  71. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/resources/chat/__init__.py +0 -0
  72. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/resources/model.py +0 -0
  73. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/resources/toolset.py +0 -0
  74. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/types/__init__.py +0 -0
  75. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/types/chat/__init__.py +0 -0
  76. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/types/chat/legacy/__init__.py +0 -0
  77. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/types/chat/tool.py +0 -0
  78. {aidial_client-0.11.0.dev1 → aidial_client-0.11.0.dev2}/aidial_client/types/client_channel.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aidial-client
3
- Version: 0.11.0.dev1
3
+ Version: 0.11.0.dev2
4
4
  Summary: A Python client library for the AI DIAL API
5
5
  License-Expression: Apache-2.0
6
6
  License-File: LICENSE
@@ -1,12 +1,13 @@
1
+ from collections.abc import Awaitable, Callable
1
2
  from inspect import isawaitable
2
- from typing import Awaitable, Callable, Dict, Optional, TypeVar, Union
3
+ from typing import TypeVar
3
4
 
4
- SyncAuthValue = Union[str, Callable[[], str]]
5
- AsyncAuthValue = Union[SyncAuthValue, Callable[[], Awaitable[str]]]
5
+ SyncAuthValue = str | Callable[[], str]
6
+ AsyncAuthValue = SyncAuthValue | Callable[[], Awaitable[str]]
6
7
 
7
8
  AuthValueT = TypeVar(
8
9
  "AuthValueT",
9
- bound=Union[SyncAuthValue, AsyncAuthValue],
10
+ bound=SyncAuthValue | AsyncAuthValue,
10
11
  )
11
12
 
12
13
 
@@ -20,7 +21,8 @@ def get_auth_value(auth_value: SyncAuthValue) -> str:
20
21
  if TYPE_CHECKING:
21
22
  assert_never(auth_value)
22
23
  raise TypeError(
23
- f"auth_value must be a string or a callable returning a string, got {type(auth_value).__name__}"
24
+ f"auth_value must be a string or a callable returning a string, "
25
+ f"got {type(auth_value).__name__}"
24
26
  )
25
27
 
26
28
 
@@ -35,16 +37,17 @@ async def aget_auth_value(auth_value: AsyncAuthValue) -> str:
35
37
  if TYPE_CHECKING:
36
38
  assert_never(auth_value)
37
39
  raise TypeError(
38
- f"auth_value must be a string or a callable, got {type(auth_value).__name__}"
40
+ "auth_value must be a string or a callable, "
41
+ f"got {type(auth_value).__name__}"
39
42
  )
40
43
 
41
44
 
42
45
  def get_combined_auth_headers(
43
46
  *,
44
- api_key: Optional[SyncAuthValue] = None,
45
- bearer_token: Optional[SyncAuthValue] = None,
46
- ) -> Dict[str, str]:
47
- headers: Dict[str, str] = {}
47
+ api_key: SyncAuthValue | None = None,
48
+ bearer_token: SyncAuthValue | None = None,
49
+ ) -> dict[str, str]:
50
+ headers: dict[str, str] = {}
48
51
 
49
52
  if api_key is not None:
50
53
  headers["api-key"] = get_auth_value(api_key)
@@ -58,11 +61,14 @@ def get_combined_auth_headers(
58
61
 
59
62
  async def aget_combined_auth_headers(
60
63
  *,
61
- api_key: Optional[AsyncAuthValue] = None,
62
- bearer_token: Optional[AsyncAuthValue] = None,
63
- ) -> Dict[str, str]:
64
- """Get combined authentication headers from both api_key and bearer_token (async)."""
65
- headers: Dict[str, str] = {}
64
+ api_key: AsyncAuthValue | None = None,
65
+ bearer_token: AsyncAuthValue | None = None,
66
+ ) -> dict[str, str]:
67
+ """
68
+ Get combined authentication headers from both api_key and
69
+ bearer_token (async).
70
+ """
71
+ headers: dict[str, str] = {}
66
72
 
67
73
  if api_key is not None:
68
74
  processed_api_key = await aget_auth_value(api_key)
@@ -77,8 +83,8 @@ async def aget_combined_auth_headers(
77
83
 
78
84
  def validate_auth(
79
85
  *,
80
- api_key: Optional[AsyncAuthValue] = None,
81
- bearer_token: Optional[AsyncAuthValue] = None,
86
+ api_key: AsyncAuthValue | None = None,
87
+ bearer_token: AsyncAuthValue | None = None,
82
88
  ) -> None:
83
89
  """Validate that at least one authentication method is provided."""
84
90
  if not api_key and not bearer_token:
@@ -1,6 +1,6 @@
1
1
  from abc import ABC, abstractmethod
2
2
  from pathlib import PurePosixPath
3
- from typing import Dict, Generic, Optional, TypeVar, Union
3
+ from typing import Generic, TypeVar
4
4
  from urllib.parse import urljoin
5
5
 
6
6
  import openai
@@ -24,30 +24,28 @@ from aidial_client._internal_types._defaults import NOT_GIVEN, NotGiven
24
24
  from aidial_client.helpers._url import enforce_trailing_slash
25
25
  from aidial_client.types.bucket import AppData
26
26
 
27
- _HttpClientT = TypeVar(
28
- "_HttpClientT", bound=Union[AsyncHTTPClient, SyncHTTPClient]
29
- )
27
+ _HttpClientT = TypeVar("_HttpClientT", bound=AsyncHTTPClient | SyncHTTPClient)
30
28
 
31
29
 
32
30
  class BaseDialClient(Generic[_HttpClientT, AuthValueT], ABC):
33
- _api_key: Optional[AuthValueT]
34
- _bearer_token: Optional[AuthValueT]
31
+ _api_key: AuthValueT | None
32
+ _bearer_token: AuthValueT | None
35
33
  _base_url: str
36
34
  _http_client: _HttpClientT
37
- _auth_headers: Dict[str, str]
38
- _my_bucket: Optional[str]
39
- _my_appdata: Union[AppData, None, NotGiven]
35
+ _auth_headers: dict[str, str]
36
+ _my_bucket: str | None
37
+ _my_appdata: AppData | None | NotGiven
40
38
 
41
39
  def __init__(
42
40
  self,
43
41
  *,
44
42
  base_url: str,
45
- api_key: Optional[AuthValueT] = None,
46
- bearer_token: Optional[AuthValueT] = None,
43
+ api_key: AuthValueT | None = None,
44
+ bearer_token: AuthValueT | None = None,
47
45
  max_retries: int = DEFAULT_MAX_RETRIES,
48
- timeout: Union[float, Timeout, None] = DEFAULT_TIMEOUT,
49
- api_version: Optional[str] = None,
50
- http_client: Optional[_HttpClientT] = None,
46
+ timeout: float | Timeout | None = DEFAULT_TIMEOUT,
47
+ api_version: str | None = None,
48
+ http_client: _HttpClientT | None = None,
51
49
  ):
52
50
  validate_auth(api_key=api_key, bearer_token=bearer_token)
53
51
  self._api_key = api_key
@@ -79,12 +77,11 @@ class BaseDialClient(Generic[_HttpClientT, AuthValueT], ABC):
79
77
  return self._base_url
80
78
 
81
79
  @property
82
- def api_version(self) -> Optional[str]:
80
+ def api_version(self) -> str | None:
83
81
  return self._api_version
84
82
 
85
83
 
86
84
  class Dial(BaseDialClient[SyncHTTPClient, SyncAuthValue]):
87
-
88
85
  def _init_resources(self) -> None:
89
86
  openai_client = openai.AzureOpenAI(
90
87
  api_key="-",
@@ -150,26 +147,25 @@ class Dial(BaseDialClient[SyncHTTPClient, SyncAuthValue]):
150
147
  def my_prompts_home(self) -> PurePosixPath:
151
148
  return "prompts" / PurePosixPath(self.my_bucket())
152
149
 
153
- def _get_my_appdata(self) -> Optional[AppData]:
150
+ def _get_my_appdata(self) -> AppData | None:
154
151
  return self.bucket.get_appdata()
155
152
 
156
- def my_appdata(self) -> Optional[AppData]:
153
+ def my_appdata(self) -> AppData | None:
157
154
  if isinstance(self._my_appdata, NotGiven):
158
155
  self._my_appdata = self._get_my_appdata()
159
156
  return self._my_appdata
160
157
 
161
- def my_appdata_home(self) -> Optional[PurePosixPath]:
158
+ def my_appdata_home(self) -> PurePosixPath | None:
162
159
  appdata = self.my_appdata()
163
160
  if appdata:
164
161
  return PurePosixPath(appdata.raw)
165
162
  return None
166
163
 
167
- def auth_headers(self) -> Dict[str, str]:
164
+ def auth_headers(self) -> dict[str, str]:
168
165
  return self._http_client.auth_headers()
169
166
 
170
167
 
171
168
  class AsyncDial(BaseDialClient[AsyncHTTPClient, AsyncAuthValue]):
172
-
173
169
  def _init_resources(self) -> None:
174
170
  openai_client = openai.AsyncAzureOpenAI(
175
171
  api_key="-",
@@ -241,19 +237,19 @@ class AsyncDial(BaseDialClient[AsyncHTTPClient, AsyncAuthValue]):
241
237
  async def my_prompts_home(self) -> PurePosixPath:
242
238
  return "prompts" / PurePosixPath(await self.my_bucket())
243
239
 
244
- async def _get_my_appdata(self) -> Optional[AppData]:
240
+ async def _get_my_appdata(self) -> AppData | None:
245
241
  return await self.bucket.get_appdata()
246
242
 
247
- async def my_appdata(self) -> Optional[AppData]:
243
+ async def my_appdata(self) -> AppData | None:
248
244
  if isinstance(self._my_appdata, NotGiven):
249
245
  self._my_appdata = await self._get_my_appdata()
250
246
  return self._my_appdata
251
247
 
252
- async def my_appdata_home(self) -> Optional[PurePosixPath]:
248
+ async def my_appdata_home(self) -> PurePosixPath | None:
253
249
  appdata = await self.my_appdata()
254
250
  if appdata:
255
251
  return PurePosixPath(appdata.raw)
256
252
  return None
257
253
 
258
- async def auth_headers(self) -> Dict[str, str]:
254
+ async def auth_headers(self) -> dict[str, str]:
259
255
  return await self._http_client.auth_headers()
@@ -1,5 +1,3 @@
1
- from typing import Optional, Union
2
-
3
1
  import httpx
4
2
 
5
3
  from aidial_client._auth import AsyncAuthValue, SyncAuthValue
@@ -27,10 +25,10 @@ class DialClientPool:
27
25
  self,
28
26
  *,
29
27
  base_url: str,
30
- api_key: Optional[SyncAuthValue] = None,
31
- bearer_token: Optional[SyncAuthValue] = None,
28
+ api_key: SyncAuthValue | None = None,
29
+ bearer_token: SyncAuthValue | None = None,
32
30
  max_retries: int = DEFAULT_MAX_RETRIES,
33
- timeout: Union[httpx.Timeout, float] = DEFAULT_TIMEOUT,
31
+ timeout: httpx.Timeout | float = DEFAULT_TIMEOUT,
34
32
  ) -> Dial:
35
33
  return Dial(
36
34
  base_url=base_url,
@@ -62,10 +60,10 @@ class AsyncDialClientPool:
62
60
  self,
63
61
  *,
64
62
  base_url: str,
65
- api_key: Optional[AsyncAuthValue] = None,
66
- bearer_token: Optional[AsyncAuthValue] = None,
63
+ api_key: AsyncAuthValue | None = None,
64
+ bearer_token: AsyncAuthValue | None = None,
67
65
  max_retries: int = DEFAULT_MAX_RETRIES,
68
- timeout: Union[httpx.Timeout, float] = DEFAULT_TIMEOUT,
66
+ timeout: httpx.Timeout | float = DEFAULT_TIMEOUT,
69
67
  ) -> AsyncDial:
70
68
  return AsyncDial(
71
69
  base_url=base_url,
@@ -1,5 +1,5 @@
1
+ from collections.abc import Mapping
1
2
  from http import HTTPStatus
2
- from typing import Mapping, Optional
3
3
 
4
4
 
5
5
  class DialException(Exception):
@@ -7,10 +7,10 @@ class DialException(Exception):
7
7
  self,
8
8
  message: str,
9
9
  status_code: int = 500,
10
- type: Optional[str] = "runtime_error",
11
- param: Optional[str] = None,
12
- code: Optional[str] = None,
13
- display_message: Optional[str] = None,
10
+ type: str | None = "runtime_error",
11
+ param: str | None = None,
12
+ code: str | None = None,
13
+ display_message: str | None = None,
14
14
  ) -> None:
15
15
  self.message = message
16
16
  self.status_code = status_code
@@ -1,16 +1,8 @@
1
1
  import asyncio
2
- from contextlib import asynccontextmanager
2
+ from collections.abc import AsyncIterator, Callable, Mapping
3
+ from contextlib import asynccontextmanager, suppress
3
4
  from http import HTTPStatus
4
- from typing import (
5
- Any,
6
- AsyncIterator,
7
- Callable,
8
- Dict,
9
- Mapping,
10
- Optional,
11
- Type,
12
- Union,
13
- )
5
+ from typing import Any
14
6
 
15
7
  import httpx
16
8
 
@@ -30,7 +22,7 @@ class AsyncHTTPClient(BaseHTTPClient[httpx.AsyncClient, AsyncAuthValue]):
30
22
  timeout=self._timeout,
31
23
  )
32
24
 
33
- async def auth_headers(self) -> Dict[str, str]:
25
+ async def auth_headers(self) -> dict[str, str]:
34
26
  return await aget_combined_auth_headers(
35
27
  api_key=self._api_key, bearer_token=self._bearer_token
36
28
  )
@@ -39,7 +31,7 @@ class AsyncHTTPClient(BaseHTTPClient[httpx.AsyncClient, AsyncAuthValue]):
39
31
  self,
40
32
  *,
41
33
  options: FinalRequestOptions,
42
- cast_to: Type[ResponseT],
34
+ cast_to: type[ResponseT],
43
35
  remaining_retries: int,
44
36
  ) -> ResponseT:
45
37
  remaining = remaining_retries - 1
@@ -57,11 +49,10 @@ class AsyncHTTPClient(BaseHTTPClient[httpx.AsyncClient, AsyncAuthValue]):
57
49
  self,
58
50
  *,
59
51
  options: FinalRequestOptions,
60
- cast_to: Type[ResponseT],
61
- remaining_retries: Optional[int] = None,
62
- on_http_error: Optional[
63
- Callable[[httpx.HTTPStatusError], Optional[DialException]]
64
- ] = None,
52
+ cast_to: type[ResponseT],
53
+ remaining_retries: int | None = None,
54
+ on_http_error: Callable[[httpx.HTTPStatusError], DialException | None]
55
+ | None = None,
65
56
  ) -> ResponseT:
66
57
  retries = self._remaining_retries(remaining_retries, options)
67
58
  auth_headers = await self.auth_headers()
@@ -127,8 +118,8 @@ class AsyncHTTPClient(BaseHTTPClient[httpx.AsyncClient, AsyncAuthValue]):
127
118
  method: str,
128
119
  url: str,
129
120
  json_data: Any,
130
- headers: Optional[Mapping[str, str]] = None,
131
- timeout: Union[float, httpx.Timeout, None, NotGiven] = NOT_GIVEN,
121
+ headers: Mapping[str, str] | None = None,
122
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
132
123
  ) -> AsyncIterator[httpx.Response]:
133
124
  """Open an SSE streaming response. Yields the open httpx.Response.
134
125
 
@@ -155,10 +146,8 @@ class AsyncHTTPClient(BaseHTTPClient[httpx.AsyncClient, AsyncAuthValue]):
155
146
  try:
156
147
  response.raise_for_status()
157
148
  except httpx.HTTPStatusError as err:
158
- try:
149
+ with suppress(httpx.HTTPError):
159
150
  await response.aread()
160
- except httpx.HTTPError:
161
- pass
162
151
  raise self._make_dial_error_from_response(
163
152
  err.response
164
153
  ) from err
@@ -1,7 +1,7 @@
1
1
  from abc import ABC, abstractmethod
2
2
  from http import HTTPStatus
3
3
  from random import uniform
4
- from typing import Dict, Generic, Optional, TypeVar, Union
4
+ from typing import Generic, TypeVar
5
5
 
6
6
  import httpx
7
7
 
@@ -13,23 +13,23 @@ from aidial_client._utils._type_guard import is_mapping
13
13
  from aidial_client.helpers._url import enforce_trailing_slash
14
14
 
15
15
  _HttpInternalClientT = TypeVar(
16
- "_HttpInternalClientT", bound=Union[httpx.Client, httpx.AsyncClient]
16
+ "_HttpInternalClientT", bound=httpx.Client | httpx.AsyncClient
17
17
  )
18
18
 
19
19
 
20
20
  class BaseHTTPClient(ABC, Generic[_HttpInternalClientT, AuthValueT]):
21
21
  _internal_http_client: _HttpInternalClientT
22
- _api_key: Optional[AuthValueT]
23
- _bearer_token: Optional[AuthValueT]
22
+ _api_key: AuthValueT | None
23
+ _bearer_token: AuthValueT | None
24
24
 
25
25
  def __init__(
26
26
  self,
27
27
  base_url: str,
28
- api_key: Optional[AuthValueT],
29
- bearer_token: Optional[AuthValueT],
28
+ api_key: AuthValueT | None,
29
+ bearer_token: AuthValueT | None,
30
30
  max_retries: int,
31
- timeout: Union[float, httpx.Timeout, None],
32
- internal_http_client: Optional[_HttpInternalClientT] = None,
31
+ timeout: float | httpx.Timeout | None,
32
+ internal_http_client: _HttpInternalClientT | None = None,
33
33
  ):
34
34
  self.base_url = httpx.URL(enforce_trailing_slash(base_url))
35
35
  self._api_key = api_key
@@ -57,7 +57,7 @@ class BaseHTTPClient(ABC, Generic[_HttpInternalClientT, AuthValueT]):
57
57
  def _build_request(
58
58
  self,
59
59
  options: FinalRequestOptions,
60
- auth_headers: Dict[str, str],
60
+ auth_headers: dict[str, str],
61
61
  ) -> httpx.Request:
62
62
  custom_headers = options.headers or {}
63
63
  return self._internal_http_client.build_request(
@@ -88,10 +88,7 @@ class BaseHTTPClient(ABC, Generic[_HttpInternalClientT, AuthValueT]):
88
88
  if response.status_code == HTTPStatus.CONFLICT:
89
89
  return True
90
90
 
91
- if response.status_code == HTTPStatus.TOO_MANY_REQUESTS:
92
- return True
93
-
94
- return False
91
+ return response.status_code == HTTPStatus.TOO_MANY_REQUESTS
95
92
 
96
93
  def _calculate_retry_sleep_seconds(
97
94
  self,
@@ -106,7 +103,7 @@ class BaseHTTPClient(ABC, Generic[_HttpInternalClientT, AuthValueT]):
106
103
  sleep_seconds = min(
107
104
  INITIAL_RETRY_DELAY * pow(2.0, nb_retries), MAX_RETRY_DELAY
108
105
  )
109
- timeout = sleep_seconds + uniform(-0.5, 0.5)
106
+ timeout = sleep_seconds + uniform(-0.5, 0.5) # noqa: S311
110
107
  return max(0, timeout)
111
108
 
112
109
  def _make_dial_error_from_response(
@@ -1,4 +1,4 @@
1
- from typing import AsyncIterator, Iterator, List
1
+ from collections.abc import AsyncIterator, Iterator
2
2
 
3
3
  from aidial_client._log import logger
4
4
 
@@ -9,20 +9,23 @@ _UNCOMMITTED_BUFFER_WARNING = (
9
9
 
10
10
 
11
11
  def _strip_field(line: str, prefix: str) -> str:
12
- """Strip a single leading U+0020 SPACE after the field colon, per the SSE spec."""
12
+ """
13
+ Strip a single leading U+0020 SPACE after the field colon, per the SSE spec.
14
+ """
13
15
  value = line[len(prefix) :]
14
- return value[1:] if value.startswith(" ") else value
16
+ return value.removeprefix(" ")
15
17
 
16
18
 
17
19
  def iter_data_events(lines: Iterator[str]) -> Iterator[str]:
18
- """Yield the payload of each complete ``data:`` event from an SSE line stream.
20
+ """
21
+ Yield the payload of each complete ``data:`` event from an SSE line stream.
19
22
 
20
23
  An event is complete when a blank line follows the ``data:`` line(s). Per
21
24
  the SSE dispatch rule, a buffer that has not been terminated by a blank
22
25
  line is discarded (we do NOT flush partial events at end of stream).
23
26
  Comment lines (``:``) and other field names are ignored.
24
27
  """
25
- buffer: List[str] = []
28
+ buffer: list[str] = []
26
29
  for line in lines:
27
30
  if line == "":
28
31
  if buffer:
@@ -35,7 +38,7 @@ def iter_data_events(lines: Iterator[str]) -> Iterator[str]:
35
38
 
36
39
 
37
40
  async def aiter_data_events(lines: AsyncIterator[str]) -> AsyncIterator[str]:
38
- buffer: List[str] = []
41
+ buffer: list[str] = []
39
42
  async for line in lines:
40
43
  if line == "":
41
44
  if buffer:
@@ -1,7 +1,8 @@
1
1
  import time
2
- from contextlib import contextmanager
2
+ from collections.abc import Callable, Iterator, Mapping
3
+ from contextlib import contextmanager, suppress
3
4
  from http import HTTPStatus
4
- from typing import Any, Callable, Dict, Iterator, Mapping, Optional, Type, Union
5
+ from typing import Any
5
6
 
6
7
  import httpx
7
8
 
@@ -22,7 +23,7 @@ class SyncHTTPClient(BaseHTTPClient[httpx.Client, SyncAuthValue]):
22
23
  def _retry_request(
23
24
  self,
24
25
  options: FinalRequestOptions,
25
- cast_to: Type[ResponseT],
26
+ cast_to: type[ResponseT],
26
27
  remaining_retries: int,
27
28
  ) -> ResponseT:
28
29
  remaining = remaining_retries - 1
@@ -38,7 +39,7 @@ class SyncHTTPClient(BaseHTTPClient[httpx.Client, SyncAuthValue]):
38
39
  remaining_retries=remaining,
39
40
  )
40
41
 
41
- def auth_headers(self) -> Dict[str, str]:
42
+ def auth_headers(self) -> dict[str, str]:
42
43
  return get_combined_auth_headers(
43
44
  api_key=self._api_key, bearer_token=self._bearer_token
44
45
  )
@@ -46,12 +47,11 @@ class SyncHTTPClient(BaseHTTPClient[httpx.Client, SyncAuthValue]):
46
47
  def request(
47
48
  self,
48
49
  *,
49
- cast_to: Type[ResponseT],
50
+ cast_to: type[ResponseT],
50
51
  options: FinalRequestOptions,
51
- remaining_retries: Optional[int] = None,
52
- on_http_error: Optional[
53
- Callable[[httpx.HTTPStatusError], Optional[DialException]]
54
- ] = None,
52
+ remaining_retries: int | None = None,
53
+ on_http_error: Callable[[httpx.HTTPStatusError], DialException | None]
54
+ | None = None,
55
55
  ) -> ResponseT:
56
56
  retries = self._remaining_retries(remaining_retries, options)
57
57
  auth_headers = self.auth_headers()
@@ -118,8 +118,8 @@ class SyncHTTPClient(BaseHTTPClient[httpx.Client, SyncAuthValue]):
118
118
  method: str,
119
119
  url: str,
120
120
  json_data: Any,
121
- headers: Optional[Mapping[str, str]] = None,
122
- timeout: Union[float, httpx.Timeout, None, NotGiven] = NOT_GIVEN,
121
+ headers: Mapping[str, str] | None = None,
122
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
123
123
  ) -> Iterator[httpx.Response]:
124
124
  """Open an SSE streaming response. Yields the open httpx.Response.
125
125
 
@@ -146,10 +146,8 @@ class SyncHTTPClient(BaseHTTPClient[httpx.Client, SyncAuthValue]):
146
146
  try:
147
147
  response.raise_for_status()
148
148
  except httpx.HTTPStatusError as err:
149
- try:
149
+ with suppress(httpx.HTTPError):
150
150
  response.read()
151
- except httpx.HTTPError:
152
- pass
153
151
  raise self._make_dial_error_from_response(
154
152
  err.response
155
153
  ) from err
@@ -1,4 +1,4 @@
1
- from typing import TypeVar, Union
1
+ from typing import TypeVar
2
2
 
3
3
  import httpx
4
4
 
@@ -10,15 +10,13 @@ from aidial_client.types.file import FileDownloadResponse
10
10
 
11
11
  ResponseT = TypeVar(
12
12
  "ResponseT",
13
- bound=Union[
14
- ExtraAllowModel,
15
- ExtraForbidModel,
16
- bytes,
17
- str,
18
- dict,
19
- httpx.Response,
20
- FileDownloadResponse,
21
- None,
22
- ],
13
+ bound=ExtraAllowModel
14
+ | ExtraForbidModel
15
+ | bytes
16
+ | str
17
+ | dict
18
+ | httpx.Response
19
+ | FileDownloadResponse
20
+ | None,
23
21
  )
24
22
  NoneType = type(None)
@@ -1,13 +1,9 @@
1
+ from collections.abc import Mapping, Sequence
1
2
  from io import BufferedReader
2
3
  from typing import (
3
4
  IO,
4
5
  Any,
5
6
  Literal,
6
- Mapping,
7
- Optional,
8
- Sequence,
9
- Tuple,
10
- Union,
11
7
  final,
12
8
  )
13
9
 
@@ -16,29 +12,29 @@ from httpx import Timeout
16
12
  from aidial_client._compatibility.pydantic_v1 import BaseModel
17
13
  from aidial_client._internal_types._defaults import NOT_GIVEN, NotGiven
18
14
 
19
- FileContent = Union[
20
- IO[bytes],
21
- bytes,
22
- str,
23
- # Somehow, pydantic doesn't recognize result of open('...', 'rb') as IO[bytes]
24
- # even though BufferedReader is a subclass of IO[bytes]
25
- BufferedReader,
26
- ]
27
- FileTypes = Union[
15
+ FileContent = (
16
+ IO[bytes]
17
+ | bytes
18
+ | str
19
+ # Somehow, pydantic doesn't recognize result of open('...', 'rb')
20
+ # as IO[bytes] even though BufferedReader is a subclass of IO[bytes]
21
+ | BufferedReader
22
+ )
23
+ FileTypes = (
28
24
  # file (or bytes)
29
- FileContent,
25
+ FileContent
30
26
  # (filename, file (or bytes))
31
- Tuple[Optional[str], FileContent],
27
+ | tuple[str | None, FileContent]
32
28
  # (filename, file (or bytes), content_type)
33
- Tuple[Optional[str], FileContent, Optional[str]],
29
+ | tuple[str | None, FileContent, str | None]
34
30
  # (filename, file (or bytes), content_type, headers)
35
- Tuple[Optional[str], FileContent, Optional[str], Mapping[str, str]],
36
- ]
31
+ | tuple[str | None, FileContent, str | None, Mapping[str, str]]
32
+ )
37
33
 
38
34
  Params = Mapping[str, Any]
39
35
  Headers = Mapping[str, Any]
40
36
  Data = Mapping[str, Any]
41
- RequestFiles = Union[Mapping[str, FileTypes], Sequence[Tuple[str, FileTypes]]]
37
+ RequestFiles = Mapping[str, FileTypes] | Sequence[tuple[str, FileTypes]]
42
38
 
43
39
 
44
40
  @final
@@ -48,12 +44,12 @@ class FinalRequestOptions(BaseModel):
48
44
 
49
45
  method: Literal["GET", "PUT", "POST", "DELETE"]
50
46
  url: str
51
- params: Optional[Params] = None
52
- headers: Optional[Headers] = None
53
- max_retries: Union[int, NotGiven] = NOT_GIVEN
54
- timeout: Union[float, Timeout, NotGiven, None] = NOT_GIVEN
55
- files: Optional[RequestFiles] = None
56
- json_data: Optional[Data] = None
47
+ params: Params | None = None
48
+ headers: Headers | None = None
49
+ max_retries: int | NotGiven = NOT_GIVEN
50
+ timeout: float | Timeout | NotGiven | None = NOT_GIVEN
51
+ files: RequestFiles | None = None
52
+ json_data: Data | None = None
57
53
 
58
54
  def get_max_retries(self, max_retries: int) -> int:
59
55
  if isinstance(self.max_retries, NotGiven):
@@ -61,8 +57,8 @@ class FinalRequestOptions(BaseModel):
61
57
  return self.max_retries
62
58
 
63
59
  def get_timeout(
64
- self, timeout: Union[float, Timeout, None]
65
- ) -> Union[float, Timeout, None]:
60
+ self, timeout: float | Timeout | None
61
+ ) -> float | Timeout | None:
66
62
  if isinstance(self.timeout, NotGiven):
67
63
  return timeout
68
64
  return self.timeout