google-genai 1.53.0__py3-none-any.whl → 1.55.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 +1 -0
- google/genai/_api_client.py +6 -6
- google/genai/_interactions/__init__.py +117 -0
- google/genai/_interactions/_base_client.py +2019 -0
- google/genai/_interactions/_client.py +511 -0
- google/genai/_interactions/_compat.py +234 -0
- google/genai/_interactions/_constants.py +29 -0
- google/genai/_interactions/_exceptions.py +122 -0
- google/genai/_interactions/_files.py +139 -0
- google/genai/_interactions/_models.py +873 -0
- google/genai/_interactions/_qs.py +165 -0
- google/genai/_interactions/_resource.py +58 -0
- google/genai/_interactions/_response.py +847 -0
- google/genai/_interactions/_streaming.py +354 -0
- google/genai/_interactions/_types.py +276 -0
- google/genai/_interactions/_utils/__init__.py +79 -0
- google/genai/_interactions/_utils/_compat.py +61 -0
- google/genai/_interactions/_utils/_datetime_parse.py +151 -0
- google/genai/_interactions/_utils/_logs.py +40 -0
- google/genai/_interactions/_utils/_proxy.py +80 -0
- google/genai/_interactions/_utils/_reflection.py +57 -0
- google/genai/_interactions/_utils/_resources_proxy.py +39 -0
- google/genai/_interactions/_utils/_streams.py +27 -0
- google/genai/_interactions/_utils/_sync.py +73 -0
- google/genai/_interactions/_utils/_transform.py +472 -0
- google/genai/_interactions/_utils/_typing.py +172 -0
- google/genai/_interactions/_utils/_utils.py +437 -0
- google/genai/_interactions/_version.py +18 -0
- google/genai/_interactions/resources/__init__.py +34 -0
- google/genai/_interactions/resources/interactions.py +1350 -0
- google/genai/_interactions/types/__init__.py +107 -0
- google/genai/_interactions/types/allowed_tools.py +33 -0
- google/genai/_interactions/types/allowed_tools_param.py +35 -0
- google/genai/_interactions/types/annotation.py +42 -0
- google/genai/_interactions/types/annotation_param.py +42 -0
- google/genai/_interactions/types/audio_content.py +38 -0
- google/genai/_interactions/types/audio_content_param.py +45 -0
- google/genai/_interactions/types/audio_mime_type.py +25 -0
- google/genai/_interactions/types/audio_mime_type_param.py +27 -0
- google/genai/_interactions/types/code_execution_call_arguments.py +33 -0
- google/genai/_interactions/types/code_execution_call_arguments_param.py +32 -0
- google/genai/_interactions/types/code_execution_call_content.py +37 -0
- google/genai/_interactions/types/code_execution_call_content_param.py +37 -0
- google/genai/_interactions/types/code_execution_result_content.py +42 -0
- google/genai/_interactions/types/code_execution_result_content_param.py +41 -0
- google/genai/_interactions/types/content_delta.py +358 -0
- google/genai/_interactions/types/content_start.py +79 -0
- google/genai/_interactions/types/content_stop.py +35 -0
- google/genai/_interactions/types/deep_research_agent_config.py +33 -0
- google/genai/_interactions/types/deep_research_agent_config_param.py +32 -0
- google/genai/_interactions/types/document_content.py +36 -0
- google/genai/_interactions/types/document_content_param.py +43 -0
- google/genai/_interactions/types/dynamic_agent_config.py +44 -0
- google/genai/_interactions/types/dynamic_agent_config_param.py +33 -0
- google/genai/_interactions/types/error_event.py +46 -0
- google/genai/_interactions/types/file_search_result_content.py +46 -0
- google/genai/_interactions/types/file_search_result_content_param.py +46 -0
- google/genai/_interactions/types/function.py +38 -0
- google/genai/_interactions/types/function_call_content.py +39 -0
- google/genai/_interactions/types/function_call_content_param.py +39 -0
- google/genai/_interactions/types/function_param.py +37 -0
- google/genai/_interactions/types/function_result_content.py +52 -0
- google/genai/_interactions/types/function_result_content_param.py +54 -0
- google/genai/_interactions/types/generation_config.py +57 -0
- google/genai/_interactions/types/generation_config_param.py +59 -0
- google/genai/_interactions/types/google_search_call_arguments.py +29 -0
- google/genai/_interactions/types/google_search_call_arguments_param.py +31 -0
- google/genai/_interactions/types/google_search_call_content.py +37 -0
- google/genai/_interactions/types/google_search_call_content_param.py +37 -0
- google/genai/_interactions/types/google_search_result.py +35 -0
- google/genai/_interactions/types/google_search_result_content.py +43 -0
- google/genai/_interactions/types/google_search_result_content_param.py +44 -0
- google/genai/_interactions/types/google_search_result_param.py +35 -0
- google/genai/_interactions/types/image_content.py +41 -0
- google/genai/_interactions/types/image_content_param.py +48 -0
- google/genai/_interactions/types/image_mime_type.py +23 -0
- google/genai/_interactions/types/image_mime_type_param.py +25 -0
- google/genai/_interactions/types/interaction.py +165 -0
- google/genai/_interactions/types/interaction_create_params.py +212 -0
- google/genai/_interactions/types/interaction_event.py +37 -0
- google/genai/_interactions/types/interaction_get_params.py +46 -0
- google/genai/_interactions/types/interaction_sse_event.py +32 -0
- google/genai/_interactions/types/interaction_status_update.py +37 -0
- google/genai/_interactions/types/mcp_server_tool_call_content.py +42 -0
- google/genai/_interactions/types/mcp_server_tool_call_content_param.py +42 -0
- google/genai/_interactions/types/mcp_server_tool_result_content.py +52 -0
- google/genai/_interactions/types/mcp_server_tool_result_content_param.py +54 -0
- google/genai/_interactions/types/model.py +36 -0
- google/genai/_interactions/types/model_param.py +38 -0
- google/genai/_interactions/types/speech_config.py +35 -0
- google/genai/_interactions/types/speech_config_param.py +35 -0
- google/genai/_interactions/types/text_content.py +37 -0
- google/genai/_interactions/types/text_content_param.py +38 -0
- google/genai/_interactions/types/thinking_level.py +22 -0
- google/genai/_interactions/types/thought_content.py +41 -0
- google/genai/_interactions/types/thought_content_param.py +47 -0
- google/genai/_interactions/types/tool.py +100 -0
- google/genai/_interactions/types/tool_choice.py +26 -0
- google/genai/_interactions/types/tool_choice_config.py +28 -0
- google/genai/_interactions/types/tool_choice_config_param.py +29 -0
- google/genai/_interactions/types/tool_choice_param.py +28 -0
- google/genai/_interactions/types/tool_choice_type.py +22 -0
- google/genai/_interactions/types/tool_param.py +97 -0
- google/genai/_interactions/types/turn.py +76 -0
- google/genai/_interactions/types/turn_param.py +73 -0
- google/genai/_interactions/types/url_context_call_arguments.py +29 -0
- google/genai/_interactions/types/url_context_call_arguments_param.py +31 -0
- google/genai/_interactions/types/url_context_call_content.py +37 -0
- google/genai/_interactions/types/url_context_call_content_param.py +37 -0
- google/genai/_interactions/types/url_context_result.py +33 -0
- google/genai/_interactions/types/url_context_result_content.py +43 -0
- google/genai/_interactions/types/url_context_result_content_param.py +44 -0
- google/genai/_interactions/types/url_context_result_param.py +32 -0
- google/genai/_interactions/types/usage.py +106 -0
- google/genai/_interactions/types/usage_param.py +106 -0
- google/genai/_interactions/types/video_content.py +41 -0
- google/genai/_interactions/types/video_content_param.py +48 -0
- google/genai/_interactions/types/video_mime_type.py +36 -0
- google/genai/_interactions/types/video_mime_type_param.py +38 -0
- google/genai/_live_converters.py +34 -3
- google/genai/_tokens_converters.py +5 -0
- google/genai/batches.py +62 -55
- google/genai/client.py +223 -0
- google/genai/errors.py +16 -1
- google/genai/file_search_stores.py +60 -60
- google/genai/files.py +56 -56
- google/genai/interactions.py +17 -0
- google/genai/live.py +4 -3
- google/genai/models.py +15 -3
- google/genai/tests/__init__.py +21 -0
- google/genai/tests/afc/__init__.py +21 -0
- google/genai/tests/afc/test_convert_if_exist_pydantic_model.py +309 -0
- google/genai/tests/afc/test_convert_number_values_for_function_call_args.py +63 -0
- google/genai/tests/afc/test_find_afc_incompatible_tool_indexes.py +240 -0
- google/genai/tests/afc/test_generate_content_stream_afc.py +530 -0
- google/genai/tests/afc/test_generate_content_stream_afc_thoughts.py +77 -0
- google/genai/tests/afc/test_get_function_map.py +176 -0
- google/genai/tests/afc/test_get_function_response_parts.py +277 -0
- google/genai/tests/afc/test_get_max_remote_calls_for_afc.py +130 -0
- google/genai/tests/afc/test_invoke_function_from_dict_args.py +241 -0
- google/genai/tests/afc/test_raise_error_for_afc_incompatible_config.py +159 -0
- google/genai/tests/afc/test_should_append_afc_history.py +53 -0
- google/genai/tests/afc/test_should_disable_afc.py +214 -0
- google/genai/tests/batches/__init__.py +17 -0
- google/genai/tests/batches/test_cancel.py +77 -0
- google/genai/tests/batches/test_create.py +78 -0
- google/genai/tests/batches/test_create_with_bigquery.py +113 -0
- google/genai/tests/batches/test_create_with_file.py +82 -0
- google/genai/tests/batches/test_create_with_gcs.py +125 -0
- google/genai/tests/batches/test_create_with_inlined_requests.py +255 -0
- google/genai/tests/batches/test_delete.py +86 -0
- google/genai/tests/batches/test_embedding.py +157 -0
- google/genai/tests/batches/test_get.py +78 -0
- google/genai/tests/batches/test_list.py +79 -0
- google/genai/tests/caches/__init__.py +17 -0
- google/genai/tests/caches/constants.py +29 -0
- google/genai/tests/caches/test_create.py +210 -0
- google/genai/tests/caches/test_create_custom_url.py +105 -0
- google/genai/tests/caches/test_delete.py +54 -0
- google/genai/tests/caches/test_delete_custom_url.py +52 -0
- google/genai/tests/caches/test_get.py +94 -0
- google/genai/tests/caches/test_get_custom_url.py +52 -0
- google/genai/tests/caches/test_list.py +68 -0
- google/genai/tests/caches/test_update.py +70 -0
- google/genai/tests/caches/test_update_custom_url.py +58 -0
- google/genai/tests/chats/__init__.py +1 -0
- google/genai/tests/chats/test_get_history.py +597 -0
- google/genai/tests/chats/test_send_message.py +844 -0
- google/genai/tests/chats/test_validate_response.py +90 -0
- google/genai/tests/client/__init__.py +17 -0
- google/genai/tests/client/test_async_stream.py +427 -0
- google/genai/tests/client/test_client_close.py +197 -0
- google/genai/tests/client/test_client_initialization.py +1687 -0
- google/genai/tests/client/test_client_requests.py +355 -0
- google/genai/tests/client/test_custom_client.py +77 -0
- google/genai/tests/client/test_http_options.py +178 -0
- google/genai/tests/client/test_replay_client_equality.py +168 -0
- google/genai/tests/client/test_retries.py +846 -0
- google/genai/tests/client/test_upload_errors.py +136 -0
- google/genai/tests/common/__init__.py +17 -0
- google/genai/tests/common/test_common.py +954 -0
- google/genai/tests/conftest.py +162 -0
- google/genai/tests/documents/__init__.py +17 -0
- google/genai/tests/documents/test_delete.py +51 -0
- google/genai/tests/documents/test_get.py +85 -0
- google/genai/tests/documents/test_list.py +72 -0
- google/genai/tests/errors/__init__.py +1 -0
- google/genai/tests/errors/test_api_error.py +417 -0
- google/genai/tests/file_search_stores/__init__.py +17 -0
- google/genai/tests/file_search_stores/test_create.py +66 -0
- google/genai/tests/file_search_stores/test_delete.py +64 -0
- google/genai/tests/file_search_stores/test_get.py +94 -0
- google/genai/tests/file_search_stores/test_import_file.py +112 -0
- google/genai/tests/file_search_stores/test_list.py +57 -0
- google/genai/tests/file_search_stores/test_upload_to_file_search_store.py +141 -0
- google/genai/tests/files/__init__.py +17 -0
- google/genai/tests/files/test_delete.py +46 -0
- google/genai/tests/files/test_download.py +85 -0
- google/genai/tests/files/test_get.py +46 -0
- google/genai/tests/files/test_list.py +72 -0
- google/genai/tests/files/test_upload.py +255 -0
- google/genai/tests/imports/test_no_optional_imports.py +28 -0
- google/genai/tests/interactions/__init__.py +0 -0
- google/genai/tests/interactions/test_integration.py +80 -0
- google/genai/tests/live/__init__.py +16 -0
- google/genai/tests/live/test_live.py +2177 -0
- google/genai/tests/live/test_live_music.py +362 -0
- google/genai/tests/live/test_live_response.py +163 -0
- google/genai/tests/live/test_send_client_content.py +147 -0
- google/genai/tests/live/test_send_realtime_input.py +268 -0
- google/genai/tests/live/test_send_tool_response.py +222 -0
- google/genai/tests/local_tokenizer/__init__.py +17 -0
- google/genai/tests/local_tokenizer/test_local_tokenizer.py +343 -0
- google/genai/tests/local_tokenizer/test_local_tokenizer_loader.py +235 -0
- google/genai/tests/mcp/__init__.py +17 -0
- google/genai/tests/mcp/test_has_mcp_tool_usage.py +89 -0
- google/genai/tests/mcp/test_mcp_to_gemini_tools.py +191 -0
- google/genai/tests/mcp/test_parse_config_for_mcp_sessions.py +201 -0
- google/genai/tests/mcp/test_parse_config_for_mcp_usage.py +130 -0
- google/genai/tests/mcp/test_set_mcp_usage_header.py +72 -0
- google/genai/tests/models/__init__.py +17 -0
- google/genai/tests/models/constants.py +8 -0
- google/genai/tests/models/test_compute_tokens.py +120 -0
- google/genai/tests/models/test_count_tokens.py +159 -0
- google/genai/tests/models/test_delete.py +107 -0
- google/genai/tests/models/test_edit_image.py +264 -0
- google/genai/tests/models/test_embed_content.py +94 -0
- google/genai/tests/models/test_function_call_streaming.py +442 -0
- google/genai/tests/models/test_generate_content.py +2502 -0
- google/genai/tests/models/test_generate_content_cached_content.py +132 -0
- google/genai/tests/models/test_generate_content_config_zero_value.py +103 -0
- google/genai/tests/models/test_generate_content_from_apikey.py +44 -0
- google/genai/tests/models/test_generate_content_http_options.py +40 -0
- google/genai/tests/models/test_generate_content_image_generation.py +143 -0
- google/genai/tests/models/test_generate_content_mcp.py +343 -0
- google/genai/tests/models/test_generate_content_media_resolution.py +97 -0
- google/genai/tests/models/test_generate_content_model.py +139 -0
- google/genai/tests/models/test_generate_content_part.py +821 -0
- google/genai/tests/models/test_generate_content_thought.py +76 -0
- google/genai/tests/models/test_generate_content_tools.py +1761 -0
- google/genai/tests/models/test_generate_images.py +191 -0
- google/genai/tests/models/test_generate_videos.py +759 -0
- google/genai/tests/models/test_get.py +104 -0
- google/genai/tests/models/test_list.py +233 -0
- google/genai/tests/models/test_recontext_image.py +189 -0
- google/genai/tests/models/test_segment_image.py +148 -0
- google/genai/tests/models/test_update.py +95 -0
- google/genai/tests/models/test_upscale_image.py +157 -0
- google/genai/tests/operations/__init__.py +17 -0
- google/genai/tests/operations/test_get.py +38 -0
- google/genai/tests/public_samples/__init__.py +17 -0
- google/genai/tests/public_samples/test_gemini_text_only.py +34 -0
- google/genai/tests/pytest_helper.py +229 -0
- google/genai/tests/shared/__init__.py +16 -0
- google/genai/tests/shared/batches/__init__.py +14 -0
- google/genai/tests/shared/batches/test_create_delete.py +57 -0
- google/genai/tests/shared/batches/test_create_get_cancel.py +56 -0
- google/genai/tests/shared/batches/test_list.py +40 -0
- google/genai/tests/shared/caches/__init__.py +14 -0
- google/genai/tests/shared/caches/test_create_get_delete.py +67 -0
- google/genai/tests/shared/caches/test_create_update_get.py +71 -0
- google/genai/tests/shared/caches/test_list.py +40 -0
- google/genai/tests/shared/chats/__init__.py +14 -0
- google/genai/tests/shared/chats/test_send_message.py +48 -0
- google/genai/tests/shared/chats/test_send_message_stream.py +50 -0
- google/genai/tests/shared/files/__init__.py +14 -0
- google/genai/tests/shared/files/test_list.py +41 -0
- google/genai/tests/shared/files/test_upload_get_delete.py +54 -0
- google/genai/tests/shared/models/__init__.py +14 -0
- google/genai/tests/shared/models/test_compute_tokens.py +41 -0
- google/genai/tests/shared/models/test_count_tokens.py +40 -0
- google/genai/tests/shared/models/test_edit_image.py +67 -0
- google/genai/tests/shared/models/test_embed.py +40 -0
- google/genai/tests/shared/models/test_generate_content.py +39 -0
- google/genai/tests/shared/models/test_generate_content_stream.py +54 -0
- google/genai/tests/shared/models/test_generate_images.py +40 -0
- google/genai/tests/shared/models/test_generate_videos.py +38 -0
- google/genai/tests/shared/models/test_list.py +37 -0
- google/genai/tests/shared/models/test_recontext_image.py +55 -0
- google/genai/tests/shared/models/test_segment_image.py +52 -0
- google/genai/tests/shared/models/test_upscale_image.py +52 -0
- google/genai/tests/shared/tunings/__init__.py +16 -0
- google/genai/tests/shared/tunings/test_create.py +46 -0
- google/genai/tests/shared/tunings/test_create_get_cancel.py +56 -0
- google/genai/tests/shared/tunings/test_list.py +39 -0
- google/genai/tests/tokens/__init__.py +16 -0
- google/genai/tests/tokens/test_create.py +154 -0
- google/genai/tests/transformers/__init__.py +17 -0
- google/genai/tests/transformers/test_blobs.py +71 -0
- google/genai/tests/transformers/test_bytes.py +15 -0
- google/genai/tests/transformers/test_duck_type.py +96 -0
- google/genai/tests/transformers/test_function_responses.py +72 -0
- google/genai/tests/transformers/test_schema.py +653 -0
- google/genai/tests/transformers/test_t_batch.py +286 -0
- google/genai/tests/transformers/test_t_content.py +160 -0
- google/genai/tests/transformers/test_t_contents.py +398 -0
- google/genai/tests/transformers/test_t_part.py +85 -0
- google/genai/tests/transformers/test_t_parts.py +87 -0
- google/genai/tests/transformers/test_t_tool.py +157 -0
- google/genai/tests/transformers/test_t_tools.py +195 -0
- google/genai/tests/tunings/__init__.py +16 -0
- google/genai/tests/tunings/test_cancel.py +39 -0
- google/genai/tests/tunings/test_end_to_end.py +106 -0
- google/genai/tests/tunings/test_get.py +67 -0
- google/genai/tests/tunings/test_list.py +75 -0
- google/genai/tests/tunings/test_tune.py +268 -0
- google/genai/tests/types/__init__.py +16 -0
- google/genai/tests/types/test_bytes_internal.py +271 -0
- google/genai/tests/types/test_bytes_type.py +152 -0
- google/genai/tests/types/test_future.py +101 -0
- google/genai/tests/types/test_optional_types.py +36 -0
- google/genai/tests/types/test_part_type.py +616 -0
- google/genai/tests/types/test_schema_from_json_schema.py +417 -0
- google/genai/tests/types/test_schema_json_schema.py +468 -0
- google/genai/tests/types/test_types.py +2903 -0
- google/genai/tunings.py +57 -57
- google/genai/types.py +229 -121
- google/genai/version.py +1 -1
- {google_genai-1.53.0.dist-info → google_genai-1.55.0.dist-info}/METADATA +4 -2
- google_genai-1.55.0.dist-info/RECORD +345 -0
- google_genai-1.53.0.dist-info/RECORD +0 -41
- {google_genai-1.53.0.dist-info → google_genai-1.55.0.dist-info}/WHEEL +0 -0
- {google_genai-1.53.0.dist-info → google_genai-1.55.0.dist-info}/licenses/LICENSE +0 -0
- {google_genai-1.53.0.dist-info → google_genai-1.55.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,653 @@
|
|
|
1
|
+
# Copyright 2025 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
|
+
|
|
17
|
+
"""Tests schema processing methods in the _transformers module."""
|
|
18
|
+
|
|
19
|
+
import copy
|
|
20
|
+
from typing import Union
|
|
21
|
+
|
|
22
|
+
import pydantic
|
|
23
|
+
import pytest
|
|
24
|
+
|
|
25
|
+
from ... import _transformers
|
|
26
|
+
from ... import client as google_genai_client_module
|
|
27
|
+
from ... import types
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class CurrencyInfo(pydantic.BaseModel):
|
|
31
|
+
name: str
|
|
32
|
+
code: str
|
|
33
|
+
symbol: str
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
currency_info_fields = CurrencyInfo.model_fields
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class CountryInfo(pydantic.BaseModel):
|
|
40
|
+
name: str
|
|
41
|
+
population: int
|
|
42
|
+
capital: str
|
|
43
|
+
continent: str
|
|
44
|
+
gdp: int
|
|
45
|
+
official_language: str
|
|
46
|
+
total_area_sq_mi: int
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
country_info_fields = CountryInfo.model_fields
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class CountryInfoWithCurrency(pydantic.BaseModel):
|
|
53
|
+
name: str
|
|
54
|
+
population: int
|
|
55
|
+
capital: str
|
|
56
|
+
continent: str
|
|
57
|
+
gdp: int
|
|
58
|
+
official_language: str
|
|
59
|
+
total_area_sq_mi: int
|
|
60
|
+
currency: CurrencyInfo
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
nested_country_info_fields = CountryInfoWithCurrency.model_fields
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class CountryInfoWithNullFields(pydantic.BaseModel):
|
|
67
|
+
name: str
|
|
68
|
+
population: Union[int, None] = None
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class CountryInfoWithDefaultValue(pydantic.BaseModel):
|
|
72
|
+
name: str
|
|
73
|
+
population: int = 0
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class CountryInfoWithAnyOf(pydantic.BaseModel):
|
|
77
|
+
name: str
|
|
78
|
+
restaurants_per_capita: Union[int, float]
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@pytest.fixture
|
|
82
|
+
@pytest.mark.parametrize('use_vertex', [True, False])
|
|
83
|
+
def client(use_vertex):
|
|
84
|
+
if use_vertex:
|
|
85
|
+
yield google_genai_client_module.Client(
|
|
86
|
+
vertexai=use_vertex, project='test-project', location='test-location'
|
|
87
|
+
)
|
|
88
|
+
else:
|
|
89
|
+
yield google_genai_client_module.Client(
|
|
90
|
+
vertexai=use_vertex, api_key='test-api-key'
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def test_build_schema_for_list_of_pydantic_schema(client):
|
|
95
|
+
"""Tests _build_schema() when list[pydantic.BaseModel] is provided to response_schema."""
|
|
96
|
+
|
|
97
|
+
list_schema = _transformers.t_schema(client, CountryInfo).model_dump()
|
|
98
|
+
|
|
99
|
+
assert isinstance(list_schema, dict)
|
|
100
|
+
|
|
101
|
+
for field_name in list_schema['properties']:
|
|
102
|
+
assert 'title' in list_schema['properties'][field_name]
|
|
103
|
+
assert 'type' in list_schema['properties'][field_name]
|
|
104
|
+
assert field_name in country_info_fields
|
|
105
|
+
field_type_str = country_info_fields[field_name].annotation.__name__
|
|
106
|
+
assert (
|
|
107
|
+
list_schema['properties'][field_name]['type']
|
|
108
|
+
.lower()
|
|
109
|
+
.startswith(field_type_str.lower())
|
|
110
|
+
)
|
|
111
|
+
assert 'required' in list_schema
|
|
112
|
+
assert list_schema['required'] == list(country_info_fields.keys())
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def test_build_schema_for_list_of_nested_pydantic_schema(client):
|
|
116
|
+
"""Tests _build_schema() when list[pydantic.BaseModel] is provided to response_schema and the pydantic.BaseModel has nested pydantic fields."""
|
|
117
|
+
list_schema = _transformers.t_schema(
|
|
118
|
+
client, CountryInfoWithCurrency
|
|
119
|
+
).model_dump()
|
|
120
|
+
|
|
121
|
+
assert isinstance(list_schema, dict)
|
|
122
|
+
|
|
123
|
+
for field_name in list_schema['properties']:
|
|
124
|
+
assert 'title' in list_schema['properties'][field_name]
|
|
125
|
+
assert 'type' in list_schema['properties'][field_name]
|
|
126
|
+
assert field_name in nested_country_info_fields
|
|
127
|
+
|
|
128
|
+
# Tested nested schema was created
|
|
129
|
+
assert 'properties' in list_schema['properties']['currency']
|
|
130
|
+
|
|
131
|
+
for field_name in list_schema['properties']['currency']['properties']:
|
|
132
|
+
assert field_name in currency_info_fields
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def test_t_schema_for_pydantic_schema(client):
|
|
136
|
+
"""Tests t_schema when pydantic.BaseModel is passed to response_schema."""
|
|
137
|
+
transformed_schema = _transformers.t_schema(client, CountryInfo)
|
|
138
|
+
assert isinstance(transformed_schema, types.Schema)
|
|
139
|
+
for schema_property in transformed_schema.properties:
|
|
140
|
+
assert schema_property in country_info_fields
|
|
141
|
+
assert isinstance(
|
|
142
|
+
transformed_schema.properties[schema_property], types.Schema
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def test_t_schema_for_list_of_pydantic_schema(client):
|
|
147
|
+
"""Tests t_schema when list[pydantic.BaseModel] is passed to response_schema."""
|
|
148
|
+
transformed_schema = _transformers.t_schema(client, list[CountryInfo])
|
|
149
|
+
assert isinstance(transformed_schema, types.Schema)
|
|
150
|
+
assert isinstance(transformed_schema.items, types.Schema)
|
|
151
|
+
|
|
152
|
+
for schema_property in transformed_schema.items.properties:
|
|
153
|
+
assert schema_property in country_info_fields
|
|
154
|
+
assert isinstance(
|
|
155
|
+
transformed_schema.items.properties[schema_property], types.Schema
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def test_t_schema_for_null_fields(client):
|
|
160
|
+
"""Tests t_schema when null fields are present."""
|
|
161
|
+
transformed_schema = _transformers.t_schema(client, CountryInfoWithNullFields)
|
|
162
|
+
assert isinstance(transformed_schema, types.Schema)
|
|
163
|
+
assert transformed_schema.properties['population'].nullable
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def test_schema_with_no_null_fields_is_unchanged():
|
|
167
|
+
"""Tests handle_null_fields() doesn't change anything when no null fields are present."""
|
|
168
|
+
test_properties = {
|
|
169
|
+
'name': {'title': 'Name', 'type': 'string'},
|
|
170
|
+
'total_area_sq_mi': {
|
|
171
|
+
'anyOf': [{'type': 'integer'}, {'type': 'float'}],
|
|
172
|
+
'default': 'null',
|
|
173
|
+
'title': 'Total Area Sq Mi',
|
|
174
|
+
},
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
for _, schema in test_properties.items():
|
|
178
|
+
schema_before = copy.deepcopy(schema)
|
|
179
|
+
_transformers.handle_null_fields(schema)
|
|
180
|
+
assert schema_before == schema
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
@pytest.mark.parametrize('use_vertex', [True, False])
|
|
184
|
+
def test_schema_with_default_value(client):
|
|
185
|
+
|
|
186
|
+
transformed_schema = _transformers.t_schema(
|
|
187
|
+
client._api_client, CountryInfoWithDefaultValue
|
|
188
|
+
)
|
|
189
|
+
expected_schema = types.Schema(
|
|
190
|
+
properties={
|
|
191
|
+
'name': types.Schema(
|
|
192
|
+
type='STRING',
|
|
193
|
+
title='Name',
|
|
194
|
+
),
|
|
195
|
+
'population': types.Schema(
|
|
196
|
+
type='INTEGER',
|
|
197
|
+
default=0,
|
|
198
|
+
title='Population',
|
|
199
|
+
),
|
|
200
|
+
},
|
|
201
|
+
type='OBJECT',
|
|
202
|
+
required=['name'],
|
|
203
|
+
title='CountryInfoWithDefaultValue',
|
|
204
|
+
property_ordering=['name', 'population'],
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
assert transformed_schema == expected_schema
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def test_schema_with_any_of(client):
|
|
211
|
+
transformed_schema = _transformers.t_schema(client, CountryInfoWithAnyOf)
|
|
212
|
+
expected_schema = types.Schema(
|
|
213
|
+
properties={
|
|
214
|
+
'name': types.Schema(
|
|
215
|
+
type='STRING',
|
|
216
|
+
title='Name',
|
|
217
|
+
),
|
|
218
|
+
'restaurants_per_capita': types.Schema(
|
|
219
|
+
any_of=[
|
|
220
|
+
types.Schema(type='INTEGER'),
|
|
221
|
+
types.Schema(type='NUMBER'),
|
|
222
|
+
],
|
|
223
|
+
title='Restaurants Per Capita',
|
|
224
|
+
),
|
|
225
|
+
},
|
|
226
|
+
type='OBJECT',
|
|
227
|
+
required=['name', 'restaurants_per_capita'],
|
|
228
|
+
title='CountryInfoWithAnyOf',
|
|
229
|
+
property_ordering=['name', 'restaurants_per_capita'],
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
assert transformed_schema == expected_schema
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
@pytest.mark.parametrize('use_vertex', [True, False])
|
|
236
|
+
def test_complex_dict_schema_with_anyof_is_unchanged(client):
|
|
237
|
+
"""When a dict schema is passed to process_schema, the only change should be camel-casing anyOf."""
|
|
238
|
+
if client.vertexai:
|
|
239
|
+
dict_schema = {
|
|
240
|
+
'type': 'OBJECT',
|
|
241
|
+
'title': 'Fruit Basket',
|
|
242
|
+
'description': 'A structured representation of a fruit basket',
|
|
243
|
+
'required': ['fruit'],
|
|
244
|
+
'properties': {
|
|
245
|
+
'fruit': {
|
|
246
|
+
'type': 'ARRAY',
|
|
247
|
+
'description': 'An ordered list of the fruit in the basket',
|
|
248
|
+
'items': {
|
|
249
|
+
'description': 'A piece of fruit',
|
|
250
|
+
'anyOf': [
|
|
251
|
+
{
|
|
252
|
+
'title': 'Apple',
|
|
253
|
+
'description': 'Describes an apple',
|
|
254
|
+
'type': 'OBJECT',
|
|
255
|
+
'properties': {
|
|
256
|
+
'type': {
|
|
257
|
+
'type': 'STRING',
|
|
258
|
+
'description': "Always 'apple'",
|
|
259
|
+
},
|
|
260
|
+
'color': {
|
|
261
|
+
'type': 'STRING',
|
|
262
|
+
'description': (
|
|
263
|
+
"The color of the apple (e.g., 'red')"
|
|
264
|
+
),
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
'propertyOrdering': ['type', 'color'],
|
|
268
|
+
'required': ['type', 'color'],
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
'title': 'Orange',
|
|
272
|
+
'description': 'Describes an orange',
|
|
273
|
+
'type': 'OBJECT',
|
|
274
|
+
'properties': {
|
|
275
|
+
'type': {
|
|
276
|
+
'type': 'STRING',
|
|
277
|
+
'description': "Always 'orange'",
|
|
278
|
+
},
|
|
279
|
+
'size': {
|
|
280
|
+
'type': 'STRING',
|
|
281
|
+
'description': (
|
|
282
|
+
'The size of the orange (e.g.,'
|
|
283
|
+
" 'medium')"
|
|
284
|
+
),
|
|
285
|
+
},
|
|
286
|
+
},
|
|
287
|
+
'propertyOrdering': ['type', 'size'],
|
|
288
|
+
'required': ['type', 'size'],
|
|
289
|
+
},
|
|
290
|
+
],
|
|
291
|
+
},
|
|
292
|
+
}
|
|
293
|
+
},
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
schema_before = copy.deepcopy(dict_schema)
|
|
297
|
+
_transformers.process_schema(dict_schema, client)
|
|
298
|
+
|
|
299
|
+
assert schema_before == dict_schema
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
@pytest.mark.parametrize('use_vertex', [True, False])
|
|
303
|
+
def test_process_schema_converts_const_to_enum(client):
|
|
304
|
+
"""The 'const' field should be converted to a singleton 'enum'."""
|
|
305
|
+
schema = {
|
|
306
|
+
'type': 'STRING',
|
|
307
|
+
'const': 'FOO',
|
|
308
|
+
}
|
|
309
|
+
expected_schema = {
|
|
310
|
+
'type': 'STRING',
|
|
311
|
+
'enum': ['FOO'],
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
_transformers.process_schema(schema, client)
|
|
315
|
+
|
|
316
|
+
assert schema == expected_schema
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
@pytest.mark.parametrize('use_vertex', [True, False])
|
|
320
|
+
def test_process_schema_forbids_non_string_const(client):
|
|
321
|
+
"""The 'const' field only works for strings."""
|
|
322
|
+
schema = {
|
|
323
|
+
'type': 'INTEGER',
|
|
324
|
+
'const': 123,
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
with pytest.raises(ValueError, match='.*Literal values must be strings.*'):
|
|
328
|
+
_transformers.process_schema(schema, client)
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
@pytest.mark.parametrize(
|
|
332
|
+
'use_vertex,order_properties',
|
|
333
|
+
[(False, False), (False, True), (True, False), (True, True)],
|
|
334
|
+
)
|
|
335
|
+
def test_process_schema_order_properties_propagates_into_defs(
|
|
336
|
+
client, order_properties
|
|
337
|
+
):
|
|
338
|
+
"""The `order_properties` setting should apply to '$defs'."""
|
|
339
|
+
schema = {
|
|
340
|
+
'$ref': '#/$defs/Foo',
|
|
341
|
+
'$defs': {
|
|
342
|
+
'Foo': {
|
|
343
|
+
'type': 'OBJECT',
|
|
344
|
+
'properties': {
|
|
345
|
+
'foo': {'type': 'STRING'},
|
|
346
|
+
'bar': {'type': 'STRING'},
|
|
347
|
+
},
|
|
348
|
+
},
|
|
349
|
+
},
|
|
350
|
+
}
|
|
351
|
+
schema_without_property_ordering = {
|
|
352
|
+
'type': 'OBJECT',
|
|
353
|
+
'properties': {
|
|
354
|
+
'foo': {'type': 'STRING'},
|
|
355
|
+
'bar': {'type': 'STRING'},
|
|
356
|
+
},
|
|
357
|
+
}
|
|
358
|
+
schema_with_property_ordering = {
|
|
359
|
+
'type': 'OBJECT',
|
|
360
|
+
'properties': {
|
|
361
|
+
'foo': {'type': 'STRING'},
|
|
362
|
+
'bar': {'type': 'STRING'},
|
|
363
|
+
},
|
|
364
|
+
'property_ordering': ['foo', 'bar'],
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
_transformers.process_schema(
|
|
368
|
+
schema, client, order_properties=order_properties
|
|
369
|
+
)
|
|
370
|
+
|
|
371
|
+
if order_properties:
|
|
372
|
+
assert schema == schema_with_property_ordering
|
|
373
|
+
else:
|
|
374
|
+
assert schema == schema_without_property_ordering
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
@pytest.mark.parametrize(
|
|
378
|
+
'use_vertex,order_properties',
|
|
379
|
+
[(False, False), (False, True), (True, False), (True, True)],
|
|
380
|
+
)
|
|
381
|
+
def test_process_schema_order_properties_propagates_into_items(
|
|
382
|
+
client, order_properties
|
|
383
|
+
):
|
|
384
|
+
"""The `order_properties` setting should apply to 'items'."""
|
|
385
|
+
schema = {
|
|
386
|
+
'type': 'ARRAY',
|
|
387
|
+
'items': {
|
|
388
|
+
'type': 'OBJECT',
|
|
389
|
+
'properties': {
|
|
390
|
+
'foo': {'type': 'STRING'},
|
|
391
|
+
'bar': {'type': 'STRING'},
|
|
392
|
+
},
|
|
393
|
+
},
|
|
394
|
+
}
|
|
395
|
+
schema_without_property_ordering = copy.deepcopy(schema)
|
|
396
|
+
schema_with_property_ordering = {
|
|
397
|
+
'type': 'ARRAY',
|
|
398
|
+
'items': {
|
|
399
|
+
'type': 'OBJECT',
|
|
400
|
+
'properties': {
|
|
401
|
+
'foo': {'type': 'STRING'},
|
|
402
|
+
'bar': {'type': 'STRING'},
|
|
403
|
+
},
|
|
404
|
+
'property_ordering': ['foo', 'bar'],
|
|
405
|
+
},
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
_transformers.process_schema(
|
|
409
|
+
schema, client, order_properties=order_properties
|
|
410
|
+
)
|
|
411
|
+
|
|
412
|
+
if order_properties:
|
|
413
|
+
assert schema == schema_with_property_ordering
|
|
414
|
+
else:
|
|
415
|
+
assert schema == schema_without_property_ordering
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
@pytest.mark.parametrize(
|
|
419
|
+
'use_vertex,order_properties',
|
|
420
|
+
[(False, False), (False, True), (True, False), (True, True)],
|
|
421
|
+
)
|
|
422
|
+
def test_process_schema_order_properties_propagates_into_prefix_items(
|
|
423
|
+
client, order_properties
|
|
424
|
+
):
|
|
425
|
+
"""The `order_properties` setting should apply to 'prefixItems'."""
|
|
426
|
+
schema = {
|
|
427
|
+
'type': 'ARRAY',
|
|
428
|
+
'prefixItems': [
|
|
429
|
+
{
|
|
430
|
+
'type': 'OBJECT',
|
|
431
|
+
'properties': {
|
|
432
|
+
'foo': {'type': 'STRING'},
|
|
433
|
+
'bar': {'type': 'STRING'},
|
|
434
|
+
},
|
|
435
|
+
},
|
|
436
|
+
],
|
|
437
|
+
}
|
|
438
|
+
schema_without_property_ordering = copy.deepcopy(schema)
|
|
439
|
+
schema_with_property_ordering = {
|
|
440
|
+
'type': 'ARRAY',
|
|
441
|
+
'prefixItems': [
|
|
442
|
+
{
|
|
443
|
+
'type': 'OBJECT',
|
|
444
|
+
'properties': {
|
|
445
|
+
'foo': {'type': 'STRING'},
|
|
446
|
+
'bar': {'type': 'STRING'},
|
|
447
|
+
},
|
|
448
|
+
'property_ordering': ['foo', 'bar'],
|
|
449
|
+
},
|
|
450
|
+
],
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
_transformers.process_schema(
|
|
454
|
+
schema, client, order_properties=order_properties
|
|
455
|
+
)
|
|
456
|
+
|
|
457
|
+
if order_properties:
|
|
458
|
+
assert schema == schema_with_property_ordering
|
|
459
|
+
else:
|
|
460
|
+
assert schema == schema_without_property_ordering
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
@pytest.mark.parametrize(
|
|
464
|
+
'use_vertex,order_properties',
|
|
465
|
+
[(False, False), (False, True), (True, False), (True, True)],
|
|
466
|
+
)
|
|
467
|
+
def test_process_schema_order_properties_propagates_into_properties(
|
|
468
|
+
client, order_properties
|
|
469
|
+
):
|
|
470
|
+
"""The `order_properties` setting should apply to 'properties'."""
|
|
471
|
+
schema = {
|
|
472
|
+
'type': 'OBJECT',
|
|
473
|
+
'properties': {
|
|
474
|
+
'xyz': {
|
|
475
|
+
'type': 'OBJECT',
|
|
476
|
+
'properties': {
|
|
477
|
+
'foo': {'type': 'STRING'},
|
|
478
|
+
'bar': {'type': 'STRING'},
|
|
479
|
+
},
|
|
480
|
+
},
|
|
481
|
+
'abc': {'type': 'STRING'},
|
|
482
|
+
},
|
|
483
|
+
}
|
|
484
|
+
schema_without_property_ordering = copy.deepcopy(schema)
|
|
485
|
+
schema_with_property_ordering = {
|
|
486
|
+
'type': 'OBJECT',
|
|
487
|
+
'properties': {
|
|
488
|
+
'xyz': {
|
|
489
|
+
'type': 'OBJECT',
|
|
490
|
+
'properties': {
|
|
491
|
+
'foo': {'type': 'STRING'},
|
|
492
|
+
'bar': {'type': 'STRING'},
|
|
493
|
+
},
|
|
494
|
+
'property_ordering': ['foo', 'bar'],
|
|
495
|
+
},
|
|
496
|
+
'abc': {'type': 'STRING'},
|
|
497
|
+
},
|
|
498
|
+
'property_ordering': ['xyz', 'abc'],
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
_transformers.process_schema(
|
|
502
|
+
schema, client, order_properties=order_properties
|
|
503
|
+
)
|
|
504
|
+
|
|
505
|
+
if order_properties:
|
|
506
|
+
assert schema == schema_with_property_ordering
|
|
507
|
+
else:
|
|
508
|
+
assert schema == schema_without_property_ordering
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
@pytest.mark.parametrize(
|
|
512
|
+
'use_vertex,order_properties',
|
|
513
|
+
[(False, False), (False, True), (True, False), (True, True)],
|
|
514
|
+
)
|
|
515
|
+
def test_process_schema_order_properties_propagates_into_additional_properties(
|
|
516
|
+
client, order_properties
|
|
517
|
+
):
|
|
518
|
+
"""The `order_properties` setting should apply to 'additionalProperties'."""
|
|
519
|
+
schema = {
|
|
520
|
+
'type': 'OBJECT',
|
|
521
|
+
'additionalProperties': {
|
|
522
|
+
'type': 'OBJECT',
|
|
523
|
+
'properties': {
|
|
524
|
+
'foo': {'type': 'STRING'},
|
|
525
|
+
'bar': {'type': 'STRING'},
|
|
526
|
+
},
|
|
527
|
+
},
|
|
528
|
+
}
|
|
529
|
+
schema_without_property_ordering = copy.deepcopy(schema)
|
|
530
|
+
schema_with_property_ordering = {
|
|
531
|
+
'type': 'OBJECT',
|
|
532
|
+
'additionalProperties': {
|
|
533
|
+
'type': 'OBJECT',
|
|
534
|
+
'properties': {
|
|
535
|
+
'foo': {'type': 'STRING'},
|
|
536
|
+
'bar': {'type': 'STRING'},
|
|
537
|
+
},
|
|
538
|
+
'property_ordering': ['foo', 'bar'],
|
|
539
|
+
},
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
if client.vertexai:
|
|
543
|
+
_transformers.process_schema(
|
|
544
|
+
schema, client, order_properties=order_properties
|
|
545
|
+
)
|
|
546
|
+
|
|
547
|
+
if order_properties:
|
|
548
|
+
assert schema == schema_with_property_ordering
|
|
549
|
+
else:
|
|
550
|
+
assert schema == schema_without_property_ordering
|
|
551
|
+
else:
|
|
552
|
+
with pytest.raises(ValueError) as e:
|
|
553
|
+
_transformers.process_schema(
|
|
554
|
+
schema, client, order_properties=order_properties
|
|
555
|
+
)
|
|
556
|
+
assert 'additionalProperties is not supported in the Gemini API.' in str(e)
|
|
557
|
+
|
|
558
|
+
|
|
559
|
+
@pytest.mark.parametrize(
|
|
560
|
+
'use_vertex,order_properties',
|
|
561
|
+
[(False, False), (False, True), (True, False), (True, True)],
|
|
562
|
+
)
|
|
563
|
+
def test_process_schema_order_properties_propagates_into_any_of(
|
|
564
|
+
client, order_properties
|
|
565
|
+
):
|
|
566
|
+
"""The `order_properties` setting should apply to 'anyOf'."""
|
|
567
|
+
schema = {
|
|
568
|
+
'anyOf': [
|
|
569
|
+
{
|
|
570
|
+
'type': 'OBJECT',
|
|
571
|
+
'properties': {
|
|
572
|
+
'foo': {'type': 'STRING'},
|
|
573
|
+
'bar': {'type': 'STRING'},
|
|
574
|
+
},
|
|
575
|
+
},
|
|
576
|
+
{'type': 'STRING'},
|
|
577
|
+
]
|
|
578
|
+
}
|
|
579
|
+
schema_without_property_ordering = copy.deepcopy(schema)
|
|
580
|
+
schema_with_property_ordering = {
|
|
581
|
+
'anyOf': [
|
|
582
|
+
{
|
|
583
|
+
'type': 'OBJECT',
|
|
584
|
+
'properties': {
|
|
585
|
+
'foo': {'type': 'STRING'},
|
|
586
|
+
'bar': {'type': 'STRING'},
|
|
587
|
+
},
|
|
588
|
+
'property_ordering': ['foo', 'bar'],
|
|
589
|
+
},
|
|
590
|
+
{'type': 'STRING'},
|
|
591
|
+
]
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
_transformers.process_schema(
|
|
595
|
+
schema, client, order_properties=order_properties
|
|
596
|
+
)
|
|
597
|
+
|
|
598
|
+
if order_properties:
|
|
599
|
+
assert schema == schema_with_property_ordering
|
|
600
|
+
else:
|
|
601
|
+
assert schema == schema_without_property_ordering
|
|
602
|
+
|
|
603
|
+
|
|
604
|
+
def test_t_schema_does_not_change_property_ordering_if_set(client):
|
|
605
|
+
"""Tests t_schema doesn't overwrite the property_ordering field if already set."""
|
|
606
|
+
|
|
607
|
+
schema = CountryInfo.model_json_schema()
|
|
608
|
+
custom_property_ordering = ['code', 'symbol', 'name']
|
|
609
|
+
schema['property_ordering'] = custom_property_ordering.copy()
|
|
610
|
+
|
|
611
|
+
transformed_schema = _transformers.t_schema(client, schema)
|
|
612
|
+
assert transformed_schema.property_ordering == custom_property_ordering
|
|
613
|
+
|
|
614
|
+
|
|
615
|
+
def test_t_schema_sets_property_ordering_for_json_schema(client):
|
|
616
|
+
"""Tests t_schema sets the property_ordering field for json schemas."""
|
|
617
|
+
|
|
618
|
+
schema = CountryInfo.model_json_schema()
|
|
619
|
+
|
|
620
|
+
transformed_schema = _transformers.t_schema(client, schema)
|
|
621
|
+
assert transformed_schema.property_ordering == [
|
|
622
|
+
'name',
|
|
623
|
+
'population',
|
|
624
|
+
'capital',
|
|
625
|
+
'continent',
|
|
626
|
+
'gdp',
|
|
627
|
+
'official_language',
|
|
628
|
+
'total_area_sq_mi',
|
|
629
|
+
]
|
|
630
|
+
|
|
631
|
+
|
|
632
|
+
def test_t_schema_sets_property_ordering_for_schema_type(client):
|
|
633
|
+
"""Tests t_schema sets the property_ordering field for Schema types."""
|
|
634
|
+
|
|
635
|
+
schema = types.Schema(
|
|
636
|
+
properties={
|
|
637
|
+
'name': types.Schema(
|
|
638
|
+
type='STRING',
|
|
639
|
+
title='Name',
|
|
640
|
+
),
|
|
641
|
+
'population': types.Schema(
|
|
642
|
+
type='INTEGER',
|
|
643
|
+
default=0,
|
|
644
|
+
title='Population',
|
|
645
|
+
),
|
|
646
|
+
},
|
|
647
|
+
type='OBJECT',
|
|
648
|
+
required=['name'],
|
|
649
|
+
title='CountryInfoWithDefaultValue',
|
|
650
|
+
)
|
|
651
|
+
|
|
652
|
+
transformed_schema = _transformers.t_schema(client, schema)
|
|
653
|
+
assert transformed_schema.property_ordering == ['name', 'population']
|