google-genai 0.7.0__py3-none-any.whl → 1.0.0rc0__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.
@@ -255,7 +255,7 @@ class ApiClient:
255
255
  'Project and location or API key must be set when using the Vertex '
256
256
  'AI API.'
257
257
  )
258
- if self.api_key:
258
+ if self.api_key or self.location == 'global':
259
259
  self._http_options['base_url'] = (
260
260
  f'https://aiplatform.googleapis.com/'
261
261
  )
@@ -273,7 +273,7 @@ class ApiClient:
273
273
  self._http_options['api_version'] = 'v1beta'
274
274
  # Default options for both clients.
275
275
  self._http_options['headers'] = {'Content-Type': 'application/json'}
276
- if self.api_key and not self.vertexai:
276
+ if self.api_key:
277
277
  self._http_options['headers']['x-goog-api-key'] = self.api_key
278
278
  # Update the http options with the user provided http options.
279
279
  if http_options:
@@ -323,8 +323,6 @@ class ApiClient:
323
323
  and not self.api_key
324
324
  ):
325
325
  path = f'projects/{self.project}/locations/{self.location}/' + path
326
- elif self.vertexai and self.api_key:
327
- path = f'{path}?key={self.api_key}'
328
326
  url = _join_url_path(
329
327
  patched_http_options['base_url'],
330
328
  patched_http_options['api_version'] + '/' + path,
@@ -22,9 +22,9 @@ import pydantic
22
22
  from . import types
23
23
 
24
24
  if sys.version_info >= (3, 10):
25
- UnionType = builtin_types.UnionType
25
+ VersionedUnionType = builtin_types.UnionType
26
26
  else:
27
- UnionType = typing._UnionGenericAlias
27
+ VersionedUnionType = typing._UnionGenericAlias
28
28
 
29
29
  _py_builtin_type_to_schema_type = {
30
30
  str: 'STRING',
@@ -45,7 +45,8 @@ def _is_builtin_primitive_or_compound(
45
45
  def _raise_for_any_of_if_mldev(schema: types.Schema):
46
46
  if schema.any_of:
47
47
  raise ValueError(
48
- 'AnyOf is not supported in function declaration schema for Google AI.'
48
+ 'AnyOf is not supported in function declaration schema for'
49
+ ' the Gemini API.'
49
50
  )
50
51
 
51
52
 
@@ -53,15 +54,7 @@ def _raise_for_default_if_mldev(schema: types.Schema):
53
54
  if schema.default is not None:
54
55
  raise ValueError(
55
56
  'Default value is not supported in function declaration schema for'
56
- ' Google AI.'
57
- )
58
-
59
-
60
- def _raise_for_nullable_if_mldev(schema: types.Schema):
61
- if schema.nullable:
62
- raise ValueError(
63
- 'Nullable is not supported in function declaration schema for'
64
- ' Google AI.'
57
+ ' the Gemini API.'
65
58
  )
66
59
 
67
60
 
@@ -69,7 +62,6 @@ def _raise_if_schema_unsupported(client, schema: types.Schema):
69
62
  if not client.vertexai:
70
63
  _raise_for_any_of_if_mldev(schema)
71
64
  _raise_for_default_if_mldev(schema)
72
- _raise_for_nullable_if_mldev(schema)
73
65
 
74
66
 
75
67
  def _is_default_value_compatible(
@@ -82,10 +74,10 @@ def _is_default_value_compatible(
82
74
  if (
83
75
  isinstance(annotation, _GenericAlias)
84
76
  or isinstance(annotation, builtin_types.GenericAlias)
85
- or isinstance(annotation, UnionType)
77
+ or isinstance(annotation, VersionedUnionType)
86
78
  ):
87
79
  origin = get_origin(annotation)
88
- if origin in (Union, UnionType):
80
+ if origin in (Union, VersionedUnionType):
89
81
  return any(
90
82
  _is_default_value_compatible(default_value, arg)
91
83
  for arg in get_args(annotation)
@@ -141,7 +133,7 @@ def _parse_schema_from_parameter(
141
133
  _raise_if_schema_unsupported(client, schema)
142
134
  return schema
143
135
  if (
144
- isinstance(param.annotation, UnionType)
136
+ isinstance(param.annotation, VersionedUnionType)
145
137
  # only parse simple UnionType, example int | str | float | bool
146
138
  # complex UnionType will be invoked in raise branch
147
139
  and all(
@@ -229,7 +221,11 @@ def _parse_schema_from_parameter(
229
221
  schema.type = 'OBJECT'
230
222
  unique_types = set()
231
223
  for arg in args:
232
- if arg.__name__ == 'NoneType': # Optional type
224
+ # The first check is for NoneType in Python 3.9, since the __name__
225
+ # attribute is not available in Python 3.9
226
+ if type(arg) is type(None) or (
227
+ hasattr(arg, '__name__') and arg.__name__ == 'NoneType'
228
+ ): # Optional type
233
229
  schema.nullable = True
234
230
  continue
235
231
  schema_in_any_of = _parse_schema_from_parameter(
google/genai/_common.py CHANGED
@@ -21,6 +21,7 @@ import enum
21
21
  import typing
22
22
  from typing import Union
23
23
  import uuid
24
+ import warnings
24
25
 
25
26
  import pydantic
26
27
  from pydantic import alias_generators
@@ -213,8 +214,16 @@ class CaseInSensitiveEnum(str, enum.Enum):
213
214
  except KeyError:
214
215
  try:
215
216
  return cls[value.lower()] # Try to access directly with lowercase
216
- except KeyError as e:
217
- raise ValueError(f"{value} is not a valid {cls.__name__}") from e
217
+ except KeyError:
218
+ warnings.warn(f"{value} is not a valid {cls.__name__}")
219
+ try:
220
+ # Creating a enum instance based on the value
221
+ unknown_enum_val = cls._new_member_(cls) # pylint: disable=protected-access,attribute-error
222
+ unknown_enum_val._name_ = str(value) # pylint: disable=protected-access
223
+ unknown_enum_val._value_ = value # pylint: disable=protected-access
224
+ return unknown_enum_val
225
+ except:
226
+ return None
218
227
 
219
228
 
220
229
  def timestamped_unique_name() -> str:
@@ -0,0 +1,365 @@
1
+ # Copyright 2024 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ #
15
+
16
+ # Code generated by the Google Gen AI SDK generator DO NOT EDIT.
17
+
18
+ from typing import Optional, Union
19
+ from urllib.parse import urlencode
20
+ from . import _api_module
21
+ from . import _common
22
+ from . import types
23
+ from ._api_client import ApiClient
24
+ from ._common import get_value_by_path as getv
25
+ from ._common import set_value_by_path as setv
26
+
27
+
28
+ def _GetOperationParameters_to_mldev(
29
+ api_client: ApiClient,
30
+ from_object: Union[dict, object],
31
+ parent_object: dict = None,
32
+ ) -> dict:
33
+ to_object = {}
34
+ if getv(from_object, ['operation_name']) is not None:
35
+ setv(
36
+ to_object,
37
+ ['_url', 'operationName'],
38
+ getv(from_object, ['operation_name']),
39
+ )
40
+
41
+ if getv(from_object, ['config']) is not None:
42
+ setv(to_object, ['config'], getv(from_object, ['config']))
43
+
44
+ return to_object
45
+
46
+
47
+ def _GetOperationParameters_to_vertex(
48
+ api_client: ApiClient,
49
+ from_object: Union[dict, object],
50
+ parent_object: dict = None,
51
+ ) -> dict:
52
+ to_object = {}
53
+ if getv(from_object, ['operation_name']) is not None:
54
+ setv(
55
+ to_object,
56
+ ['_url', 'operationName'],
57
+ getv(from_object, ['operation_name']),
58
+ )
59
+
60
+ if getv(from_object, ['config']) is not None:
61
+ setv(to_object, ['config'], getv(from_object, ['config']))
62
+
63
+ return to_object
64
+
65
+
66
+ def _FetchPredictOperationParameters_to_mldev(
67
+ api_client: ApiClient,
68
+ from_object: Union[dict, object],
69
+ parent_object: dict = None,
70
+ ) -> dict:
71
+ to_object = {}
72
+ if getv(from_object, ['operation_name']) is not None:
73
+ raise ValueError('operation_name parameter is not supported in Gemini API.')
74
+
75
+ if getv(from_object, ['resource_name']) is not None:
76
+ raise ValueError('resource_name parameter is not supported in Gemini API.')
77
+
78
+ if getv(from_object, ['config']) is not None:
79
+ raise ValueError('config parameter is not supported in Gemini API.')
80
+
81
+ return to_object
82
+
83
+
84
+ def _FetchPredictOperationParameters_to_vertex(
85
+ api_client: ApiClient,
86
+ from_object: Union[dict, object],
87
+ parent_object: dict = None,
88
+ ) -> dict:
89
+ to_object = {}
90
+ if getv(from_object, ['operation_name']) is not None:
91
+ setv(to_object, ['operationName'], getv(from_object, ['operation_name']))
92
+
93
+ if getv(from_object, ['resource_name']) is not None:
94
+ setv(
95
+ to_object,
96
+ ['_url', 'resourceName'],
97
+ getv(from_object, ['resource_name']),
98
+ )
99
+
100
+ if getv(from_object, ['config']) is not None:
101
+ setv(to_object, ['config'], getv(from_object, ['config']))
102
+
103
+ return to_object
104
+
105
+
106
+ def _Operation_from_mldev(
107
+ api_client: ApiClient,
108
+ from_object: Union[dict, object],
109
+ parent_object: dict = None,
110
+ ) -> dict:
111
+ to_object = {}
112
+ if getv(from_object, ['name']) is not None:
113
+ setv(to_object, ['name'], getv(from_object, ['name']))
114
+
115
+ if getv(from_object, ['metadata']) is not None:
116
+ setv(to_object, ['metadata'], getv(from_object, ['metadata']))
117
+
118
+ if getv(from_object, ['done']) is not None:
119
+ setv(to_object, ['done'], getv(from_object, ['done']))
120
+
121
+ if getv(from_object, ['error']) is not None:
122
+ setv(to_object, ['error'], getv(from_object, ['error']))
123
+
124
+ if getv(from_object, ['response']) is not None:
125
+ setv(to_object, ['response'], getv(from_object, ['response']))
126
+
127
+ return to_object
128
+
129
+
130
+ def _Operation_from_vertex(
131
+ api_client: ApiClient,
132
+ from_object: Union[dict, object],
133
+ parent_object: dict = None,
134
+ ) -> dict:
135
+ to_object = {}
136
+ if getv(from_object, ['name']) is not None:
137
+ setv(to_object, ['name'], getv(from_object, ['name']))
138
+
139
+ if getv(from_object, ['metadata']) is not None:
140
+ setv(to_object, ['metadata'], getv(from_object, ['metadata']))
141
+
142
+ if getv(from_object, ['done']) is not None:
143
+ setv(to_object, ['done'], getv(from_object, ['done']))
144
+
145
+ if getv(from_object, ['error']) is not None:
146
+ setv(to_object, ['error'], getv(from_object, ['error']))
147
+
148
+ if getv(from_object, ['response']) is not None:
149
+ setv(to_object, ['response'], getv(from_object, ['response']))
150
+
151
+ return to_object
152
+
153
+
154
+ class _operations(_api_module.BaseModule):
155
+
156
+ def _get_operation(
157
+ self,
158
+ *,
159
+ operation_name: str,
160
+ config: Optional[types.GetOperationConfigOrDict] = None,
161
+ ) -> types.Operation:
162
+ parameter_model = types._GetOperationParameters(
163
+ operation_name=operation_name,
164
+ config=config,
165
+ )
166
+
167
+ if self._api_client.vertexai:
168
+ request_dict = _GetOperationParameters_to_vertex(
169
+ self._api_client, parameter_model
170
+ )
171
+ path = '{operationName}'.format_map(request_dict.get('_url'))
172
+ else:
173
+ request_dict = _GetOperationParameters_to_mldev(
174
+ self._api_client, parameter_model
175
+ )
176
+ path = '{operationName}'.format_map(request_dict.get('_url'))
177
+ query_params = request_dict.get('_query')
178
+ if query_params:
179
+ path = f'{path}?{urlencode(query_params)}'
180
+ # TODO: remove the hack that pops config.
181
+ request_dict.pop('config', None)
182
+
183
+ http_options = None
184
+ if isinstance(config, dict):
185
+ http_options = config.get('http_options', None)
186
+ elif hasattr(config, 'http_options'):
187
+ http_options = config.http_options
188
+
189
+ request_dict = _common.convert_to_dict(request_dict)
190
+ request_dict = _common.encode_unserializable_types(request_dict)
191
+
192
+ response_dict = self._api_client.request(
193
+ 'get', path, request_dict, http_options
194
+ )
195
+
196
+ if self._api_client.vertexai:
197
+ response_dict = _Operation_from_vertex(self._api_client, response_dict)
198
+ else:
199
+ response_dict = _Operation_from_mldev(self._api_client, response_dict)
200
+
201
+ return_value = types.Operation._from_response(
202
+ response=response_dict, kwargs=parameter_model
203
+ )
204
+ self._api_client._verify_response(return_value)
205
+ return return_value
206
+
207
+ def _fetch_predict_operation(
208
+ self,
209
+ *,
210
+ operation_name: str,
211
+ resource_name: str,
212
+ config: Optional[types.FetchPredictOperationConfigOrDict] = None,
213
+ ) -> types.Operation:
214
+ parameter_model = types._FetchPredictOperationParameters(
215
+ operation_name=operation_name,
216
+ resource_name=resource_name,
217
+ config=config,
218
+ )
219
+
220
+ if not self._api_client.vertexai:
221
+ raise ValueError('This method is only supported in the Vertex AI client.')
222
+ else:
223
+ request_dict = _FetchPredictOperationParameters_to_vertex(
224
+ self._api_client, parameter_model
225
+ )
226
+ path = '{resourceName}:fetchPredictOperation'.format_map(
227
+ request_dict.get('_url')
228
+ )
229
+
230
+ query_params = request_dict.get('_query')
231
+ if query_params:
232
+ path = f'{path}?{urlencode(query_params)}'
233
+ # TODO: remove the hack that pops config.
234
+ request_dict.pop('config', None)
235
+
236
+ http_options = None
237
+ if isinstance(config, dict):
238
+ http_options = config.get('http_options', None)
239
+ elif hasattr(config, 'http_options'):
240
+ http_options = config.http_options
241
+
242
+ request_dict = _common.convert_to_dict(request_dict)
243
+ request_dict = _common.encode_unserializable_types(request_dict)
244
+
245
+ response_dict = self._api_client.request(
246
+ 'post', path, request_dict, http_options
247
+ )
248
+
249
+ if self._api_client.vertexai:
250
+ response_dict = _Operation_from_vertex(self._api_client, response_dict)
251
+ else:
252
+ response_dict = _Operation_from_mldev(self._api_client, response_dict)
253
+
254
+ return_value = types.Operation._from_response(
255
+ response=response_dict, kwargs=parameter_model
256
+ )
257
+ self._api_client._verify_response(return_value)
258
+ return return_value
259
+
260
+
261
+ class Async_operations(_api_module.BaseModule):
262
+
263
+ async def _get_operation(
264
+ self,
265
+ *,
266
+ operation_name: str,
267
+ config: Optional[types.GetOperationConfigOrDict] = None,
268
+ ) -> types.Operation:
269
+ parameter_model = types._GetOperationParameters(
270
+ operation_name=operation_name,
271
+ config=config,
272
+ )
273
+
274
+ if self._api_client.vertexai:
275
+ request_dict = _GetOperationParameters_to_vertex(
276
+ self._api_client, parameter_model
277
+ )
278
+ path = '{operationName}'.format_map(request_dict.get('_url'))
279
+ else:
280
+ request_dict = _GetOperationParameters_to_mldev(
281
+ self._api_client, parameter_model
282
+ )
283
+ path = '{operationName}'.format_map(request_dict.get('_url'))
284
+ query_params = request_dict.get('_query')
285
+ if query_params:
286
+ path = f'{path}?{urlencode(query_params)}'
287
+ # TODO: remove the hack that pops config.
288
+ request_dict.pop('config', None)
289
+
290
+ http_options = None
291
+ if isinstance(config, dict):
292
+ http_options = config.get('http_options', None)
293
+ elif hasattr(config, 'http_options'):
294
+ http_options = config.http_options
295
+
296
+ request_dict = _common.convert_to_dict(request_dict)
297
+ request_dict = _common.encode_unserializable_types(request_dict)
298
+
299
+ response_dict = await self._api_client.async_request(
300
+ 'get', path, request_dict, http_options
301
+ )
302
+
303
+ if self._api_client.vertexai:
304
+ response_dict = _Operation_from_vertex(self._api_client, response_dict)
305
+ else:
306
+ response_dict = _Operation_from_mldev(self._api_client, response_dict)
307
+
308
+ return_value = types.Operation._from_response(
309
+ response=response_dict, kwargs=parameter_model
310
+ )
311
+ self._api_client._verify_response(return_value)
312
+ return return_value
313
+
314
+ async def _fetch_predict_operation(
315
+ self,
316
+ *,
317
+ operation_name: str,
318
+ resource_name: str,
319
+ config: Optional[types.FetchPredictOperationConfigOrDict] = None,
320
+ ) -> types.Operation:
321
+ parameter_model = types._FetchPredictOperationParameters(
322
+ operation_name=operation_name,
323
+ resource_name=resource_name,
324
+ config=config,
325
+ )
326
+
327
+ if not self._api_client.vertexai:
328
+ raise ValueError('This method is only supported in the Vertex AI client.')
329
+ else:
330
+ request_dict = _FetchPredictOperationParameters_to_vertex(
331
+ self._api_client, parameter_model
332
+ )
333
+ path = '{resourceName}:fetchPredictOperation'.format_map(
334
+ request_dict.get('_url')
335
+ )
336
+
337
+ query_params = request_dict.get('_query')
338
+ if query_params:
339
+ path = f'{path}?{urlencode(query_params)}'
340
+ # TODO: remove the hack that pops config.
341
+ request_dict.pop('config', None)
342
+
343
+ http_options = None
344
+ if isinstance(config, dict):
345
+ http_options = config.get('http_options', None)
346
+ elif hasattr(config, 'http_options'):
347
+ http_options = config.http_options
348
+
349
+ request_dict = _common.convert_to_dict(request_dict)
350
+ request_dict = _common.encode_unserializable_types(request_dict)
351
+
352
+ response_dict = await self._api_client.async_request(
353
+ 'post', path, request_dict, http_options
354
+ )
355
+
356
+ if self._api_client.vertexai:
357
+ response_dict = _Operation_from_vertex(self._api_client, response_dict)
358
+ else:
359
+ response_dict = _Operation_from_mldev(self._api_client, response_dict)
360
+
361
+ return_value = types.Operation._from_response(
362
+ response=response_dict, kwargs=parameter_model
363
+ )
364
+ self._api_client._verify_response(return_value)
365
+ return return_value
@@ -78,6 +78,11 @@ def _redact_request_url(url: str) -> str:
78
78
  '{VERTEX_URL_PREFIX}/',
79
79
  result,
80
80
  )
81
+ result = re.sub(
82
+ r'.*aiplatform.googleapis.com/[^/]+/',
83
+ '{VERTEX_URL_PREFIX}/',
84
+ result,
85
+ )
81
86
  result = re.sub(
82
87
  r'https://generativelanguage.googleapis.com/[^/]+',
83
88
  '{MLDEV_URL_PREFIX}',
@@ -34,10 +34,12 @@ import pydantic
34
34
  from . import _api_client
35
35
  from . import types
36
36
 
37
- if sys.version_info >= (3, 11):
38
- from types import UnionType
37
+ if sys.version_info >= (3, 10):
38
+ VersionedUnionType = typing.types.UnionType
39
+ _UNION_TYPES = (typing.Union, typing.types.UnionType)
39
40
  else:
40
- UnionType = typing._UnionGenericAlias
41
+ VersionedUnionType = typing._UnionGenericAlias
42
+ _UNION_TYPES = (typing.Union,)
41
43
 
42
44
 
43
45
  def _resource_name(
@@ -225,6 +227,7 @@ PartType = Union[types.Part, types.PartDict, str, 'PIL.Image.Image']
225
227
  def t_part(client: _api_client.ApiClient, part: PartType) -> types.Part:
226
228
  try:
227
229
  import PIL.Image
230
+
228
231
  PIL_Image = PIL.Image.Image
229
232
  except ImportError:
230
233
  PIL_Image = None
@@ -342,7 +345,7 @@ def handle_null_fields(schema: dict[str, Any]):
342
345
  "type": "null"
343
346
  }
344
347
  ],
345
- "default": null,
348
+ "default": None,
346
349
  "title": "Total Area Sq Mi"
347
350
  }
348
351
  }
@@ -356,16 +359,12 @@ def handle_null_fields(schema: dict[str, Any]):
356
359
  "total_area_sq_mi": {
357
360
  "type": "integer",
358
361
  "nullable": true,
359
- "default": null,
362
+ "default": None,
360
363
  "title": "Total Area Sq Mi"
361
364
  }
362
365
  }
363
366
  """
364
- if (
365
- isinstance(schema, dict)
366
- and 'type' in schema
367
- and schema['type'] == 'null'
368
- ):
367
+ if schema.get('type', None) == 'null':
369
368
  schema['nullable'] = True
370
369
  del schema['type']
371
370
  elif 'anyOf' in schema:
@@ -445,6 +444,11 @@ def process_schema(
445
444
  if client and not client.vertexai:
446
445
  schema.pop('title', None)
447
446
 
447
+ if schema.get('default') is not None:
448
+ raise ValueError(
449
+ 'Default value is not supported in the response schema for the Gemmini API.'
450
+ )
451
+
448
452
  if defs is None:
449
453
  defs = schema.pop('$defs', {})
450
454
  for _, sub_schema in defs.items():
@@ -454,8 +458,19 @@ def process_schema(
454
458
 
455
459
  any_of = schema.get('anyOf', None)
456
460
  if any_of is not None:
461
+ if not client.vertexai:
462
+ raise ValueError(
463
+ 'AnyOf is not supported in the response schema for the Gemini API.'
464
+ )
457
465
  for sub_schema in any_of:
458
- process_schema(sub_schema, client, defs)
466
+ # $ref is present in any_of if the schema is a union of Pydantic classes
467
+ ref_key = sub_schema.get('$ref', None)
468
+ if ref_key is None:
469
+ process_schema(sub_schema, client, defs)
470
+ else:
471
+ ref = defs[ref_key.split('defs/')[-1]]
472
+ any_of.append(ref)
473
+ schema['anyOf'] = [item for item in any_of if '$ref' not in item]
459
474
  return
460
475
 
461
476
  schema_type = schema.get('type', None)
@@ -526,15 +541,18 @@ def t_schema(
526
541
  if (
527
542
  # in Python 3.9 Generic alias list[int] counts as a type,
528
543
  # and breaks issubclass because it's not a class.
529
- not isinstance(origin, GenericAlias) and
530
- isinstance(origin, type) and
544
+ not isinstance(origin, GenericAlias) and
545
+ isinstance(origin, type) and
531
546
  issubclass(origin, pydantic.BaseModel)
532
547
  ):
533
548
  schema = origin.model_json_schema()
534
549
  process_schema(schema, client)
535
550
  return types.Schema.model_validate(schema)
536
551
  elif (
537
- isinstance(origin, GenericAlias) or isinstance(origin, type) or isinstance(origin, UnionType)
552
+ isinstance(origin, GenericAlias)
553
+ or isinstance(origin, type)
554
+ or isinstance(origin, VersionedUnionType)
555
+ or typing.get_origin(origin) in _UNION_TYPES
538
556
  ):
539
557
  class Placeholder(pydantic.BaseModel):
540
558
  placeholder: origin