google-genai 1.46.0__py3-none-any.whl → 1.47.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.
@@ -599,7 +599,7 @@ class BaseApiClient:
599
599
  # Handle when to use Vertex AI in express mode (api key).
600
600
  # Explicit initializer arguments are already validated above.
601
601
  if self.vertexai:
602
- if credentials:
602
+ if credentials and env_api_key:
603
603
  # Explicit credentials take precedence over implicit api_key.
604
604
  logger.info(
605
605
  'The user provided Google Cloud credentials will take precedence'
@@ -629,6 +629,9 @@ class BaseApiClient:
629
629
  )
630
630
  self.api_key = None
631
631
 
632
+ if not self.location and not self.api_key:
633
+ self.location = 'global'
634
+
632
635
  self.custom_base_url = (
633
636
  validated_http_options.base_url
634
637
  if validated_http_options.base_url
@@ -650,16 +653,19 @@ class BaseApiClient:
650
653
  if not has_sufficient_auth and not self.custom_base_url:
651
654
  # Skip sufficient auth check if base url is provided in http options.
652
655
  raise ValueError(
653
- 'Project and location or API key must be set when using the Vertex '
656
+ 'Project or API key must be set when using the Vertex '
654
657
  'AI API.'
655
658
  )
656
659
  if self.api_key or self.location == 'global':
657
660
  self._http_options.base_url = f'https://aiplatform.googleapis.com/'
658
- elif self.custom_base_url and not has_sufficient_auth:
661
+ elif self.custom_base_url and not ((project and location) or api_key):
659
662
  # Avoid setting default base url and api version if base_url provided.
660
663
  # API gateway proxy can use the auth in custom headers, not url.
661
664
  # Enable custom url if auth is not sufficient.
662
665
  self._http_options.base_url = self.custom_base_url
666
+ # Clear project and location if base_url is provided.
667
+ self.project = None
668
+ self.location = None
663
669
  else:
664
670
  self._http_options.base_url = (
665
671
  f'https://{self.location}-aiplatform.googleapis.com/'
@@ -703,10 +709,15 @@ class BaseApiClient:
703
709
  else:
704
710
  self._async_httpx_client = AsyncHttpxClient(**async_client_args)
705
711
  if self._use_aiohttp():
706
- # Do it once at the genai.Client level. Share among all requests.
707
- self._async_client_session_request_args = self._ensure_aiohttp_ssl_ctx(
708
- self._http_options
709
- )
712
+ try:
713
+ import aiohttp # pylint: disable=g-import-not-at-top
714
+ # Do it once at the genai.Client level. Share among all requests.
715
+ self._async_client_session_request_args = self._ensure_aiohttp_ssl_ctx(
716
+ self._http_options
717
+ )
718
+ except ImportError:
719
+ pass
720
+
710
721
  # Initialize the aiohttp client session.
711
722
  self._aiohttp_session: Optional[aiohttp.ClientSession] = None
712
723
 
@@ -911,6 +922,7 @@ class BaseApiClient:
911
922
  has_aiohttp
912
923
  and (self._http_options.async_client_args or {}).get('transport')
913
924
  is None
925
+ and (self._http_options.httpx_async_client is None)
914
926
  )
915
927
 
916
928
  def _websocket_base_url(self) -> str:
@@ -1056,11 +1068,16 @@ class BaseApiClient:
1056
1068
  _common.recursive_dict_update(
1057
1069
  request_dict, patched_http_options.extra_body
1058
1070
  )
1059
-
1060
- url = join_url_path(
1061
- base_url,
1062
- versioned_path,
1063
- )
1071
+ url = base_url
1072
+ if (
1073
+ not self.custom_base_url
1074
+ or (self.project and self.location)
1075
+ or self.api_key
1076
+ ):
1077
+ url = join_url_path(
1078
+ base_url,
1079
+ versioned_path,
1080
+ )
1064
1081
 
1065
1082
  if self.api_key and self.api_key.startswith('auth_tokens/'):
1066
1083
  raise EphemeralTokenAPIKeyError(
@@ -1807,11 +1824,17 @@ class BaseApiClient:
1807
1824
  """
1808
1825
 
1809
1826
  try:
1810
- self.close()
1827
+ # Let users close the custom client explicitly by themselves. Otherwise,
1828
+ # close the client when the object is garbage collected.
1829
+ if not self._http_options.httpx_client:
1830
+ self.close()
1811
1831
  except Exception: # pylint: disable=broad-except
1812
1832
  pass
1813
1833
 
1814
1834
  try:
1815
- asyncio.get_running_loop().create_task(self.aclose())
1835
+ # Let users close the custom client explicitly by themselves. Otherwise,
1836
+ # close the client when the object is garbage collected.
1837
+ if not self._http_options.httpx_async_client:
1838
+ asyncio.get_running_loop().create_task(self.aclose())
1816
1839
  except Exception: # pylint: disable=broad-except
1817
- pass
1840
+ pass
@@ -611,4 +611,8 @@ def prepare_resumable_upload(
611
611
  'X-Goog-Upload-Header-Content-Type': f'{mime_type}',
612
612
  },
613
613
  )
614
+ if isinstance(file, (str, os.PathLike)):
615
+ if http_options.headers is None:
616
+ http_options.headers = {}
617
+ http_options.headers['X-Goog-Upload-File-Name'] = os.path.basename(file)
614
618
  return http_options, size_bytes, mime_type
@@ -28,12 +28,12 @@ def _Blob_to_mldev(
28
28
  parent_object: Optional[dict[str, Any]] = None,
29
29
  ) -> dict[str, Any]:
30
30
  to_object: dict[str, Any] = {}
31
- if getv(from_object, ['display_name']) is not None:
32
- raise ValueError('display_name parameter is not supported in Gemini API.')
33
-
34
31
  if getv(from_object, ['data']) is not None:
35
32
  setv(to_object, ['data'], getv(from_object, ['data']))
36
33
 
34
+ if getv(from_object, ['display_name']) is not None:
35
+ raise ValueError('display_name parameter is not supported in Gemini API.')
36
+
37
37
  if getv(from_object, ['mime_type']) is not None:
38
38
  setv(to_object, ['mimeType'], getv(from_object, ['mime_type']))
39
39
 
@@ -253,16 +253,16 @@ def _GoogleSearch_to_mldev(
253
253
  parent_object: Optional[dict[str, Any]] = None,
254
254
  ) -> dict[str, Any]:
255
255
  to_object: dict[str, Any] = {}
256
- if getv(from_object, ['time_range_filter']) is not None:
257
- setv(
258
- to_object, ['timeRangeFilter'], getv(from_object, ['time_range_filter'])
259
- )
260
-
261
256
  if getv(from_object, ['exclude_domains']) is not None:
262
257
  raise ValueError(
263
258
  'exclude_domains parameter is not supported in Gemini API.'
264
259
  )
265
260
 
261
+ if getv(from_object, ['time_range_filter']) is not None:
262
+ setv(
263
+ to_object, ['timeRangeFilter'], getv(from_object, ['time_range_filter'])
264
+ )
265
+
266
266
  return to_object
267
267
 
268
268
 
@@ -1156,19 +1156,19 @@ def _Part_to_mldev(
1156
1156
  parent_object: Optional[dict[str, Any]] = None,
1157
1157
  ) -> dict[str, Any]:
1158
1158
  to_object: dict[str, Any] = {}
1159
- if getv(from_object, ['video_metadata']) is not None:
1160
- setv(to_object, ['videoMetadata'], getv(from_object, ['video_metadata']))
1161
-
1162
- if getv(from_object, ['thought']) is not None:
1163
- setv(to_object, ['thought'], getv(from_object, ['thought']))
1159
+ if getv(from_object, ['function_call']) is not None:
1160
+ setv(to_object, ['functionCall'], getv(from_object, ['function_call']))
1164
1161
 
1165
- if getv(from_object, ['inline_data']) is not None:
1162
+ if getv(from_object, ['code_execution_result']) is not None:
1166
1163
  setv(
1167
1164
  to_object,
1168
- ['inlineData'],
1169
- _Blob_to_mldev(getv(from_object, ['inline_data']), to_object),
1165
+ ['codeExecutionResult'],
1166
+ getv(from_object, ['code_execution_result']),
1170
1167
  )
1171
1168
 
1169
+ if getv(from_object, ['executable_code']) is not None:
1170
+ setv(to_object, ['executableCode'], getv(from_object, ['executable_code']))
1171
+
1172
1172
  if getv(from_object, ['file_data']) is not None:
1173
1173
  setv(
1174
1174
  to_object,
@@ -1176,35 +1176,35 @@ def _Part_to_mldev(
1176
1176
  _FileData_to_mldev(getv(from_object, ['file_data']), to_object),
1177
1177
  )
1178
1178
 
1179
- if getv(from_object, ['thought_signature']) is not None:
1179
+ if getv(from_object, ['function_response']) is not None:
1180
1180
  setv(
1181
1181
  to_object,
1182
- ['thoughtSignature'],
1183
- getv(from_object, ['thought_signature']),
1182
+ ['functionResponse'],
1183
+ getv(from_object, ['function_response']),
1184
1184
  )
1185
1185
 
1186
- if getv(from_object, ['function_call']) is not None:
1187
- setv(to_object, ['functionCall'], getv(from_object, ['function_call']))
1188
-
1189
- if getv(from_object, ['code_execution_result']) is not None:
1186
+ if getv(from_object, ['inline_data']) is not None:
1190
1187
  setv(
1191
1188
  to_object,
1192
- ['codeExecutionResult'],
1193
- getv(from_object, ['code_execution_result']),
1189
+ ['inlineData'],
1190
+ _Blob_to_mldev(getv(from_object, ['inline_data']), to_object),
1194
1191
  )
1195
1192
 
1196
- if getv(from_object, ['executable_code']) is not None:
1197
- setv(to_object, ['executableCode'], getv(from_object, ['executable_code']))
1193
+ if getv(from_object, ['text']) is not None:
1194
+ setv(to_object, ['text'], getv(from_object, ['text']))
1198
1195
 
1199
- if getv(from_object, ['function_response']) is not None:
1196
+ if getv(from_object, ['thought']) is not None:
1197
+ setv(to_object, ['thought'], getv(from_object, ['thought']))
1198
+
1199
+ if getv(from_object, ['thought_signature']) is not None:
1200
1200
  setv(
1201
1201
  to_object,
1202
- ['functionResponse'],
1203
- getv(from_object, ['function_response']),
1202
+ ['thoughtSignature'],
1203
+ getv(from_object, ['thought_signature']),
1204
1204
  )
1205
1205
 
1206
- if getv(from_object, ['text']) is not None:
1207
- setv(to_object, ['text'], getv(from_object, ['text']))
1206
+ if getv(from_object, ['video_metadata']) is not None:
1207
+ setv(to_object, ['videoMetadata'], getv(from_object, ['video_metadata']))
1208
1208
 
1209
1209
  return to_object
1210
1210
 
@@ -1228,6 +1228,9 @@ def _SpeechConfig_to_vertex(
1228
1228
  parent_object: Optional[dict[str, Any]] = None,
1229
1229
  ) -> dict[str, Any]:
1230
1230
  to_object: dict[str, Any] = {}
1231
+ if getv(from_object, ['language_code']) is not None:
1232
+ setv(to_object, ['languageCode'], getv(from_object, ['language_code']))
1233
+
1231
1234
  if getv(from_object, ['voice_config']) is not None:
1232
1235
  setv(to_object, ['voiceConfig'], getv(from_object, ['voice_config']))
1233
1236
 
@@ -1236,9 +1239,6 @@ def _SpeechConfig_to_vertex(
1236
1239
  'multi_speaker_voice_config parameter is not supported in Vertex AI.'
1237
1240
  )
1238
1241
 
1239
- if getv(from_object, ['language_code']) is not None:
1240
- setv(to_object, ['languageCode'], getv(from_object, ['language_code']))
1241
-
1242
1242
  return to_object
1243
1243
 
1244
1244
 
@@ -1257,13 +1257,6 @@ def _Tool_to_mldev(
1257
1257
  if getv(from_object, ['retrieval']) is not None:
1258
1258
  raise ValueError('retrieval parameter is not supported in Gemini API.')
1259
1259
 
1260
- if getv(from_object, ['google_search']) is not None:
1261
- setv(
1262
- to_object,
1263
- ['googleSearch'],
1264
- _GoogleSearch_to_mldev(getv(from_object, ['google_search']), to_object),
1265
- )
1266
-
1267
1260
  if getv(from_object, ['google_search_retrieval']) is not None:
1268
1261
  setv(
1269
1262
  to_object,
@@ -1271,11 +1264,6 @@ def _Tool_to_mldev(
1271
1264
  getv(from_object, ['google_search_retrieval']),
1272
1265
  )
1273
1266
 
1274
- if getv(from_object, ['enterprise_web_search']) is not None:
1275
- raise ValueError(
1276
- 'enterprise_web_search parameter is not supported in Gemini API.'
1277
- )
1278
-
1279
1267
  if getv(from_object, ['google_maps']) is not None:
1280
1268
  setv(
1281
1269
  to_object,
@@ -1283,15 +1271,27 @@ def _Tool_to_mldev(
1283
1271
  _GoogleMaps_to_mldev(getv(from_object, ['google_maps']), to_object),
1284
1272
  )
1285
1273
 
1286
- if getv(from_object, ['url_context']) is not None:
1287
- setv(to_object, ['urlContext'], getv(from_object, ['url_context']))
1288
-
1289
1274
  if getv(from_object, ['computer_use']) is not None:
1290
1275
  setv(to_object, ['computerUse'], getv(from_object, ['computer_use']))
1291
1276
 
1292
1277
  if getv(from_object, ['code_execution']) is not None:
1293
1278
  setv(to_object, ['codeExecution'], getv(from_object, ['code_execution']))
1294
1279
 
1280
+ if getv(from_object, ['enterprise_web_search']) is not None:
1281
+ raise ValueError(
1282
+ 'enterprise_web_search parameter is not supported in Gemini API.'
1283
+ )
1284
+
1285
+ if getv(from_object, ['google_search']) is not None:
1286
+ setv(
1287
+ to_object,
1288
+ ['googleSearch'],
1289
+ _GoogleSearch_to_mldev(getv(from_object, ['google_search']), to_object),
1290
+ )
1291
+
1292
+ if getv(from_object, ['url_context']) is not None:
1293
+ setv(to_object, ['urlContext'], getv(from_object, ['url_context']))
1294
+
1295
1295
  return to_object
1296
1296
 
1297
1297
 
@@ -1313,9 +1313,6 @@ def _Tool_to_vertex(
1313
1313
  if getv(from_object, ['retrieval']) is not None:
1314
1314
  setv(to_object, ['retrieval'], getv(from_object, ['retrieval']))
1315
1315
 
1316
- if getv(from_object, ['google_search']) is not None:
1317
- setv(to_object, ['googleSearch'], getv(from_object, ['google_search']))
1318
-
1319
1316
  if getv(from_object, ['google_search_retrieval']) is not None:
1320
1317
  setv(
1321
1318
  to_object,
@@ -1323,6 +1320,15 @@ def _Tool_to_vertex(
1323
1320
  getv(from_object, ['google_search_retrieval']),
1324
1321
  )
1325
1322
 
1323
+ if getv(from_object, ['google_maps']) is not None:
1324
+ setv(to_object, ['googleMaps'], getv(from_object, ['google_maps']))
1325
+
1326
+ if getv(from_object, ['computer_use']) is not None:
1327
+ setv(to_object, ['computerUse'], getv(from_object, ['computer_use']))
1328
+
1329
+ if getv(from_object, ['code_execution']) is not None:
1330
+ setv(to_object, ['codeExecution'], getv(from_object, ['code_execution']))
1331
+
1326
1332
  if getv(from_object, ['enterprise_web_search']) is not None:
1327
1333
  setv(
1328
1334
  to_object,
@@ -1330,18 +1336,12 @@ def _Tool_to_vertex(
1330
1336
  getv(from_object, ['enterprise_web_search']),
1331
1337
  )
1332
1338
 
1333
- if getv(from_object, ['google_maps']) is not None:
1334
- setv(to_object, ['googleMaps'], getv(from_object, ['google_maps']))
1339
+ if getv(from_object, ['google_search']) is not None:
1340
+ setv(to_object, ['googleSearch'], getv(from_object, ['google_search']))
1335
1341
 
1336
1342
  if getv(from_object, ['url_context']) is not None:
1337
1343
  setv(to_object, ['urlContext'], getv(from_object, ['url_context']))
1338
1344
 
1339
- if getv(from_object, ['computer_use']) is not None:
1340
- setv(to_object, ['computerUse'], getv(from_object, ['computer_use']))
1341
-
1342
- if getv(from_object, ['code_execution']) is not None:
1343
- setv(to_object, ['codeExecution'], getv(from_object, ['code_execution']))
1344
-
1345
1345
  return to_object
1346
1346
 
1347
1347
 
@@ -28,12 +28,12 @@ def _Blob_to_mldev(
28
28
  parent_object: Optional[dict[str, Any]] = None,
29
29
  ) -> dict[str, Any]:
30
30
  to_object: dict[str, Any] = {}
31
- if getv(from_object, ['display_name']) is not None:
32
- raise ValueError('display_name parameter is not supported in Gemini API.')
33
-
34
31
  if getv(from_object, ['data']) is not None:
35
32
  setv(to_object, ['data'], getv(from_object, ['data']))
36
33
 
34
+ if getv(from_object, ['display_name']) is not None:
35
+ raise ValueError('display_name parameter is not supported in Gemini API.')
36
+
37
37
  if getv(from_object, ['mime_type']) is not None:
38
38
  setv(to_object, ['mimeType'], getv(from_object, ['mime_type']))
39
39
 
@@ -167,16 +167,16 @@ def _GoogleSearch_to_mldev(
167
167
  parent_object: Optional[dict[str, Any]] = None,
168
168
  ) -> dict[str, Any]:
169
169
  to_object: dict[str, Any] = {}
170
- if getv(from_object, ['time_range_filter']) is not None:
171
- setv(
172
- to_object, ['timeRangeFilter'], getv(from_object, ['time_range_filter'])
173
- )
174
-
175
170
  if getv(from_object, ['exclude_domains']) is not None:
176
171
  raise ValueError(
177
172
  'exclude_domains parameter is not supported in Gemini API.'
178
173
  )
179
174
 
175
+ if getv(from_object, ['time_range_filter']) is not None:
176
+ setv(
177
+ to_object, ['timeRangeFilter'], getv(from_object, ['time_range_filter'])
178
+ )
179
+
180
180
  return to_object
181
181
 
182
182
 
@@ -360,19 +360,19 @@ def _Part_to_mldev(
360
360
  parent_object: Optional[dict[str, Any]] = None,
361
361
  ) -> dict[str, Any]:
362
362
  to_object: dict[str, Any] = {}
363
- if getv(from_object, ['video_metadata']) is not None:
364
- setv(to_object, ['videoMetadata'], getv(from_object, ['video_metadata']))
365
-
366
- if getv(from_object, ['thought']) is not None:
367
- setv(to_object, ['thought'], getv(from_object, ['thought']))
363
+ if getv(from_object, ['function_call']) is not None:
364
+ setv(to_object, ['functionCall'], getv(from_object, ['function_call']))
368
365
 
369
- if getv(from_object, ['inline_data']) is not None:
366
+ if getv(from_object, ['code_execution_result']) is not None:
370
367
  setv(
371
368
  to_object,
372
- ['inlineData'],
373
- _Blob_to_mldev(getv(from_object, ['inline_data']), to_object),
369
+ ['codeExecutionResult'],
370
+ getv(from_object, ['code_execution_result']),
374
371
  )
375
372
 
373
+ if getv(from_object, ['executable_code']) is not None:
374
+ setv(to_object, ['executableCode'], getv(from_object, ['executable_code']))
375
+
376
376
  if getv(from_object, ['file_data']) is not None:
377
377
  setv(
378
378
  to_object,
@@ -380,35 +380,35 @@ def _Part_to_mldev(
380
380
  _FileData_to_mldev(getv(from_object, ['file_data']), to_object),
381
381
  )
382
382
 
383
- if getv(from_object, ['thought_signature']) is not None:
383
+ if getv(from_object, ['function_response']) is not None:
384
384
  setv(
385
385
  to_object,
386
- ['thoughtSignature'],
387
- getv(from_object, ['thought_signature']),
386
+ ['functionResponse'],
387
+ getv(from_object, ['function_response']),
388
388
  )
389
389
 
390
- if getv(from_object, ['function_call']) is not None:
391
- setv(to_object, ['functionCall'], getv(from_object, ['function_call']))
392
-
393
- if getv(from_object, ['code_execution_result']) is not None:
390
+ if getv(from_object, ['inline_data']) is not None:
394
391
  setv(
395
392
  to_object,
396
- ['codeExecutionResult'],
397
- getv(from_object, ['code_execution_result']),
393
+ ['inlineData'],
394
+ _Blob_to_mldev(getv(from_object, ['inline_data']), to_object),
398
395
  )
399
396
 
400
- if getv(from_object, ['executable_code']) is not None:
401
- setv(to_object, ['executableCode'], getv(from_object, ['executable_code']))
397
+ if getv(from_object, ['text']) is not None:
398
+ setv(to_object, ['text'], getv(from_object, ['text']))
402
399
 
403
- if getv(from_object, ['function_response']) is not None:
400
+ if getv(from_object, ['thought']) is not None:
401
+ setv(to_object, ['thought'], getv(from_object, ['thought']))
402
+
403
+ if getv(from_object, ['thought_signature']) is not None:
404
404
  setv(
405
405
  to_object,
406
- ['functionResponse'],
407
- getv(from_object, ['function_response']),
406
+ ['thoughtSignature'],
407
+ getv(from_object, ['thought_signature']),
408
408
  )
409
409
 
410
- if getv(from_object, ['text']) is not None:
411
- setv(to_object, ['text'], getv(from_object, ['text']))
410
+ if getv(from_object, ['video_metadata']) is not None:
411
+ setv(to_object, ['videoMetadata'], getv(from_object, ['video_metadata']))
412
412
 
413
413
  return to_object
414
414
 
@@ -442,13 +442,6 @@ def _Tool_to_mldev(
442
442
  if getv(from_object, ['retrieval']) is not None:
443
443
  raise ValueError('retrieval parameter is not supported in Gemini API.')
444
444
 
445
- if getv(from_object, ['google_search']) is not None:
446
- setv(
447
- to_object,
448
- ['googleSearch'],
449
- _GoogleSearch_to_mldev(getv(from_object, ['google_search']), to_object),
450
- )
451
-
452
445
  if getv(from_object, ['google_search_retrieval']) is not None:
453
446
  setv(
454
447
  to_object,
@@ -456,11 +449,6 @@ def _Tool_to_mldev(
456
449
  getv(from_object, ['google_search_retrieval']),
457
450
  )
458
451
 
459
- if getv(from_object, ['enterprise_web_search']) is not None:
460
- raise ValueError(
461
- 'enterprise_web_search parameter is not supported in Gemini API.'
462
- )
463
-
464
452
  if getv(from_object, ['google_maps']) is not None:
465
453
  setv(
466
454
  to_object,
@@ -468,13 +456,25 @@ def _Tool_to_mldev(
468
456
  _GoogleMaps_to_mldev(getv(from_object, ['google_maps']), to_object),
469
457
  )
470
458
 
471
- if getv(from_object, ['url_context']) is not None:
472
- setv(to_object, ['urlContext'], getv(from_object, ['url_context']))
473
-
474
459
  if getv(from_object, ['computer_use']) is not None:
475
460
  setv(to_object, ['computerUse'], getv(from_object, ['computer_use']))
476
461
 
477
462
  if getv(from_object, ['code_execution']) is not None:
478
463
  setv(to_object, ['codeExecution'], getv(from_object, ['code_execution']))
479
464
 
465
+ if getv(from_object, ['enterprise_web_search']) is not None:
466
+ raise ValueError(
467
+ 'enterprise_web_search parameter is not supported in Gemini API.'
468
+ )
469
+
470
+ if getv(from_object, ['google_search']) is not None:
471
+ setv(
472
+ to_object,
473
+ ['googleSearch'],
474
+ _GoogleSearch_to_mldev(getv(from_object, ['google_search']), to_object),
475
+ )
476
+
477
+ if getv(from_object, ['url_context']) is not None:
478
+ setv(to_object, ['urlContext'], getv(from_object, ['url_context']))
479
+
480
480
  return to_object
@@ -91,7 +91,16 @@ def _is_duck_type_of(obj: Any, cls: type[pydantic.BaseModel]) -> bool:
91
91
  return False
92
92
 
93
93
  # Check if the object has all of the Pydantic model's defined fields.
94
- return all(hasattr(obj, field) for field in cls.model_fields)
94
+ all_matched = all(hasattr(obj, field) for field in cls.model_fields)
95
+ if not all_matched and isinstance(obj, pydantic.BaseModel):
96
+ # Check the other way around if obj is a Pydantic model.
97
+ # Check if the Pydantic model has all of the object's defined fields.
98
+ try:
99
+ obj_private = cls()
100
+ all_matched = all(hasattr(obj_private, f) for f in type(obj).model_fields)
101
+ except ValueError:
102
+ return False
103
+ return all_matched
95
104
 
96
105
 
97
106
  def _resource_name(