google-genai 1.7.0__py3-none-any.whl → 1.53.0__py3-none-any.whl
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.
- google/genai/__init__.py +4 -2
- google/genai/_adapters.py +55 -0
- google/genai/_api_client.py +1301 -299
- google/genai/_api_module.py +1 -1
- google/genai/_automatic_function_calling_util.py +54 -33
- google/genai/_base_transformers.py +26 -0
- google/genai/_base_url.py +50 -0
- google/genai/_common.py +560 -59
- google/genai/_extra_utils.py +371 -38
- google/genai/_live_converters.py +1467 -0
- google/genai/_local_tokenizer_loader.py +214 -0
- google/genai/_mcp_utils.py +117 -0
- google/genai/_operations_converters.py +394 -0
- google/genai/_replay_api_client.py +204 -92
- google/genai/_test_api_client.py +1 -1
- google/genai/_tokens_converters.py +520 -0
- google/genai/_transformers.py +633 -233
- google/genai/batches.py +1733 -538
- google/genai/caches.py +678 -1012
- google/genai/chats.py +48 -38
- google/genai/client.py +142 -15
- google/genai/documents.py +532 -0
- google/genai/errors.py +141 -35
- google/genai/file_search_stores.py +1296 -0
- google/genai/files.py +312 -744
- google/genai/live.py +617 -367
- google/genai/live_music.py +197 -0
- google/genai/local_tokenizer.py +395 -0
- google/genai/models.py +3598 -3116
- google/genai/operations.py +201 -362
- google/genai/pagers.py +23 -7
- google/genai/py.typed +1 -0
- google/genai/tokens.py +362 -0
- google/genai/tunings.py +1274 -496
- google/genai/types.py +14535 -5454
- google/genai/version.py +2 -2
- {google_genai-1.7.0.dist-info → google_genai-1.53.0.dist-info}/METADATA +736 -234
- google_genai-1.53.0.dist-info/RECORD +41 -0
- {google_genai-1.7.0.dist-info → google_genai-1.53.0.dist-info}/WHEEL +1 -1
- google_genai-1.7.0.dist-info/RECORD +0 -27
- {google_genai-1.7.0.dist-info → google_genai-1.53.0.dist-info/licenses}/LICENSE +0 -0
- {google_genai-1.7.0.dist-info → google_genai-1.53.0.dist-info}/top_level.txt +0 -0
google/genai/errors.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright
|
|
1
|
+
# Copyright 2025 Google LLC
|
|
2
2
|
#
|
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
# you may not use this file except in compliance with the License.
|
|
@@ -18,16 +18,18 @@
|
|
|
18
18
|
from typing import Any, Optional, TYPE_CHECKING, Union
|
|
19
19
|
import httpx
|
|
20
20
|
import json
|
|
21
|
+
from . import _common
|
|
21
22
|
|
|
22
23
|
|
|
23
24
|
if TYPE_CHECKING:
|
|
24
25
|
from .replay_api_client import ReplayResponse
|
|
26
|
+
import aiohttp
|
|
25
27
|
|
|
26
28
|
|
|
27
29
|
class APIError(Exception):
|
|
28
30
|
"""General errors raised by the GenAI API."""
|
|
29
31
|
code: int
|
|
30
|
-
response: Union['ReplayResponse', httpx.Response]
|
|
32
|
+
response: Union['ReplayResponse', httpx.Response, 'aiohttp.ClientResponse']
|
|
31
33
|
|
|
32
34
|
status: Optional[str] = None
|
|
33
35
|
message: Optional[str] = None
|
|
@@ -35,28 +37,15 @@ class APIError(Exception):
|
|
|
35
37
|
def __init__(
|
|
36
38
|
self,
|
|
37
39
|
code: int,
|
|
38
|
-
|
|
40
|
+
response_json: Any,
|
|
41
|
+
response: Optional[
|
|
42
|
+
Union['ReplayResponse', httpx.Response, 'aiohttp.ClientResponse']
|
|
43
|
+
] = None,
|
|
39
44
|
):
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
if isinstance(response, httpx.Response):
|
|
43
|
-
try:
|
|
44
|
-
response_json = response.json()
|
|
45
|
-
except (json.decoder.JSONDecodeError):
|
|
46
|
-
message = response.text
|
|
47
|
-
response_json = {
|
|
48
|
-
'message': message,
|
|
49
|
-
'status': response.reason_phrase,
|
|
50
|
-
}
|
|
51
|
-
except httpx.ResponseNotRead:
|
|
52
|
-
message = 'Response not read'
|
|
53
|
-
response_json = {
|
|
54
|
-
'message': message,
|
|
55
|
-
'status': response.reason_phrase,
|
|
56
|
-
}
|
|
57
|
-
else:
|
|
58
|
-
response_json = response.body_segments[0].get('error', {})
|
|
45
|
+
if isinstance(response_json, list) and len(response_json) == 1:
|
|
46
|
+
response_json = response_json[0]
|
|
59
47
|
|
|
48
|
+
self.response = response
|
|
60
49
|
self.details = response_json
|
|
61
50
|
self.message = self._get_message(response_json)
|
|
62
51
|
self.status = self._get_status(response_json)
|
|
@@ -64,22 +53,22 @@ class APIError(Exception):
|
|
|
64
53
|
|
|
65
54
|
super().__init__(f'{self.code} {self.status}. {self.details}')
|
|
66
55
|
|
|
67
|
-
def _get_status(self, response_json):
|
|
56
|
+
def _get_status(self, response_json: Any) -> Any:
|
|
68
57
|
return response_json.get(
|
|
69
58
|
'status', response_json.get('error', {}).get('status', None)
|
|
70
59
|
)
|
|
71
60
|
|
|
72
|
-
def _get_message(self, response_json):
|
|
61
|
+
def _get_message(self, response_json: Any) -> Any:
|
|
73
62
|
return response_json.get(
|
|
74
63
|
'message', response_json.get('error', {}).get('message', None)
|
|
75
64
|
)
|
|
76
65
|
|
|
77
|
-
def _get_code(self, response_json):
|
|
66
|
+
def _get_code(self, response_json: Any) -> Any:
|
|
78
67
|
return response_json.get(
|
|
79
68
|
'code', response_json.get('error', {}).get('code', None)
|
|
80
69
|
)
|
|
81
70
|
|
|
82
|
-
def _to_replay_record(self):
|
|
71
|
+
def _to_replay_record(self) -> _common.StringDict:
|
|
83
72
|
"""Returns a dictionary representation of the error for replay recording.
|
|
84
73
|
|
|
85
74
|
details is not included since it may expose internal information in the
|
|
@@ -96,18 +85,133 @@ class APIError(Exception):
|
|
|
96
85
|
@classmethod
|
|
97
86
|
def raise_for_response(
|
|
98
87
|
cls, response: Union['ReplayResponse', httpx.Response]
|
|
99
|
-
):
|
|
88
|
+
) -> None:
|
|
100
89
|
"""Raises an error with detailed error message if the response has an error status."""
|
|
101
90
|
if response.status_code == 200:
|
|
102
91
|
return
|
|
103
92
|
|
|
104
|
-
|
|
93
|
+
if isinstance(response, httpx.Response):
|
|
94
|
+
try:
|
|
95
|
+
response.read()
|
|
96
|
+
response_json = response.json()
|
|
97
|
+
except json.decoder.JSONDecodeError:
|
|
98
|
+
message = response.text
|
|
99
|
+
response_json = {
|
|
100
|
+
'message': message,
|
|
101
|
+
'status': response.reason_phrase,
|
|
102
|
+
}
|
|
103
|
+
else:
|
|
104
|
+
response_json = response.body_segments[0].get('error', {})
|
|
105
|
+
|
|
106
|
+
cls.raise_error(response.status_code, response_json, response)
|
|
107
|
+
|
|
108
|
+
@classmethod
|
|
109
|
+
def raise_error(
|
|
110
|
+
cls,
|
|
111
|
+
status_code: int,
|
|
112
|
+
response_json: Any,
|
|
113
|
+
response: Optional[
|
|
114
|
+
Union['ReplayResponse', httpx.Response, 'aiohttp.ClientResponse']
|
|
115
|
+
],
|
|
116
|
+
) -> None:
|
|
117
|
+
"""Raises an appropriate APIError subclass based on the status code.
|
|
118
|
+
|
|
119
|
+
Args:
|
|
120
|
+
status_code: The HTTP status code of the response.
|
|
121
|
+
response_json: The JSON body of the response, or a dict containing error
|
|
122
|
+
details.
|
|
123
|
+
response: The original response object.
|
|
124
|
+
|
|
125
|
+
Raises:
|
|
126
|
+
ClientError: If the status code is in the 4xx range.
|
|
127
|
+
ServerError: If the status code is in the 5xx range.
|
|
128
|
+
APIError: For other error status codes.
|
|
129
|
+
"""
|
|
130
|
+
if 400 <= status_code < 500:
|
|
131
|
+
raise ClientError(status_code, response_json, response)
|
|
132
|
+
elif 500 <= status_code < 600:
|
|
133
|
+
raise ServerError(status_code, response_json, response)
|
|
134
|
+
else:
|
|
135
|
+
raise cls(status_code, response_json, response)
|
|
136
|
+
|
|
137
|
+
@classmethod
|
|
138
|
+
async def raise_for_async_response(
|
|
139
|
+
cls,
|
|
140
|
+
response: Union[
|
|
141
|
+
'ReplayResponse', httpx.Response, 'aiohttp.ClientResponse'
|
|
142
|
+
],
|
|
143
|
+
) -> None:
|
|
144
|
+
"""Raises an error with detailed error message if the response has an error status."""
|
|
145
|
+
status_code = 0
|
|
146
|
+
response_json = None
|
|
147
|
+
if isinstance(response, httpx.Response):
|
|
148
|
+
if response.status_code == 200:
|
|
149
|
+
return
|
|
150
|
+
try:
|
|
151
|
+
await response.aread()
|
|
152
|
+
response_json = response.json()
|
|
153
|
+
except json.decoder.JSONDecodeError:
|
|
154
|
+
message = response.text
|
|
155
|
+
response_json = {
|
|
156
|
+
'message': message,
|
|
157
|
+
'status': response.reason_phrase,
|
|
158
|
+
}
|
|
159
|
+
status_code = response.status_code
|
|
160
|
+
elif hasattr(response, 'body_segments') and hasattr(
|
|
161
|
+
response, 'status_code'
|
|
162
|
+
):
|
|
163
|
+
if response.status_code == 200:
|
|
164
|
+
return
|
|
165
|
+
response_json = response.body_segments[0].get('error', {})
|
|
166
|
+
status_code = response.status_code
|
|
167
|
+
else:
|
|
168
|
+
try:
|
|
169
|
+
import aiohttp # pylint: disable=g-import-not-at-top
|
|
170
|
+
|
|
171
|
+
if isinstance(response, aiohttp.ClientResponse):
|
|
172
|
+
if response.status == 200:
|
|
173
|
+
return
|
|
174
|
+
try:
|
|
175
|
+
response_json = await response.json()
|
|
176
|
+
except aiohttp.client_exceptions.ContentTypeError:
|
|
177
|
+
message = await response.text()
|
|
178
|
+
response_json = {
|
|
179
|
+
'message': message,
|
|
180
|
+
'status': response.reason,
|
|
181
|
+
}
|
|
182
|
+
status_code = response.status
|
|
183
|
+
else:
|
|
184
|
+
raise ValueError(f'Unsupported response type: {type(response)}')
|
|
185
|
+
except ImportError:
|
|
186
|
+
raise ValueError(f'Unsupported response type: {type(response)}')
|
|
187
|
+
|
|
188
|
+
await cls.raise_error_async(status_code, response_json, response)
|
|
189
|
+
|
|
190
|
+
@classmethod
|
|
191
|
+
async def raise_error_async(
|
|
192
|
+
cls, status_code: int, response_json: Any, response: Optional[
|
|
193
|
+
Union['ReplayResponse', httpx.Response, 'aiohttp.ClientResponse']
|
|
194
|
+
]
|
|
195
|
+
) -> None:
|
|
196
|
+
"""Raises an appropriate APIError subclass based on the status code.
|
|
197
|
+
|
|
198
|
+
Args:
|
|
199
|
+
status_code: The HTTP status code of the response.
|
|
200
|
+
response_json: The JSON body of the response, or a dict containing error
|
|
201
|
+
details.
|
|
202
|
+
response: The original response object.
|
|
203
|
+
|
|
204
|
+
Raises:
|
|
205
|
+
ClientError: If the status code is in the 4xx range.
|
|
206
|
+
ServerError: If the status code is in the 5xx range.
|
|
207
|
+
APIError: For other error status codes.
|
|
208
|
+
"""
|
|
105
209
|
if 400 <= status_code < 500:
|
|
106
|
-
raise ClientError(status_code, response)
|
|
210
|
+
raise ClientError(status_code, response_json, response)
|
|
107
211
|
elif 500 <= status_code < 600:
|
|
108
|
-
raise ServerError(status_code, response)
|
|
212
|
+
raise ServerError(status_code, response_json, response)
|
|
109
213
|
else:
|
|
110
|
-
raise cls(status_code, response)
|
|
214
|
+
raise cls(status_code, response_json, response)
|
|
111
215
|
|
|
112
216
|
|
|
113
217
|
class ClientError(APIError):
|
|
@@ -122,19 +226,21 @@ class ServerError(APIError):
|
|
|
122
226
|
|
|
123
227
|
class UnknownFunctionCallArgumentError(ValueError):
|
|
124
228
|
"""Raised when the function call argument cannot be converted to the parameter annotation."""
|
|
125
|
-
|
|
126
229
|
pass
|
|
127
230
|
|
|
128
231
|
|
|
129
232
|
class UnsupportedFunctionError(ValueError):
|
|
130
233
|
"""Raised when the function is not supported."""
|
|
234
|
+
pass
|
|
131
235
|
|
|
132
236
|
|
|
133
237
|
class FunctionInvocationError(ValueError):
|
|
134
238
|
"""Raised when the function cannot be invoked with the given arguments."""
|
|
135
|
-
|
|
136
239
|
pass
|
|
137
240
|
|
|
138
241
|
|
|
139
|
-
class
|
|
140
|
-
"""
|
|
242
|
+
class UnknownApiResponseError(ValueError):
|
|
243
|
+
"""Raised when the response from the API cannot be parsed as JSON."""
|
|
244
|
+
pass
|
|
245
|
+
|
|
246
|
+
ExperimentalWarning = _common.ExperimentalWarning
|